Index: includes/translation.node.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/translation/includes/translation.node.inc,v retrieving revision 1.2 diff -u -r1.2 translation.node.inc --- includes/translation.node.inc 3 Oct 2010 16:36:14 -0000 1.2 +++ includes/translation.node.inc 26 Jan 2011 17:30:50 -0000 @@ -37,7 +37,7 @@ * Node specific access callback. */ function translation_node_tab_access($node) { - return !empty($node->language) && (translation_supported_type($node->type) || translation_node('node', $node)) && translation_tab_access('node'); + return !empty($node->language) && ((translation_supported_type($node->type) && translation_tab_access('node')) || translation_node('node', $node)); } /** Index: modules/translation_node/translation_node.pages.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/translation/modules/translation_node/translation_node.pages.inc,v retrieving revision 1.1 diff -u -r1.1 translation_node.pages.inc --- modules/translation_node/translation_node.pages.inc 23 Sep 2010 11:58:28 -0000 1.1 +++ modules/translation_node/translation_node.pages.inc 26 Jan 2011 17:30:52 -0000 @@ -13,6 +13,8 @@ * Node object. */ function translation_node_overview($node) { + include_once DRUPAL_ROOT . '/includes/language.inc'; + if ($node->tnid) { // Already part of a set, grab that set. $tnid = $node->tnid; @@ -24,18 +26,24 @@ $translations = array($node->language => $node); } + $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE); $header = array(t('Language'), t('Title'), t('Status'), t('Operations')); - foreach (language_list() as $language) { + foreach (language_list() as $langcode => $language) { $options = array(); $language_name = $language->name; - if (isset($translations[$language->language])) { + if (isset($translations[$langcode])) { // Existing translation in the translation set: display status. // We load the full node to check whether the user can edit it. - $translation_node = node_load($translations[$language->language]->nid); - $title = l($translation_node->title, 'node/' . $translation_node->nid); + $translation_node = node_load($translations[$langcode]->nid); + $path = 'node/' . $translation_node->nid; + $links = language_negotiation_get_switch_links($type, $path); + $title = empty($links->links[$langcode]) ? l($translation_node->title, $path) : l($translation_node->title, $links->links[$langcode]['href'], $links->links[$langcode]); if (node_access('update', $translation_node)) { - $options[] = l(t('edit'), "node/$translation_node->nid/edit"); + $text = t('edit'); + $path = 'node/' . $translation_node->nid . '/edit'; + $links = language_negotiation_get_switch_links($type, $path); + $options[] = empty($links->links[$langcode]) ? l($text, $path) : l($text, $links->links[$langcode]['href'], $links->links[$langcode]); } $status = $translation_node->status ? t('Published') : t('Not published'); $status .= $translation_node->translate ? ' - ' . t('outdated') . '' : ''; @@ -47,7 +55,11 @@ // No such translation in the set yet: help user to create it. $title = t('n/a'); if (node_access('create', $node)) { - $options[] = l(t('add translation'), 'node/add/' . str_replace('_', '-', $node->type), array('query' => array('translation' => $node->nid, 'target' => $language->language))); + $text = t('add translation'); + $path = 'node/add/' . str_replace('_', '-', $node->type); + $links = language_negotiation_get_switch_links($type, $path); + $query = array('query' => array('translation' => $node->nid, 'target' => $langcode)); + $options[] = empty($links->links[$langcode]) ? l($text, $path, $query) : l($text, $links->links[$langcode]['href'], array_merge_recursive($links->links[$langcode], $query)); } $status = t('Not translated'); } Index: modules/translation_node/translation_node.info =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/translation/modules/translation_node/translation_node.info,v retrieving revision 1.1 diff -u -r1.1 translation_node.info --- modules/translation_node/translation_node.info 23 Sep 2010 11:58:28 -0000 1.1 +++ modules/translation_node/translation_node.info 26 Jan 2011 17:30:50 -0000 @@ -5,6 +5,4 @@ dependencies[] = translation package = Multilingual core = 7.x -files[] = translation_node.module -files[] = translation_node.pages.inc -;files[] = translation_node.test +files[] = translation_node.test Index: modules/translation_node/translation_node.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/translation/modules/translation_node/translation_node.module,v retrieving revision 1.1 diff -u -r1.1 translation_node.module --- modules/translation_node/translation_node.module 23 Sep 2010 11:58:28 -0000 1.1 +++ modules/translation_node/translation_node.module 26 Jan 2011 17:30:52 -0000 @@ -72,7 +72,7 @@ function translation_node_permission() { return array( 'translate content' => array( - 'title' => t('Translate content'), + 'title' => t('Create node translations'), ), ); } @@ -83,6 +83,7 @@ function translation_node_form_node_type_form_alter(&$form, &$form_state) { // Add translation option to content type form. $form['workflow']['language_content_type']['#options'][TRANSLATION_NODE_ENABLED] = t('Enabled, with node translation'); + // Description based on text from locale.module. $form['workflow']['language_content_type']['#description'] .= ' ' . t('If node translation is enabled every translation will be a different node.'); } @@ -93,9 +94,27 @@ * - Alters language fields on node forms when a translation * is about to be created. */ -function translation_node_form_alter(&$form, &$form_state, $form_id) { - if (!empty($form['#node_edit_form']) && translation_node_supported_type($form['#node']->type)) { +function translation_node_form_node_form_alter(&$form, &$form_state) { + if (translation_node_supported_type($form['#node']->type)) { $node = $form['#node']; + $languages = language_list('enabled'); + $disabled_languages = isset($languages[0]) ? $languages[0] : FALSE; + $translator_widget = $disabled_languages && user_access('translate content'); + $groups = array(t('Disabled'), t('Enabled')); + // Allow translators to enter content in disabled languages. Translators + // might need to distinguish between enabled and disabled languages, hence + // we divide them in two option groups. + if ($translator_widget) { + $options = array(); + $language_list = locale_language_list('name', TRUE); + foreach (array(1, 0) as $status) { + $group = $groups[$status]; + foreach ($languages[$status] as $langcode => $language) { + $options[$group][$langcode] = $language_list[$langcode]; + } + } + $form['language']['#options'] = $options; + } if (!empty($node->translation_source)) { // We are creating a translation. Add values and lock language field. $form['translation_source'] = array('#type' => 'value', '#value' => $node->translation_source); @@ -106,9 +125,15 @@ // node to some language which is already in the translation set. Also remove the // language neutral option. unset($form['language']['#options'][LANGUAGE_NONE]); - foreach (translation_node_get_translations($node->tnid) as $translation) { + foreach (translation_node_get_translations($node->tnid) as $langcode => $translation) { if ($translation->nid != $node->nid) { - unset($form['language']['#options'][$translation->language]); + if ($translator_widget) { + $group = $groups[(int)!isset($disabled_languages[$langcode])]; + unset($form['language']['#options'][$group][$langcode]); + } + else { + unset($form['language']['#options'][$langcode]); + } } } // Add translation values and workflow options. @@ -147,20 +172,61 @@ /** * Implements hook_node_view(). * - * Display translation links with native language names, if this node - * is part of a translation set. + * Display translation links with native language names, if this node is part of + * a translation set. If no language provider is enabled "fall back" to the + * simple links built through the result of translation_node_get_translations(). */ function translation_node_node_view($node, $view_mode) { - if (isset($node->tnid) && drupal_multilingual() && - translation_node_supported_type($node->type) && $translations = translation_node_get_translations($node->tnid)) { - $path = 'node/' . $node->nid; - $links = language_negotiation_get_switch_links(LANGUAGE_TYPE_CONTENT, $path); - if (is_object($links)) { - $links = $links->links; - // Do not show link to the same node. - unset($links[$node->language]); - $node->content['links']['#links'] = array_merge($node->content['links']['#links'], $links); + // If the site has no translations or is not multilingual we have no content + // translation links to display. + if (isset($node->tnid) && drupal_multilingual() && $translations = translation_node_get_translations($node->tnid)) { + $languages = language_list('enabled'); + $languages = $languages[1]; + + // There might be a language provider enabled defining custom language + // switch links which need to be taken into account while generating the + // content translation links. As custom language switch links are available + // only for configurable language types and interface language is the only + // configurable language type in core, we use it as default. Contributed + // modules can change this behavior by setting the system variable below. + $type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE); + $custom_links = language_negotiation_get_switch_links($type, "node/$node->nid"); + $links = array(); + + foreach ($translations as $langcode => $translation) { + // Do not show links to the same node, to unpublished translations or to + // translations in disabled languages. + if ($translation->status && isset($languages[$langcode]) && $langcode != $node->language) { + $language = $languages[$langcode]; + $key = "translation_$langcode"; + + if (isset($custom_links->links[$langcode])) { + $links[$key] = $custom_links->links[$langcode]; + } + else { + $links[$key] = array( + 'href' => "node/{$translation->nid}", + 'title' => $language->native, + 'language' => $language, + ); + } + + // Custom switch links are more generic than content translation links, + // hence we override existing attributes with the ones below. + $links[$key] += array('attributes' => array()); + $attributes = array( + 'title' => $translation->title, + 'class' => array('translation-link'), + ); + $links[$key]['attributes'] = $attributes + $links[$key]['attributes']; + } } + + $node->content['links']['translation'] = array( + '#theme' => 'links__node__translation', + '#links' => $links, + '#attributes' => array('class' => array('links', 'inline')), + ); } } @@ -243,6 +309,8 @@ )) ->condition('nid', $node->nid) ->execute(); + // Save tnid to avoid loss in case of resave. + $node->tnid = $tnid; } } } @@ -355,7 +423,7 @@ if (!isset($translations[$tnid])) { $translations[$tnid] = array(); $result = db_select('node', 'n') - ->fields('n', array('nid', 'title', 'language')) + ->fields('n', array('nid', 'type', 'uid', 'status', 'title', 'language')) ->condition('n.tnid', $tnid) ->addTag('node_access') ->execute(); @@ -391,7 +459,7 @@ function translation_node_path_get_translations($path) { $paths = array(); // Check for a node related path, and for its translations. - if ((preg_match("!^node/([0-9]+)(/.+|)$!", $path, $matches)) && ($node = node_load((int)$matches[1])) && !empty($node->tnid)) { + if ((preg_match("!^node/(\d+)(/.+|)$!", $path, $matches)) && ($node = node_load((int) $matches[1])) && !empty($node->tnid)) { foreach (translation_node_get_translations($node->tnid) as $language => $translation_node) { $paths[$language] = 'node/' . $translation_node->nid . $matches[2]; } @@ -405,15 +473,19 @@ * Replaces links with pointers to translated versions of the content. */ function translation_node_language_switch_links_alter(array &$links, $type, $path) { - if ($type == LANGUAGE_TYPE_CONTENT && $paths = translation_node_path_get_translations($path)) { + $language_type = variable_get('translation_language_type', LANGUAGE_TYPE_INTERFACE); + if ($type == $language_type && preg_match("!^node/(\d+)(/.+|)!", $path, $matches) && ($node = node_load((int) $matches[1]))) { + $translations = $node->tnid ? translation_node_get_translations($node->tnid) : array($node->language => $node); + foreach ($links as $langcode => $link) { - if (isset($paths[$langcode])) { + if (isset($translations[$langcode]) && $translations[$langcode]->status) { // Translation in a different node. - $links[$langcode]['href'] = $paths[$langcode]; + $links[$langcode]['href'] = 'node/' . $translations[$langcode]->nid . $matches[2]; } else { // No translation in this language, or no permission to view. - unset($links[$langcode]); + unset($links[$langcode]['href']); + $links[$langcode]['attributes']['class'] = 'locale-untranslated'; } } } Index: modules/translation_node/translation_node.test =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/translation/modules/translation_node/translation_node.test,v retrieving revision 1.1 diff -u -r1.1 translation_node.test --- modules/translation_node/translation_node.test 23 Sep 2010 11:58:28 -0000 1.1 +++ modules/translation_node/translation_node.test 26 Jan 2011 17:30:54 -0000 @@ -13,46 +13,74 @@ } function setUp() { - parent::setUp('locale', 'translation', 'translation_node'); - } + parent::setUp('locale', 'translation', 'translation_node', 'translation_node_test'); - /** - * Create a basic page with translation, modify the basic page outdating translation, and update translation. - */ - function testContentTranslation() { // Setup users. - $admin_user = $this->drupalCreateUser(array('administer languages', 'administer content types', 'access administration pages')); - $translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content')); + $this->admin_user = $this->drupalCreateUser(array('bypass node access', 'administer nodes', 'administer languages', 'administer content types', 'administer blocks', 'access administration pages')); + $this->translator = $this->drupalCreateUser(array('create page content', 'edit own page content', 'translate content')); - $this->drupalLogin($admin_user); + $this->drupalLogin($this->admin_user); // Add languages. $this->addLanguage('en'); $this->addLanguage('es'); + $this->addLanguage('it'); + + // 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')); - // Set "Basic page" content type to use multilingual support with translation. + // Set "Basic page" content type to use multilingual support with + // translation. $this->drupalGet('admin/structure/types/manage/page'); $edit = array(); $edit['language_content_type'] = 2; $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.')); - $this->drupalLogout(); - $this->drupalLogin($translator); + // 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(); + $this->drupalLogin($this->translator); + } + + /** + * Create a basic page with translation, modify the basic page outdating + * translation, and update translation. + */ + function testContentTranslation() { // Create Basic page in English. $node_title = $this->randomName(); $node_body = $this->randomName(); $node = $this->createPage($node_title, $node_body, 'en'); + // Check that the "add translation" link uses a localized path. + $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(); $node_translation = $this->createTranslation($node, $node_translation_title, $node_translation_body, 'es'); + // Check that the "edit translation" and "view node" links use localized + // paths. + $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))); + // Attempt to submit a duplicate translation by visiting the node/add page // with identical query string. - $languages = language_list(); $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.')); @@ -67,13 +95,15 @@ $this->assertEqual($duplicate->tnid, 0, t('The node does not have a tnid.')); // Update original and mark translation as outdated. + $node_body = $this->randomName(); + $node->body[$node->language][0]['value'] = $node_body; $edit = array(); - $edit["body[$node->language][0][value]"] = $this->randomName(); + $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.')); - // Check to make sure that interface shows translation as outdated + // Check to make sure that interface shows translation as outdated. $this->drupalGet('node/' . $node->nid . '/translate'); $this->assertRaw('' . t('outdated') . '', t('Translation marked as outdated.')); @@ -83,13 +113,115 @@ $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.')); + + // Confirm that disabled languages are an option for translators when + // creating nodes. + $this->drupalGet('node/add/page'); + $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.')); + } + + /** + * Check that language switch links behave properly. + */ + 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); + + // Check that content translation links are shown even when no language + // negotiation is configured. + $this->drupalLogin($this->admin_user); + $edit = array('language[enabled][locale-url]' => FALSE); + $this->drupalPost('admin/config/regional/language/configure', $edit, t('Save settings')); + $this->resetCaches(); + $edit = array('status' => TRUE); + $this->drupalPost("node/$translation_es->nid/edit", $edit, t('Save')); + $this->drupalLogin($this->translator); + $this->assertLanguageSwitchLinks($node, $translation_es, TRUE, 'node'); + } + + /** + * 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); } /** * Install a the specified language if it has not been already. Otherwise make sure that * the language is enabled. * - * @param string $language_code The language code the check. + * @param $language_code + * The language code the check. */ function addLanguage($language_code) { // Check to make sure that language has not already been installed. @@ -101,7 +233,7 @@ $edit['langcode'] = $language_code; $this->drupalPost('admin/config/regional/language/add', $edit, t('Add language')); - // Make sure we're not using a stale list. + // Make sure we are not using a stale list. drupal_static_reset('language_list'); $languages = language_list('language'); $this->assertTrue(array_key_exists($language_code, $languages), t('Language was installed successfully.')); @@ -125,9 +257,12 @@ /** * Create a "Basic page" in the specified language. * - * @param string $title Title of basic page in specified language. - * @param string $body Body of basic page in specified language. - * @param string $language Language code. + * @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(); @@ -146,12 +281,17 @@ } /** - * Create a translation for the specified basic page in the specified language. + * Create a translation for the specified basic page in the specified + * language. * - * @param integer $nid Node id of basic page to create translation for. - * @param string $title Title of basic page in specified language. - * @param string $body Body of basic page in specified language. - * @param string $language Language code. + * @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))); @@ -167,9 +307,108 @@ $this->assertRaw(t('Basic page %title has been created.', array('%title' => $title)), t('Translation created.')); // Check to make sure that translation was successful. - $node = $this->drupalGetNodeByTitle($title); - $this->assertTrue($node, t('Node found in database.')); + $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 $node; + return $translation; + } + + /** + * 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') { + $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) { + $elements = $this->xpath($xpath, $arguments); + + $found = TRUE; + if ($value && $elements) { + $found = FALSE; + foreach ($elements as $element) { + if ((string) $element == $value) { + $found = TRUE; + break; + } + } + } + + return $elements && $found; } } Index: modules/translation_node/tests/translation_node_test.info =================================================================== RCS file: modules/translation_node/tests/translation_node_test.info diff -N modules/translation_node/tests/translation_node_test.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_node/tests/translation_node_test.info 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,6 @@ +; $Id$ +name = "Content translation (Node) Test" +description = "Support module for the node translation tests." +core = 7.x +package = Testing +hidden = TRUE Index: modules/translation_node/tests/translation_node_test.module =================================================================== RCS file: modules/translation_node/tests/translation_node_test.module diff -N modules/translation_node/tests/translation_node_test.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/translation_node/tests/translation_node_test.module 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,14 @@ +