Newer
Older
<?php
// $Id$
Dries Buytaert
committed
/**
* @file
* Tests for translation.module
*/
class TranslationTestCase extends DrupalWebTestCase {
protected $book;
Angie Byron
committed
public static function getInfo() {
return array(
'name' => 'Translation functionality',
Angie Byron
committed
'description' => 'Create a basic page with translation, modify the page outdating translation, and update translation.',
'group' => 'Translation'
);
}
function setUp() {
Angie Byron
committed
parent::setUp('locale', 'translation', 'translation_test');
// Setup users.
Angie Byron
committed
$this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages'));
Angie Byron
committed
$this->translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content'));
Angie Byron
committed
$this->drupalLogin($this->admin_user);
// Add languages.
$this->addLanguage('en');
$this->addLanguage('es');
Angie Byron
committed
$this->addLanguage('it');
Angie Byron
committed
// Disable Italian to test the translation behavior with disabled languages.
$edit = array('enabled[it]' => FALSE);
$this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
Angie Byron
committed
Angie Byron
committed
// Set "Basic page" content type to use multilingual support with
// translation.
Dries Buytaert
committed
$this->drupalGet('admin/structure/types/manage/page');
$edit = array();
$edit['language_content_type'] = 2;
Dries Buytaert
committed
$this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
$this->assertRaw(t('The content type %type has been updated.', array('%type' => 'Basic page')), t('Basic page content type has been updated.'));
Angie Byron
committed
// Enable the language switcher block.
$language_type = LANGUAGE_TYPE_INTERFACE;
$edit = array("blocks[locale_$language_type][region]" => 'sidebar_first');
$this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
// Enable URL language detection and selection to make the language switcher
// block appear.
$edit = array('language[enabled][locale-url]' => TRUE);
$this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
$this->assertRaw(t('Language negotiation configuration saved.'), t('URL language detection enabled.'));
$this->resetCaches();
Angie Byron
committed
$this->drupalLogin($this->translator);
}
Angie Byron
committed
/**
* Create a basic page with translation, modify the basic page outdating
* translation, and update translation.
*/
function testContentTranslation() {
Angie Byron
committed
// Create Basic page in English.
$node_title = $this->randomName();
$node_body = $this->randomName();
$node = $this->createPage($node_title, $node_body, 'en');
Angie Byron
committed
// Check that the "add translation" link uses a localized path.
Angie Byron
committed
$languages = language_list();
$this->drupalGet('node/' . $node->nid . '/translate');
$this->assertLinkByHref($languages['es']->prefix . '/node/add/' . str_replace('_', '-', $node->type), 0, t('The "add translation" link for %language points to the localized path of the target language.', array('%language' => $languages['es']->name)));
// Submit translation in Spanish.
$node_translation_title = $this->randomName();
$node_translation_body = $this->randomName();
Angie Byron
committed
$node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es');
Angie Byron
committed
// Check that the "edit translation" and "view node" links use localized
// paths.
Angie Byron
committed
$this->drupalGet('node/' . $node->nid . '/translate');
$this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid . '/edit', 0, t('The "edit" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
$this->assertLinkByHref($languages['es']->prefix . '/node/' . $node_translation->nid, 0, t('The "view" link for the translation in %language points to the localized path of the translation language.', array('%language' => $languages['es']->name)));
Angie Byron
committed
// Attempt to submit a duplicate translation by visiting the node/add page
// with identical query string.
Dries Buytaert
committed
$this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => 'es')));
$this->assertRaw(t('A translation of %title in %language already exists', array('%title' => $node_title, '%language' => $languages['es']->name)), t('Message regarding attempted duplicate translation is displayed.'));
Angie Byron
committed
// Attempt a resubmission of the form - this emulates using the back button
// to return to the page then resubmitting the form without a refresh.
$edit = array();
$langcode = LANGUAGE_NONE;
$edit["title"] = $this->randomName();
Angie Byron
committed
$edit["body[$langcode][0][value]"] = $this->randomName();
Angie Byron
committed
$this->drupalPost('node/add/page', $edit, t('Save'), array('query' => array('translation' => $node->nid, 'language' => 'es')));
$duplicate = $this->drupalGetNodeByTitle($edit["title"]);
$this->assertEqual($duplicate->tnid, 0, t('The node does not have a tnid.'));
Angie Byron
committed
// Update original and mark translation as outdated.
Angie Byron
committed
$node_body = $this->randomName();
$node->body[$node->language][0]['value'] = $node_body;
$edit = array();
Angie Byron
committed
$edit["body[$node->language][0][value]"] = $node_body;
$edit['translation[retranslate]'] = TRUE;
$this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_title)), t('Original node updated.'));
Angie Byron
committed
// Check to make sure that interface shows translation as outdated.
$this->drupalGet('node/' . $node->nid . '/translate');
$this->assertRaw('<span class="marker">' . t('outdated') . '</span>', t('Translation marked as outdated.'));
// Update translation and mark as updated.
$edit = array();
Angie Byron
committed
$edit["body[$node_translation->language][0][value]"] = $this->randomName();
$edit['translation[status]'] = FALSE;
$this->drupalPost('node/' . $node_translation->nid . '/edit', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been updated.', array('%title' => $node_translation_title)), t('Translated node updated.'));
Angie Byron
committed
// Confirm that disabled languages are an option for translators when
// creating nodes.
$this->drupalGet('node/add/page');
Angie Byron
committed
$this->assertFieldByXPath('//select[@name="language"]//option', 'it', t('Italian (disabled) is available in language selection.'));
$translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
$this->assertRaw($translation_it->body['it'][0]['value'], t('Content created in Italian (disabled).'));
// Leave just one language enabled and check that the translation overview
// page is still accessible.
$this->drupalLogin($this->admin_user);
$edit = array('enabled[es]' => FALSE);
$this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
$this->drupalLogin($this->translator);
$this->drupalGet('node/' . $node->nid . '/translate');
$this->assertRaw(t('Translations of %title', array('%title' => $node->title)), t('Translation overview page available with only one language enabled.'));
}
Angie Byron
committed
/**
Angie Byron
committed
* Check that language switch links behave properly.
Angie Byron
committed
*/
Angie Byron
committed
function testLanguageSwitchLinks() {
// Create a Basic page in English and its translations in Spanish and
// Italian.
$node = $this->createPage($this->randomName(), $this->randomName(), 'en');
$translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
$translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
// Check that language switch links are correctly shown only for enabled
// languages.
$this->assertLanguageSwitchLinks($node, $translation_es);
$this->assertLanguageSwitchLinks($translation_es, $node);
$this->assertLanguageSwitchLinks($node, $translation_it, FALSE);
// Check that links to the displayed translation appear only in the language
// switcher block.
$this->assertLanguageSwitchLinks($node, $node, FALSE, 'node');
$this->assertLanguageSwitchLinks($node, $node, TRUE, 'block-locale');
// Unpublish the Spanish translation to check that the related language
// switch link is not shown.
$this->drupalLogin($this->admin_user);
$edit = array('status' => FALSE);
$this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
$this->drupalLogin($this->translator);
$this->assertLanguageSwitchLinks($node, $translation_es, FALSE);
Angie Byron
committed
// Check that content translation links are shown even when no language
// negotiation is configured.
Angie Byron
committed
$this->drupalLogin($this->admin_user);
$edit = array('language[enabled][locale-url]' => FALSE);
$this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings'));
Angie Byron
committed
$this->resetCaches();
$edit = array('status' => TRUE);
$this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save'));
Angie Byron
committed
$this->drupalLogin($this->translator);
Angie Byron
committed
$this->assertLanguageSwitchLinks($node, $translation_es, TRUE, 'node');
}
Angie Byron
committed
Angie Byron
committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
/**
* Test that the language switcher block alterations work as intended.
*/
function testLanguageSwitcherBlockIntegration() {
// Enable Italian to have three items in the language switcher block.
$this->drupalLogin($this->admin_user);
$edit = array('enabled[it]' => TRUE);
$this->drupalPost('admin/config/regional/language', $edit, t('Save configuration'));
$this->drupalLogin($this->translator);
// Create a Basic page in English.
$type = 'block-locale';
$node = $this->createPage($this->randomName(), $this->randomName(), 'en');
$this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
$this->assertLanguageSwitchLinks($node, $this->emptyNode('es'), TRUE, $type);
$this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
// Create the Spanish translation.
$translation_es = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'es');
$this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
$this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
$this->assertLanguageSwitchLinks($node, $this->emptyNode('it'), TRUE, $type);
// Create the Italian translation.
$translation_it = $this->createTranslation($node, $this->randomName(), $this->randomName(), 'it');
$this->assertLanguageSwitchLinks($node, $node, TRUE, $type);
$this->assertLanguageSwitchLinks($node, $translation_es, TRUE, $type);
$this->assertLanguageSwitchLinks($node, $translation_it, TRUE, $type);
}
/**
* Reset static caches to make the test code match the client site behavior.
*/
function resetCaches() {
drupal_static_reset('locale_url_outbound_alter');
}
/**
* Return an empty node data structure.
*/
function emptyNode($langcode) {
return (object) array('nid' => NULL, 'language' => $langcode);
Angie Byron
committed
}
/**
* Install a the specified language if it has not been already. Otherwise make sure that
* the language is enabled.
*
Angie Byron
committed
* @param $language_code
* The language code the check.
*/
function addLanguage($language_code) {
// Check to make sure that language has not already been installed.
Dries Buytaert
committed
$this->drupalGet('admin/config/regional/language');
if (strpos($this->drupalGetContent(), 'enabled[' . $language_code . ']') === FALSE) {
// Doesn't have language installed so add it.
$edit = array();
$edit['langcode'] = $language_code;
Dries Buytaert
committed
$this->drupalPost('admin/config/regional/language/add', $edit, t('Add language'));
Angie Byron
committed
// Make sure we are not using a stale list.
Dries Buytaert
committed
drupal_static_reset('language_list');
$languages = language_list('language');
$this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.'));
if (array_key_exists($language_code, $languages)) {
$this->assertRaw(t('The language %language has been created and can now be used. More information is available on the <a href="@locale-help">help screen</a>.', array('%language' => $languages[$language_code]->name, '@locale-help' => url('admin/help/locale'))), t('Language has been created.'));
}
}
Dries Buytaert
committed
elseif ($this->xpath('//input[@type="checkbox" and @name=:name and @checked="checked"]', array(':name' => 'enabled[' . $language_code . ']'))) {
Dries Buytaert
committed
// It's installed and enabled. No need to do anything.
$this->assertTrue(true, 'Language [' . $language_code . '] already installed and enabled.');
}
else {
Dries Buytaert
committed
// It's installed but not enabled. Enable it.
$this->assertTrue(true, 'Language [' . $language_code . '] already installed.');
$this->drupalPost(NULL, array('enabled[' . $language_code . ']' => TRUE), t('Save configuration'));
$this->assertRaw(t('Configuration saved.'), t('Language successfully enabled.'));
}
}
/**
Angie Byron
committed
* Create a "Basic page" in the specified language.
*
Angie Byron
committed
* @param $title
* Title of basic page in specified language.
* @param $body
* Body of basic page in specified language.
* @param
* $language Language code.
*/
function createPage($title, $body, $language) {
$edit = array();
$langcode = LANGUAGE_NONE;
$edit["title"] = $title;
Angie Byron
committed
$edit["body[$langcode][0][value]"] = $body;
$edit['language'] = $language;
$this->drupalPost('node/add/page', $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Basic page created.'));
// Check to make sure the node was created.
Angie Byron
committed
$node = $this->drupalGetNodeByTitle($title);
$this->assertTrue($node, t('Node found in database.'));
return $node;
}
Angie Byron
committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/**
* Create a translation for the specified basic page in the specified
* language.
*
* @param $node
* The basic page to create translation for.
* @param $title
* Title of basic page in specified language.
* @param $body
* Body of basic page in specified language.
* @param $language
* Language code.
*/
function createTranslation($node, $title, $body, $language) {
$this->drupalGet('node/add/page', array('query' => array('translation' => $node->nid, 'target' => $language)));
$body_key = "body[$language][0][value]";
$this->assertFieldByXPath('//input[@id="edit-title"]', $node->title, "Original title value correctly populated.");
$this->assertFieldByXPath("//textarea[@name='$body_key']", $node->body[$node->language][0]['value'], "Original body value correctly populated.");
$edit = array();
$edit["title"] = $title;
$edit[$body_key] = $body;
$this->drupalPost(NULL, $edit, t('Save'));
$this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Translation created.'));
// Check to make sure that translation was successful.
$translation = $this->drupalGetNodeByTitle($title);
$this->assertTrue($translation, t('Node found in database.'));
$this->assertTrue($translation->tnid == $node->nid, t('Translation set id correctly stored.'));
return $translation;
}
Angie Byron
committed
/**
* Assert that an element identified by the given XPath has the given content.
*
* @param $xpath
* XPath used to find the element.
* @param array $arguments
* An array of arguments with keys in the form ':name' matching the
* placeholders in the query. The values may be either strings or numeric
* values.
* @param $value
* The text content of the matched element to assert.
* @param $message
* Message to display.
* @param $group
* The group this message belongs to.
*
* @return
* TRUE on pass, FALSE on fail.
*/
function assertContentByXPath($xpath, array $arguments = array(), $value = NULL, $message = '', $group = 'Other') {
Angie Byron
committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
$found = $this->findContentByXPath($xpath, $arguments, $value);
return $this->assertTrue($found, $message, $group);
}
/**
* Check that the specified language switch links are found/not found.
*
* @param $node
* The node to display.
* @param $translation
* The translation whose link has to be checked.
* @param $find
* TRUE if the link must be present in the node page.
* @param $types
* The page areas to be checked.
*
* @return
* TRUE if the language switch links are found/not found.
*/
function assertLanguageSwitchLinks($node, $translation, $find = TRUE, $types = NULL) {
if (empty($types)) {
$types = array('node', 'block-locale');
}
elseif (is_string($types)) {
$types = array($types);
}
$result = TRUE;
$languages = language_list();
$page_language = $languages[$node->language];
$translation_language = $languages[$translation->language];
$url = url("node/$translation->nid", array('language' => $translation_language));
$this->drupalGet("node/$node->nid", array('language' => $page_language));
foreach ($types as $type) {
$args = array('%translation_language' => $translation_language->native, '%page_language' => $page_language->native, '%type' => $type);
if ($find) {
$message = t('[%page_language] Language switch item found for %translation_language language in the %type page area.', $args);
}
else {
$message = t('[%page_language] Language switch item not found for %translation_language language in the %type page area.', $args);
}
if (!empty($translation->nid)) {
$xpath = '//div[contains(@class, :type)]//a[@href=:url]';
}
else {
$xpath = '//div[contains(@class, :type)]//span[@class="locale-untranslated"]';
}
$found = $this->findContentByXPath($xpath, array(':type' => $type, ':url' => $url), $translation_language->native);
$result = $this->assertTrue($found == $find, $message) && $result;
}
return $result;
}
/**
* Search for elements matching the given xpath and value.
*/
function findContentByXPath($xpath, array $arguments = array(), $value = NULL) {
Angie Byron
committed
$elements = $this->xpath($xpath, $arguments);
$found = TRUE;
if ($value && $elements) {
$found = FALSE;
foreach ($elements as $element) {
if ((string) $element == $value) {
$found = TRUE;
break;
}
}
}
Angie Byron
committed
return $elements && $found;