diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 70bec28d0bb..e5b1829661f 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -2690,21 +2690,18 @@ function language_list($field = 'language') { * A language object. */ function language_default() { - return variable_get( + $default = variable_get( 'language_default', (object) array( 'language' => 'en', 'name' => 'English', 'direction' => 0, 'enabled' => 1, - 'plurals' => 0, - 'formula' => '', - 'domain' => '', - 'prefix' => '', 'weight' => 0, - 'javascript' => '' ) ); + $default->default = TRUE; + return $default; } /** diff --git a/core/includes/language.inc b/core/includes/language.inc index 685a4d44a00..073c694cac1 100644 --- a/core/includes/language.inc +++ b/core/includes/language.inc @@ -424,8 +424,9 @@ function language_url_split_prefix($path, $languages) { $prefix = array_shift($args); // Search prefix within enabled languages. + $prefixes = locale_language_negotiation_url_prefixes(); foreach ($languages as $language) { - if (!empty($language->prefix) && $language->prefix == $prefix) { + if (isset($prefixes[$language->language]) && $prefixes[$language->language] == $prefix) { // Rebuild $path with the language removed. return array($language, implode('/', $args)); } diff --git a/core/includes/locale.inc b/core/includes/locale.inc index e9cd427b56f..85d2a8bd73d 100644 --- a/core/includes/locale.inc +++ b/core/includes/locale.inc @@ -279,12 +279,13 @@ function locale_language_from_url($languages) { break; case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN: + $domains = locale_language_negotiation_url_domains(); foreach ($languages as $language) { // Skip check if the language doesn't have a domain. - if ($language->domain) { + if (!empty($domains[$language->language])) { // Only compare the domains not the protocols or ports. // Remove protocol and add http:// so parse_url works - $host = 'http://' . str_replace(array('http://', 'https://'), '', $language->domain); + $host = 'http://' . str_replace(array('http://', 'https://'), '', $domains[$language->language]); $host = parse_url($host, PHP_URL_HOST); if ($_SERVER['HTTP_HOST'] == $host) { $language_url = $language->language; @@ -337,7 +338,9 @@ function locale_language_url_fallback($language = NULL, $language_type = LANGUAG // If the default language is not configured to convey language information, // a missing URL language information indicates that URL language should be // the default one, otherwise we fall back to an already detected language. - if (($prefix && empty($default->prefix)) || (!$prefix && empty($default->domain))) { + $domains = locale_language_negotiation_url_domains(); + $prefixes = locale_language_negotiation_url_prefixes(); + if (($prefix && empty($prefixes[$default->language])) || (!$prefix && empty($domains[$default->language]))) { return $default->language; } else { @@ -428,22 +431,52 @@ function locale_language_url_rewrite_url(&$path, &$options) { if (isset($options['language'])) { switch (variable_get('locale_language_negotiation_url_part', LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX)) { case LOCALE_LANGUAGE_NEGOTIATION_URL_DOMAIN: - if ($options['language']->domain) { + $domains = locale_language_negotiation_url_domains(); + if (!empty($domains[$options['language']->language])) { // Ask for an absolute URL with our modified base_url. $options['absolute'] = TRUE; - $options['base_url'] = $options['language']->domain; + $options['base_url'] = $domains[$options['language']->language]; } break; case LOCALE_LANGUAGE_NEGOTIATION_URL_PREFIX: - if (!empty($options['language']->prefix)) { - $options['prefix'] = $options['language']->prefix . '/'; + $prefixes = locale_language_negotiation_url_prefixes(); + if (!empty($prefixes[$options['language']->language])) { + $options['prefix'] = $prefixes[$options['language']->language] . '/'; } break; } } } +/** + * Reads language prefixes and uses the langcode if no prefix is set. + */ +function locale_language_negotiation_url_prefixes() { + return variable_get('locale_language_negotiation_url_prefixes', array()); +} + +/** + * Saves language prefix settings. + */ +function locale_language_negotiation_url_prefixes_save(array $prefixes) { + variable_set('locale_language_negotiation_url_prefixes', $prefixes); +} + +/** + * Reads language domains. + */ +function locale_language_negotiation_url_domains() { + return variable_get('locale_language_negotiation_url_domains', array()); +} + +/** + * Saves the language domain settings. + */ +function locale_language_negotiation_url_domains_save(array $domains) { + variable_set('locale_language_negotiation_url_domains', $domains); +} + /** * Rewrite URLs for the Session language provider. */ @@ -509,10 +542,6 @@ function locale_string_is_safe($string) { */ function locale_language_save($language) { $language->is_new = !(bool) db_query_range('SELECT 1 FROM {languages} WHERE language = :language', 0, 1, array(':language' => $language->language))->fetchField(); - // Default prefix on language code if not provided otherwise. - if (!isset($language->prefix)) { - $language->prefix = $language->language; - } // If name was not set, we add a predefined language. if (!isset($language->name)) { diff --git a/core/modules/locale/locale.admin.inc b/core/modules/locale/locale.admin.inc index 97d6b64186c..57326979ec0 100644 --- a/core/modules/locale/locale.admin.inc +++ b/core/modules/locale/locale.admin.inc @@ -173,15 +173,6 @@ function locale_language_overview_form_submit($form, &$form_state) { } $language->enabled = (int) !empty($form_state['values']['languages'][$langcode]['enabled']); - // If language URL prefixes are enabled we must clear language domains and - // assign a valid prefix to each non-default language. - if ($url_prefixes) { - $language->domain = ''; - if (empty($language->prefix) && !$language->default) { - $language->prefix = $langcode; - } - } - locale_language_save($language); } @@ -704,20 +695,21 @@ function locale_language_providers_url_form($form, &$form_state) { ); $languages = language_list('enabled'); + $prefixes = locale_language_negotiation_url_prefixes(); + $domains = locale_language_negotiation_url_domains(); foreach ($languages[1] as $langcode => $language) { $form['prefix'][$langcode] = array( '#type' => 'textfield', '#title' => t('%language (%langcode) path prefix', array('%language' => $language->name, '%langcode' => $language->language)), '#maxlength' => 64, - '#default_value' => $language->prefix, - '#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=') - + '#default_value' => isset($prefixes[$langcode]) ? $prefixes[$langcode] : '', + '#field_prefix' => url('', array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=') ); $form['domain'][$langcode] = array( '#type' => 'textfield', '#title' => t('%language (%langcode) domain', array('%language' => $language->name, '%langcode' => $language->language)), '#maxlength' => 128, - '#default_value' => $language->domain, + '#default_value' => isset($domains[$langcode]) ? $domains[$langcode] : '', ); } @@ -784,21 +776,9 @@ function locale_language_providers_url_form_submit($form, &$form_state) { // Save selected format (prefix or domain). variable_set('locale_language_negotiation_url_part', $form_state['values']['locale_language_negotiation_url_part']); - $languages = language_list('enabled'); - $default = language_default(); - - foreach ($languages[1] as $langcode => $language) { - - // Add new prefix and domain settings to the language object. - foreach (array('prefix', 'domain') as $type) { - if (isset($form_state['values'][$type][$langcode])) { - $language->$type = $form_state['values'][$type][$langcode]; - } - } - - // Save the prefix and domain settings for each language. - locale_language_save($language); - } + // Save new domain and prefix values. + locale_language_negotiation_url_prefixes_save($form_state['values']['prefix']); + locale_language_negotiation_url_domains_save($form_state['values']['domain']); drupal_set_message(t('Configuration saved.')); } diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install index 80f0a7e211f..4ae03fcbc4f 100644 --- a/core/modules/locale/locale.install +++ b/core/modules/locale/locale.install @@ -39,6 +39,8 @@ function locale_uninstall() { variable_del('language_count'); variable_del('language_types'); variable_del('locale_language_negotiation_url_part'); + variable_del('locale_language_negotiation_url_prefixes'); + variable_del('locale_language_negotiation_url_domains'); variable_del('locale_language_negotiation_session_param'); variable_del('language_content_type_default'); variable_del('language_content_type_negotiation'); @@ -99,20 +101,6 @@ function locale_schema() { 'default' => 0, 'description' => 'Enabled flag (1 = Enabled, 0 = Disabled).', ), - 'domain' => array( - 'type' => 'varchar', - 'length' => 128, - 'not null' => TRUE, - 'default' => '', - 'description' => 'Domain to use for this language.', - ), - 'prefix' => array( - 'type' => 'varchar', - 'length' => 128, - 'not null' => TRUE, - 'default' => '', - 'description' => 'Path prefix to use for this language.', - ), 'weight' => array( 'type' => 'int', 'not null' => TRUE, @@ -277,6 +265,37 @@ function locale_update_8002() { db_drop_field('locales_source', 'textgroup'); } +/** + * Removes the prefix and domain columns from the language table. + * + * Load all prefixes and domains from the languages table, save the values in + * two new variables. Then remove the prefix and domain columns from the + * languages table. + */ +function locale_update_8003() { + + // Look up languages directly instead of using language_list(). + $languages = db_select('languages', 'l') + ->fields('l') + ->execute(); + + // Collect all domains and prefixes. + $prefixes = array(); + $domains = array(); + foreach ($languages as $language) { + $prefixes[$language->language] = $language->prefix; + $domains[$language->language] = $language->domain; + } + + // Save the prefix and domain values in a variable. + variable_set('locale_language_negotiation_url_prefixes', $prefixes); + variable_set('locale_language_negotiation_url_domains', $domains); + + // Remove the prefix and domain columns. + db_drop_field('languages', 'prefix'); + db_drop_field('languages', 'domain'); +} + /** * @} End of "addtogroup updates-7.x-to-8.x" * The next series of updates should start at 9000. diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module index 74a74349e30..5168a24c833 100644 --- a/core/modules/locale/locale.module +++ b/core/modules/locale/locale.module @@ -607,6 +607,56 @@ function locale_modules_disabled($modules) { locale_modules_enabled($modules); } +/** + * Implements hook_locale_language_insert(). + */ +function locale_locale_language_insert($language) { + // Add new language to the list of language prefixes. + $prefixes = locale_language_negotiation_url_prefixes(); + $prefixes[$language->language] = (empty($language->default) ? $language->language : ''); + locale_language_negotiation_url_prefixes_save($prefixes); + + // Add language to the list of language domains. + $domains = locale_language_negotiation_url_domains(); + $domains[$language->language] = ''; + locale_language_negotiation_url_domains_save($domains); +} + +/** + * Implements hook_locale_language_update(). + */ +function locale_locale_language_update($language) { + + // If the language is the default, then ensure that no other languages have + // blank prefix codes. + if (!empty($language->default)) { + $prefixes = locale_language_negotiation_url_prefixes(); + foreach ($prefixes as $langcode => $prefix) { + if ($prefix == '' && $langcode != $language->language) { + $prefixes[$langcode] = $langcode; + } + } + locale_language_negotiation_url_prefixes_save($prefixes); + } + +} + +/** + * Implements hook_locale_language_delete(). + */ +function locale_locale_language_delete($language) { + // Remove language from language prefix list. + $prefixes = locale_language_negotiation_url_prefixes(); + unset($prefixes[$language->language]); + locale_language_negotiation_url_prefixes_save($prefixes); + + // Remove language from language domain list. + $domains = locale_language_negotiation_url_domains(); + unset($domains[$language->language]); + locale_language_negotiation_url_domains_save($domains); +} + + // --------------------------------------------------------------------------------- // Locale core functionality diff --git a/core/modules/locale/locale.test b/core/modules/locale/locale.test index d6cd76ad9ff..fb5bb37e825 100644 --- a/core/modules/locale/locale.test +++ b/core/modules/locale/locale.test @@ -2346,7 +2346,6 @@ class LocaleUrlRewritingTest extends DrupalWebTestCase { // Check URL rewriting with a non-installed language. $non_existing = language_default(); $non_existing->language = $this->randomName(); - $non_existing->prefix = $this->randomName(); $this->checkUrl($non_existing, t('Path language is ignored if language is not installed.'), t('URL language negotiation does not work with non-installed languages')); } @@ -2364,11 +2363,15 @@ class LocaleUrlRewritingTest extends DrupalWebTestCase { $segments = explode('/', $rewritten_path, 2); $prefix = $segments[0]; $path = isset($segments[1]) ? $segments[1] : $prefix; - // If the rewritten URL has not a language prefix we pick the right one from - // the language object so we can always check the prefixed URL. - if ($this->assertNotEqual($language->prefix, $prefix, $message1)) { - $prefix = $language->prefix; + + // If the rewritten URL has not a language prefix we pick a random prefix so + // we can always check the prefixed URL. + $prefixes = locale_language_negotiation_url_prefixes(); + $stored_prefix = isset($prefixes[$language->language]) ? $prefixes[$language->language] : $this->randomName(); + if ($this->assertNotEqual($stored_prefix, $prefix, $message1)) { + $prefix = $stored_prefix; } + $this->drupalGet("$prefix/$path"); $this->assertResponse(404, $message2); } @@ -2568,9 +2571,10 @@ class LocaleCommentLanguageFunctionalTest extends DrupalWebTestCase { $this->drupalPost("node/add/article", $edit, t('Save')); $node = $this->drupalGetNodeByTitle($title); + $prefixes = locale_language_negotiation_url_prefixes(); foreach (language_list() as $langcode => $language) { // Post a comment with content language $langcode. - $prefix = empty($language->prefix) ? '' : $language->prefix . '/'; + $prefix = empty($prefixes[$langcode]) ? '' : $prefixes[$langcode] . '/'; $edit = array("comment_body[$langcode_none][0][value]" => $this->randomName()); $this->drupalPost("{$prefix}node/{$node->nid}", $edit, t('Save')); diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php index 2818578303e..91fd2c75240 100644 --- a/core/modules/simpletest/drupal_web_test_case.php +++ b/core/modules/simpletest/drupal_web_test_case.php @@ -1288,7 +1288,13 @@ class DrupalWebTestCase extends DrupalTestCase { // Set to English to prevent exceptions from utf8_truncate() from t() // during install if the current language is not 'en'. // The following array/object conversion is copied from language_default(). - $language = (object) array('language' => 'en', 'name' => 'English', 'native' => 'English', 'direction' => 0, 'enabled' => 1, 'plurals' => 0, 'formula' => '', 'domain' => '', 'prefix' => '', 'weight' => 0, 'javascript' => ''); + $language = (object) array( + 'language' => 'en', + 'name' => 'English', + 'direction' => 0, + 'enabled' => 1, + 'weight' => 0, + ); // Save and clean shutdown callbacks array because it static cached and // will be changed by the test run. If we don't, then it will contain diff --git a/core/modules/translation/translation.test b/core/modules/translation/translation.test index c8a1ccdbbae..0e801c1bf9f 100644 --- a/core/modules/translation/translation.test +++ b/core/modules/translation/translation.test @@ -77,8 +77,9 @@ class TranslationTestCase extends DrupalWebTestCase { // Check that the "add translation" link uses a localized path. $languages = language_list(); + $prefixes = locale_language_negotiation_url_prefixes(); $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))); + $this->assertLinkByHref($prefixes['es'] . '/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(); @@ -88,8 +89,8 @@ class TranslationTestCase extends DrupalWebTestCase { // 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))); + $this->assertLinkByHref($prefixes['es'] . '/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($prefixes['es'] . '/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.