Commit 661488af authored by Dries's avatar Dries

- Patch #1222106 by Gábor Hojtsy, plach, xjm: Unify language negotiation APIs,...

- Patch #1222106 by Gábor Hojtsy, plach, xjm: Unify language negotiation APIs, declutter terminology.
parent cf77b6e8
...@@ -20,22 +20,22 @@ ...@@ -20,22 +20,22 @@
* The negotiated language object. * The negotiated language object.
*/ */
function language_types_initialize($type) { function language_types_initialize($type) {
// Execute the language providers in the order they were set up and return the // Execute the language negotiation methods in the order they were set up and
// first valid language found. // return the first valid language found.
$negotiation = variable_get("language_negotiation_$type", array()); $negotiation = variable_get("language_negotiation_$type", array());
foreach ($negotiation as $provider_id => $provider) { foreach ($negotiation as $method_id => $method) {
$language = language_provider_invoke($provider_id, $provider); $language = language_negotiation_method_invoke($method_id, $method);
if ($language) { if ($language) {
// Remember the provider key used to detect the language. // Remember the method ID used to detect the language.
$language->provider = $provider_id; $language->method_id = $method_id;
return $language; return $language;
} }
} }
// If no other language was found use the default one. // If no other language was found use the default one.
$language = language_default(); $language = language_default();
$language->provider = LANGUAGE_NEGOTIATION_DEFAULT; $language->method_id = LANGUAGE_NEGOTIATION_DEFAULT;
return $language; return $language;
} }
...@@ -68,11 +68,11 @@ function language_types_info() { ...@@ -68,11 +68,11 @@ function language_types_info() {
* language type itself. * language type itself.
* *
* @param $stored * @param $stored
* Optional. By default retrieves values from the 'language_types' variable to * (optional) By default, retrieves values from the 'language_types' variable
* avoid unnecessary hook invocations. * to avoid unnecessary hook invocations. If set to FALSE, retrieves values
* If set to FALSE retrieves values from the actual language type definitions. * from the actual language type definitions. This allows reaction to
* This allows to react to alterations performed on the definitions by modules * alterations performed on the definitions by modules installed after the
* installed after the 'language_types' variable is set. * 'language_types' variable is set.
* *
* @return * @return
* An array of language type names. * An array of language type names.
...@@ -99,7 +99,7 @@ function language_types_get_configurable($stored = TRUE) { ...@@ -99,7 +99,7 @@ function language_types_get_configurable($stored = TRUE) {
} }
/** /**
* Disable the given language types. * Disables the given language types.
* *
* @param $types * @param $types
* An array of language types. * An array of language types.
...@@ -128,17 +128,17 @@ function language_types_set() { ...@@ -128,17 +128,17 @@ function language_types_set() {
// whether the 'fixed' key is defined. Non-configurable (fixed) language types // whether the 'fixed' key is defined. Non-configurable (fixed) language types
// have their language negotiation settings stored there. // have their language negotiation settings stored there.
$language_types = array(); $language_types = array();
$defined_providers = language_negotiation_info(); $negotiation_info = language_negotiation_info();
foreach (language_types_info() as $type => $info) { foreach (language_types_info() as $type => $info) {
if (isset($info['fixed'])) { if (isset($info['fixed'])) {
$language_types[$type] = FALSE; $language_types[$type] = FALSE;
$negotiation = array(); $method_weights = array();
foreach ($info['fixed'] as $weight => $id) { foreach ($info['fixed'] as $weight => $method_id) {
if (isset($defined_providers[$id])) { if (isset($negotiation_info[$method_id])) {
$negotiation[$id] = $weight; $method_weights[$method_id] = $weight;
} }
} }
language_negotiation_set($type, $negotiation); language_negotiation_set($type, $method_weights);
} }
else { else {
$language_types[$type] = TRUE; $language_types[$type] = TRUE;
...@@ -154,52 +154,35 @@ function language_types_set() { ...@@ -154,52 +154,35 @@ function language_types_set() {
} }
/** /**
* Check if a language provider is enabled. * Returns the ID of the language type's first language negotiation method.
*
* This has two possible behaviors:
* - If $provider_id is given return its ID if enabled, FALSE otherwise.
* - If no ID is passed the first enabled language provider is returned.
* *
* @param $type * @param $type
* The language negotiation type. * The language type.
* @param $provider_id
* The language provider ID.
*
* @return
* The provider ID if it is enabled, FALSE otherwise.
*/ */
function language_negotiation_get($type, $provider_id = NULL) { function language_negotiation_method_get_first($type) {
$negotiation = variable_get("language_negotiation_$type", array()); $negotiation = variable_get("language_negotiation_$type", array());
return empty($negotiation) ? LANGUAGE_NEGOTIATION_DEFAULT : key($negotiation);
if (empty($negotiation)) {
return empty($provider_id) ? LANGUAGE_NEGOTIATION_DEFAULT : FALSE;
}
if (empty($provider_id)) {
return key($negotiation);
}
if (isset($negotiation[$provider_id])) {
return $provider_id;
}
return FALSE;
} }
/** /**
* Check if the given language provider is enabled for any configurable language * Checks if a language negotiation method is enabled for a language type.
* type.
* *
* @param $provider_id * @param $method_id
* The language provider ID. * The language negotiation method ID.
* @param $type
* (optional) The language type. If none is passed, all the configurable
* language types will be inspected.
* *
* @return * @return
* TRUE if there is at least one language type for which the give language * TRUE if the method is enabled for at least one of the given language
* provider is enabled, FALSE otherwise. * types, or FALSE otherwise.
*/ */
function language_negotiation_get_any($provider_id) { function language_negotiation_method_enabled($method_id, $type = NULL) {
foreach (language_types_get_configurable() as $type) { $language_types = !empty($type) ? array($type) : language_types_get_configurable();
if (language_negotiation_get($type, $provider_id)) {
foreach ($language_types as $type) {
$negotiation = variable_get("language_negotiation_$type", array());
if (isset($negotiation[$method_id])) {
return TRUE; return TRUE;
} }
} }
...@@ -208,10 +191,10 @@ function language_negotiation_get_any($provider_id) { ...@@ -208,10 +191,10 @@ function language_negotiation_get_any($provider_id) {
} }
/** /**
* Return the language switch links for the given language. * Returns the language switch links for the given language type.
* *
* @param $type * @param $type
* The language negotiation type. * The language type.
* @param $path * @param $path
* The internal path the switch links will be relative to. * The internal path the switch links will be relative to.
* *
...@@ -222,19 +205,19 @@ function language_negotiation_get_switch_links($type, $path) { ...@@ -222,19 +205,19 @@ function language_negotiation_get_switch_links($type, $path) {
$links = FALSE; $links = FALSE;
$negotiation = variable_get("language_negotiation_$type", array()); $negotiation = variable_get("language_negotiation_$type", array());
foreach ($negotiation as $id => $provider) { foreach ($negotiation as $method_id => $method) {
if (isset($provider['callbacks']['switcher'])) { if (isset($method['callbacks']['language_switch'])) {
if (isset($provider['file'])) { if (isset($method['file'])) {
require_once DRUPAL_ROOT . '/' . $provider['file']; require_once DRUPAL_ROOT . '/' . $method['file'];
} }
$callback = $provider['callbacks']['switcher']; $callback = $method['callbacks']['language_switch'];
$result = $callback($type, $path); $result = $callback($type, $path);
if (!empty($result)) { if (!empty($result)) {
// Allow modules to provide translations for specific links. // Allow modules to provide translations for specific links.
drupal_alter('language_switch_links', $result, $type, $path); drupal_alter('language_switch_links', $result, $type, $path);
$links = (object) array('links' => $result, 'provider' => $id); $links = (object) array('links' => $result, 'method_id' => $method_id);
break; break;
} }
} }
...@@ -244,7 +227,7 @@ function language_negotiation_get_switch_links($type, $path) { ...@@ -244,7 +227,7 @@ function language_negotiation_get_switch_links($type, $path) {
} }
/** /**
* Updates language configuration to remove any language provider that is no longer defined. * Removes any language negotiation methods that are no longer defined.
*/ */
function language_negotiation_purge() { function language_negotiation_purge() {
// Ensure that we are getting the defined language negotiation information. An // Ensure that we are getting the defined language negotiation information. An
...@@ -253,60 +236,54 @@ function language_negotiation_purge() { ...@@ -253,60 +236,54 @@ function language_negotiation_purge() {
drupal_static_reset('language_negotiation_info'); drupal_static_reset('language_negotiation_info');
drupal_static_reset('language_types_info'); drupal_static_reset('language_types_info');
$defined_providers = language_negotiation_info(); $negotiation_info = language_negotiation_info();
foreach (language_types_info() as $type => $type_info) { foreach (language_types_info() as $type => $type_info) {
$weight = 0; $weight = 0;
$negotiation = array(); $method_weights = array();
foreach (variable_get("language_negotiation_$type", array()) as $id => $provider) { foreach (variable_get("language_negotiation_$type", array()) as $method_id => $method) {
if (isset($defined_providers[$id])) { if (isset($negotiation_info[$method_id])) {
$negotiation[$id] = $weight++; $method_weights[$method_id] = $weight++;
} }
} }
language_negotiation_set($type, $negotiation); language_negotiation_set($type, $method_weights);
} }
} }
/** /**
* Save a list of language providers. * Saves a list of language negotiation methods for a language type.
* *
* @param $type * @param $type
* The language negotiation type. * The language type.
* @param $language_providers * @param $method_weights
* An array of language provider weights keyed by id. * An array of language negotiation method weights keyed by method id.
* @see language_provider_weight()
*/ */
function language_negotiation_set($type, $language_providers) { function language_negotiation_set($type, $method_weights) {
// Save only the necessary fields. // Save only the necessary fields.
$provider_fields = array('callbacks', 'file', 'cache'); $method_fields = array('callbacks', 'file', 'cache');
$negotiation = array(); $negotiation = array();
$providers_weight = array(); $negotiation_info = language_negotiation_info();
$defined_providers = language_negotiation_info();
$default_types = language_types_get_configurable(FALSE); $default_types = language_types_get_configurable(FALSE);
// Initialize the providers weight list. // Order the language negotiation method list by weight.
foreach ($language_providers as $id => $provider) { asort($method_weights);
$providers_weight[$id] = language_provider_weight($provider);
} foreach ($method_weights as $method_id => $weight) {
if (isset($negotiation_info[$method_id])) {
// Order providers list by weight. $method = $negotiation_info[$method_id];
asort($providers_weight); // If the language negotiation method does not express any preference
// about types, make it available for any configurable type.
foreach ($providers_weight as $id => $weight) { $types = array_flip(isset($method['types']) ? $method['types'] : $default_types);
if (isset($defined_providers[$id])) { // Check if the language negotiation method is defined and has the right
$provider = $defined_providers[$id]; // type.
// If the provider does not express any preference about types, make it
// available for any configurable type.
$types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
// Check if the provider is defined and has the right type.
if (isset($types[$type])) { if (isset($types[$type])) {
$provider_data = array(); $method_data = array();
foreach ($provider_fields as $field) { foreach ($method_fields as $field) {
if (isset($provider[$field])) { if (isset($method[$field])) {
$provider_data[$field] = $provider[$field]; $method_data[$field] = $method[$field];
} }
} }
$negotiation[$id] = $provider_data; $negotiation[$method_id] = $method_data;
} }
} }
} }
...@@ -315,20 +292,20 @@ function language_negotiation_set($type, $language_providers) { ...@@ -315,20 +292,20 @@ function language_negotiation_set($type, $language_providers) {
} }
/** /**
* Return all the defined language providers. * Returns all defined language negotiation methods.
* *
* @return * @return
* An array of language providers. * An array of language negotiation methods.
*/ */
function language_negotiation_info() { function language_negotiation_info() {
$language_providers = &drupal_static(__FUNCTION__); $negotiation_info = &drupal_static(__FUNCTION__);
if (!isset($language_providers)) { if (!isset($negotiation_info)) {
// Collect all the module-defined language negotiation providers. // Collect all the module-defined language negotiation methods.
$language_providers = module_invoke_all('language_negotiation_info'); $negotiation_info = module_invoke_all('language_negotiation_info');
// Add the default language provider. // Add the default language negotiation method.
$language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array( $negotiation_info[LANGUAGE_NEGOTIATION_DEFAULT] = array(
'callbacks' => array('language' => 'language_from_default'), 'callbacks' => array('language' => 'language_from_default'),
'weight' => 10, 'weight' => 10,
'name' => t('Default language'), 'name' => t('Default language'),
...@@ -336,74 +313,60 @@ function language_negotiation_info() { ...@@ -336,74 +313,60 @@ function language_negotiation_info() {
'config' => 'admin/config/regional/language', 'config' => 'admin/config/regional/language',
); );
// Let other modules alter the list of language providers. // Let other modules alter the list of language negotiation methods.
drupal_alter('language_negotiation_info', $language_providers); drupal_alter('language_negotiation_info', $negotiation_info);
} }
return $language_providers; return $negotiation_info;
} }
/** /**
* Helper function used to cache the language providers results. * Invokes a language negotiation method and caches the results.
* *
* @param $provider_id * @param $method_id
* The language provider ID. * The language negotiation method ID.
* @param $provider * @param $method
* The language provider to be invoked. If not passed it will be explicitly * (optional) The language negotiation method to be invoked. If not passed it
* loaded through language_negotiation_info(). * will be explicitly loaded through language_negotiation_info().
* *
* @return * @return
* The language provider's return value. * The language negotiation method's return value.
*/ */
function language_provider_invoke($provider_id, $provider = NULL) { function language_negotiation_method_invoke($method_id, $method = NULL) {
$results = &drupal_static(__FUNCTION__); $results = &drupal_static(__FUNCTION__);
if (!isset($results[$provider_id])) { if (!isset($results[$method_id])) {
global $user; global $user;
// Get the enabled languages only. // Get the enabled languages only.
$languages = language_list(TRUE); $languages = language_list(TRUE);
if (!isset($provider)) { if (!isset($method)) {
$providers = language_negotiation_info(); $negotiation_info = language_negotiation_info();
$provider = $providers[$provider_id]; $method = $negotiation_info[$method_id];
} }
if (isset($provider['file'])) { if (isset($method['file'])) {
require_once DRUPAL_ROOT . '/' . $provider['file']; require_once DRUPAL_ROOT . '/' . $method['file'];
} }
// If the language provider has no cache preference or this is satisfied // If the language negotiation method has no cache preference or this is
// we can execute the callback. // satisfied we can execute the callback.
$config = config('system.performance'); $cache = !isset($method['cache']) || $user->uid || $method['cache'] == variable_get('cache', 0);
$cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == $config->get('cache'); $callback = isset($method['callbacks']['negotiation']) ? $method['callbacks']['negotiation'] : FALSE;
$callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
$langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE; $langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
$results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE; $results[$method_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
} }
// Since objects are resources we need to return a clone to prevent the // Since objects are resources we need to return a clone to prevent the
// provider cache to be unintentionally altered. The same providers might be // language negotiation method cache to be unintentionally altered. The same
// used with different language types based on configuration. // language negotiation methods might be used with different language types
return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id]; // based on configuration.
} return !empty($results[$method_id]) ? clone($results[$method_id]) : $results[$method_id];
/**
* Return the passed language provider weight or a default value.
*
* @param $provider
* A language provider data structure.
*
* @return
* A numeric weight.
*/
function language_provider_weight($provider) {
$default = is_numeric($provider) ? $provider : 0;
return isset($provider['weight']) && is_numeric($provider['weight']) ? $provider['weight'] : $default;
} }
/** /**
* Default language provider. * Returns the default language code.
* *
* @return * @return
* The default language code. * The default language code.
......
...@@ -264,7 +264,7 @@ function locale_language_from_session($languages) { ...@@ -264,7 +264,7 @@ function locale_language_from_session($languages) {
function locale_language_from_url($languages) { function locale_language_from_url($languages) {
$language_url = FALSE; $language_url = FALSE;
if (!language_negotiation_get_any(LANGUAGE_NEGOTIATION_URL)) { if (!language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_URL)) {
return $language_url; return $language_url;
} }
...@@ -303,8 +303,8 @@ function locale_language_from_url($languages) { ...@@ -303,8 +303,8 @@ function locale_language_from_url($languages) {
* Determines the language to be assigned to URLs when none is detected. * Determines the language to be assigned to URLs when none is detected.
* *
* The language negotiation process has a fallback chain that ends with the * The language negotiation process has a fallback chain that ends with the
* default language provider. Each built-in language type has a separate * default language negotiation method. Each built-in language type has a
* initialization: * separate initialization:
* - Interface language, which is the only configurable one, always gets a valid * - Interface language, which is the only configurable one, always gets a valid
* value. If no request-specific language is detected, the default language * value. If no request-specific language is detected, the default language
* will be used. * will be used.
...@@ -322,8 +322,8 @@ function locale_language_from_url($languages) { ...@@ -322,8 +322,8 @@ function locale_language_from_url($languages) {
* *
* @param $languages * @param $languages
* (optional) An array of valid language objects. This is passed by * (optional) An array of valid language objects. This is passed by
* language_provider_invoke() to every language provider callback, but it is * language_negotiation_method_invoke() to every language method callback,
* not actually needed here. Defaults to NULL. * but it is not actually needed here. Defaults to NULL.
* @param $language_type * @param $language_type
* (optional) The language type to fall back to. Defaults to the interface * (optional) The language type to fall back to. Defaults to the interface
* language. * language.
...@@ -406,7 +406,7 @@ function locale_language_switcher_session($type, $path) { ...@@ -406,7 +406,7 @@ function locale_language_switcher_session($type, $path) {
} }
/** /**
* Rewrite URLs for the URL language provider. * Rewrite URLs for the URL language negotiation method.
*/ */
function locale_language_url_rewrite_url(&$path, &$options) { function locale_language_url_rewrite_url(&$path, &$options) {
static $drupal_static_fast; static $drupal_static_fast;
...@@ -492,7 +492,7 @@ function locale_language_negotiation_url_domains_save(array $domains) { ...@@ -492,7 +492,7 @@ function locale_language_negotiation_url_domains_save(array $domains) {
} }
/** /**
* Rewrite URLs for the Session language provider. * Rewrite URLs for the Session language negotiation method.
*/ */
function locale_language_url_rewrite_session(&$path, &$options) { function locale_language_url_rewrite_session(&$path, &$options) {
static $query_rewrite, $query_param, $query_value; static $query_rewrite, $query_param, $query_value;
...@@ -506,16 +506,16 @@ function locale_language_url_rewrite_session(&$path, &$options) { ...@@ -506,16 +506,16 @@ function locale_language_url_rewrite_session(&$path, &$options) {
$languages = language_list(TRUE); $languages = language_list(TRUE);
$query_param = check_plain(variable_get('locale_language_negotiation_session_param', 'language')); $query_param = check_plain(variable_get('locale_language_negotiation_session_param', 'language'));
$query_value = isset($_GET[$query_param]) ? check_plain($_GET[$query_param]) : NULL; $query_value = isset($_GET[$query_param]) ? check_plain($_GET[$query_param]) : NULL;
$query_rewrite = isset($languages[$query_value]) && language_negotiation_get_any(LANGUAGE_NEGOTIATION_SESSION); $query_rewrite = isset($languages[$query_value]) && language_negotiation_method_enabled(LANGUAGE_NEGOTIATION_SESSION);
} }
else { else {
$query_rewrite = FALSE; $query_rewrite = FALSE;
} }
} }
// If the user is anonymous, the user language provider is enabled, and the // If the user is anonymous, the user language negotiation method is enabled,
// corresponding option has been set, we must preserve any explicit user // and the corresponding option has been set, we must preserve any explicit
// language preference even with cookies disabled. // user language preference even with cookies disabled.
if ($query_rewrite) { if ($query_rewrite) {
if (is_string($options['query'])) { if (is_string($options['query'])) {
$options['query'] = drupal_get_query_array($options['query']); $options['query'] = drupal_get_query_array($options['query']);
......
...@@ -140,9 +140,9 @@ function update_prepare_stored_includes() { ...@@ -140,9 +140,9 @@ function update_prepare_stored_includes() {
// Update language negotiation settings.