Issue #1301460 by loganfsmyth, good_man, Gábor Hojtsy, xjm: Decouple domain/path language negotiation storage from language config storage.

8.0.x
catch 2011-11-29 11:23:49 +09:00
parent 7135589c89
commit c42985ffb3
9 changed files with 157 additions and 70 deletions

View File

@ -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;
}
/**

View File

@ -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));
}

View File

@ -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)) {

View File

@ -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.'));
}

View File

@ -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.

View File

@ -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

View File

@ -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'));

View File

@ -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

View File

@ -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.