diff --git a/includes/language.inc b/includes/language.inc index d0ea83113371ea7517548774a6d790d696a64eb1..ea63948d980d7b012fd118293f6dcd7d598243cf 100644 --- a/includes/language.inc +++ b/includes/language.inc @@ -2,7 +2,9 @@ /** * @file - * Multiple language handling functionality. + * Language Negotiation API. + * + * @see http://drupal.org/node/1497272 */ /** @@ -11,7 +13,96 @@ define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default'); /** - * Return all the defined language types. + * @defgroup language_negotiation Language Negotiation API functionality + * @{ + * Functions to customize the language types and the negotiation process. + * + * The language negotiation API is based on two major concepts: + * - Language types: types of translatable data (the types of data that a user + * can view or request). + * - Language negotiation providers: functions for determining which language to + * use to present a particular piece of data to the user. + * Both language types and language negotiation providers are customizable. + * + * Drupal defines three built-in language types: + * - Interface language: The page's main language, used to present translated + * user interface elements such as titles, labels, help text, and messages. + * - Content language: The language used to present content that is available + * in more than one language (see + * @link field_language Field Language API @endlink for details). + * - URL language: The language associated with URLs. When generating a URL, + * this value will be used by url() as a default if no explicit preference is + * provided. + * Modules can define additional language types through + * hook_language_types_info(), and alter existing language type definitions + * through hook_language_types_info_alter(). + * + * Language types may be configurable or fixed. The language negotiation + * providers associated with a configurable language type can be explicitly + * set through the user interface. A fixed language type has predetermined + * (module-defined) language negotiation settings and, thus, does not appear in + * the configuration page. Here is a code snippet that makes the content + * language (which by default inherits the interface language's values) + * configurable: + * @code + * function mymodule_language_types_info_alter(&$language_types) { + * unset($language_types[LANGUAGE_TYPE_CONTENT]['fixed']); + * } + * @endcode + * + * Every language type can have a different set of language negotiation + * providers assigned to it. Different language types often share the same + * language negotiation settings, but they can have independent settings if + * needed. If two language types are configured the same way, their language + * switcher configuration will be functionally identical and the same settings + * will act on both language types. + * + * Drupal defines the following built-in language negotiation providers: + * - URL: Determine the language from the URL (path prefix or domain). + * - Session: Determine the language from a request/session parameter. + * - User: Follow the user's language preference. + * - Browser: Determine the language from the browser's language settings. + * - Default language: Use the default site language. + * Language negotiation providers are simple callback functions that implement a + * particular logic to return a language code. For instance, the URL provider + * searches for a valid path prefix or domain name in the current request URL. + * If a language negotiation provider does not return a valid language code, the + * next provider associated to the language type (based on provider weight) is + * invoked. + * + * Modules can define additional language negotiation providers through + * hook_language_negotiation_info(), and alter existing providers through + * hook_language_negotiation_info_alter(). Here is an example snippet that lets + * path prefixes be ignored for administrative paths: + * @code + * function mymodule_language_negotiation_info_alter(&$negotiation_info) { + * // Replace the core function with our own function. + * module_load_include('language', 'inc', 'language.negotiation'); + * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['callbacks']['negotiation'] = 'mymodule_from_url'; + * $negotiation_info[LANGUAGE_NEGOTIATION_URL]['file'] = drupal_get_path('module', 'mymodule') . '/mymodule.module'; + * } + * + * function mymodule_from_url($languages) { + * // Use the core URL language negotiation provider to get a valid language + * // code. + * module_load_include('language', 'inc', 'language.negotiation'); + * $langcode = language_from_url($languages); + * + * // If we are on an administrative path, override with the default language. + * if (isset($_GET['q']) && strtok($_GET['q'], '/') == 'admin') { + * return language_default()->langcode; + * } + * return $langcode; + * } + * ?> + * @endcode + * + * For more information, see + * @link http://drupal.org/node/1497272 Language Negotiation API @endlink + */ + +/** + * Returns all the defined language types. * * @return * An array of language type names. The name will be used as the global @@ -30,11 +121,11 @@ function language_types_info() { } /** - * Return only the configurable language types. + * Returns only the configurable language types. * * A language type maybe configurable or fixed. A fixed language type is a type - * whose negotiation values are unchangeable and defined while defining the - * language type itself. + * whose language negotiation providers are module-defined and not altered + * through the user interface. * * @param $stored * Optional. By default retrieves values from the 'language_types' variable to @@ -68,7 +159,7 @@ function language_types_configurable($stored = TRUE) { } /** - * Disable the given language types. + * Disables the given language types. * * @param $types * An array of language types. @@ -122,16 +213,17 @@ function language_types_set() { } /** - * Check if a language provider is enabled. + * Checks whether a language negotiation provider is enabled for a language type. * * 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. + * - If no ID is passed the first enabled language negotiation provider is + * returned. * * @param $type - * The language negotiation type. + * The language negotiation provider type. * @param $provider_id - * The language provider ID. + * The language negotiation provider ID. * * @return * The provider ID if it is enabled, FALSE otherwise. @@ -155,14 +247,13 @@ function language_negotiation_get($type, $provider_id = NULL) { } /** - * Check if the given language provider is enabled for any configurable language - * type. + * Checks if the language negotiation provider is enabled for any language type. * * @param $provider_id - * The language provider ID. + * The language negotiation provider ID. * * @return - * TRUE if there is at least one language type for which the give language + * TRUE if there is at least one language type for which the given language * provider is enabled, FALSE otherwise. */ function language_negotiation_get_any($provider_id) { @@ -176,7 +267,7 @@ 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. * * @param $type * The language negotiation type. @@ -223,7 +314,7 @@ function language_negotiation_get_switch_links($type, $path) { } /** - * Updates language configuration to remove any language provider that is no longer defined. + * Removes any unused language negotation providers from the configuration. */ function language_negotiation_purge() { // Ensure that we are getting the defined language negotiation information. An @@ -246,12 +337,12 @@ function language_negotiation_purge() { } /** - * Save a list of language providers. + * Saves a list of language negotiation providers. * * @param $type * The language negotiation type. * @param $language_providers - * An array of language provider weights keyed by id. + * An array of language negotiation provider weights keyed by provider ID. * @see language_provider_weight() */ function language_negotiation_set($type, $language_providers) { @@ -277,7 +368,7 @@ function language_negotiation_set($type, $language_providers) { // 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. + // Check whether the provider is defined and has the right type. if (isset($types[$type])) { $provider_data = array(); foreach ($provider_fields as $field) { @@ -294,10 +385,10 @@ function language_negotiation_set($type, $language_providers) { } /** - * Return all the defined language providers. + * Returns all the defined language negotiation providers. * * @return - * An array of language providers. + * An array of language negotiation providers. */ function language_negotiation_info() { $language_providers = &drupal_static(__FUNCTION__); @@ -306,7 +397,7 @@ function language_negotiation_info() { // Collect all the module-defined language negotiation providers. $language_providers = module_invoke_all('language_negotiation_info'); - // Add the default language provider. + // Add the default language negotiation provider. $language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array( 'callbacks' => array('language' => 'language_from_default'), 'weight' => 10, @@ -314,7 +405,7 @@ function language_negotiation_info() { 'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)), ); - // Let other modules alter the list of language providers. + // Let other modules alter the list of language negotiation providers. drupal_alter('language_negotiation_info', $language_providers); } @@ -322,16 +413,17 @@ function language_negotiation_info() { } /** - * Helper function used to cache the language providers results. + * Helper function used to cache the language negotiation providers results. * * @param $provider_id - * The language provider ID. + * The language negotiation provider's identifier. * @param $provider - * The language provider to be invoked. If not passed it will be explicitly - * loaded through language_negotiation_info(). + * (optional) An associative array of information about the provider to be + * invoked (see hook_language_negotiation_info() for details). If not passed + * in, it will be loaded through language_negotiation_info(). * * @return - * The language provider's return value. + * A language object representing the language chosen by the provider. */ function language_provider_invoke($provider_id, $provider = NULL) { $results = &drupal_static(__FUNCTION__); @@ -352,25 +444,26 @@ function language_provider_invoke($provider_id, $provider = NULL) { require_once DRUPAL_ROOT . '/' . $provider['file']; } - // If the language provider has no cache preference or this is satisfied - // we can execute the callback. + // If the language negotiation provider has no cache preference or this is + // satisfied we can execute the callback. $cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0); $callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE; $langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE; $results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE; } - // Since objects are resources we need to return a clone to prevent the - // provider cache to be unintentionally altered. The same providers might be - // used with different language types based on configuration. + // Since objects are resources, we need to return a clone to prevent the + // language negotiation provider cache from being unintentionally altered. The + // same providers might be used with different language types based on + // configuration. return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id]; } /** - * Return the passed language provider weight or a default value. + * Returns the passed language negotiation provider weight or a default value. * * @param $provider - * A language provider data structure. + * A language negotiation provider data structure. * * @return * A numeric weight. @@ -381,16 +474,16 @@ function language_provider_weight($provider) { } /** - * Choose a language for the given type based on language negotiation settings. + * Chooses a language based on language negotiation provider settings. * * @param $type - * The language type. + * The language type key to find the language for. * * @return * The negotiated language object. */ function language_initialize($type) { - // Execute the language providers in the order they were set up and return the + // Execute the language negotiation providers in the order they were set up and return the // first valid language found. $negotiation = variable_get("language_negotiation_$type", array()); @@ -409,7 +502,7 @@ function language_initialize($type) { } /** - * Default language provider. + * Returns the default language negotiation provider. * * @return * The default language code. @@ -421,8 +514,8 @@ function language_from_default() { /** * Splits the given path into prefix and actual path. * - * Parse the given path and return the language object identified by the - * prefix and the actual path. + * Parse the given path and return the language object identified by the prefix + * and the actual path. * * @param $path * The path to split. @@ -482,3 +575,7 @@ function language_fallback_get_candidates($type = LANGUAGE_TYPE_CONTENT) { return $fallback_candidates; } + +/** + * @} End of "language_negotiation" + */ diff --git a/modules/system/language.api.php b/modules/system/language.api.php index 671479309be0a8e90643e2b337f5cbacf03132e6..d868b6fef30a68b293e4192765701213a1bc0684 100644 --- a/modules/system/language.api.php +++ b/modules/system/language.api.php @@ -62,16 +62,22 @@ function hook_language_switch_links_alter(array &$links, $type, $path) { } /** - * Allow modules to define their own language types. + * Define language types. * * @return - * An array of language type definitions. Each language type has an identifier - * key. The language type definition is an associative array that may contain - * the following key-value pairs: - * - "name": The human-readable language type identifier. - * - "description": A description of the language type. - * - "fixed": An array of language provider identifiers. Defining this key - * makes the language type non-configurable. + * An associative array of language type definitions. The keys are the + * identifiers, which are also used as names for global variables representing + * the types in the bootstrap phase. The values are associative arrays that + * may contain the following elements: + * - name: The human-readable language type identifier. + * - description: A description of the language type. + * - fixed: A fixed array of language negotiation provider identifiers to use + * to initialize this language. Defining this key makes the language type + * non-configurable, so it will always use the specified providers in the + * given priority order. Omit to make the language type configurable. + * + * @see hook_language_types_info_alter() + * @ingroup language_negotiation */ function hook_language_types_info() { return array( @@ -90,6 +96,9 @@ function hook_language_types_info() { * * @param $language_types * Array of language type definitions. + * + * @see hook_language_types_info() + * @ingroup language_negotiation */ function hook_language_types_info_alter(array &$language_types) { if (isset($language_types['custom_language_type'])) { @@ -98,31 +107,35 @@ function hook_language_types_info_alter(array &$language_types) { } /** - * Allow modules to define their own language providers. + * Define language negotiation providers. * * @return - * An array of language provider definitions. Each language provider has an - * identifier key. The language provider definition is an associative array - * that may contain the following key-value pairs: - * - "types": An array of allowed language types. If a language provider does - * not specify which language types it should be used with, it will be - * available for all the configurable language types. - * - "callbacks": An array of functions that will be called to perform various - * tasks. Possible key-value pairs are: - * - "language": Required. The callback that will determine the language - * value. - * - "switcher": The callback that will determine the language switch links - * associated to the current language provider. - * - "url_rewrite": The callback that will provide URL rewriting. - * - "file": A file that will be included before the callback is invoked; this - * allows callback functions to be in separate files. - * - "weight": The default weight the language provider has. - * - "name": A human-readable identifier. - * - "description": A description of the language provider. - * - "config": An internal path pointing to the language provider - * configuration page. - * - "cache": The value Drupal's page cache should be set to for the current - * language provider to be invoked. + * An associative array of language negotiation provider definitions. The keys + * are provider identifiers, and the values are associative arrays definining + * each provider, with the following elements: + * - types: An array of allowed language types. If a language negotiation + * provider does not specify which language types it should be used with, it + * will be available for all the configurable language types. + * - callbacks: An associative array of functions that will be called to + * perform various tasks. Possible elements are: + * - negotiation: (required) Name of the callback function that determines + * the language value. + * - language_switch: (optional) Name of the callback function that + * determines links for a language switcher block associated with this + * provider. See language_switcher_url() for an example. + * - url_rewrite: (optional) Name of the callback function that provides URL + * rewriting, if needed by this provider. + * - file: The file where callback functions are defined (this file will be + * included before the callbacks are invoked). + * - weight: The default weight of the provider. + * - name: The translated human-readable name for the provider. + * - description: A translated longer description of the provider. + * - config: An internal path pointing to the provider's configuration page. + * - cache: The value Drupal's page cache should be set to for the current + * provider to be invoked. + * + * @see hook_language_negotiation_info_alter() + * @ingroup language_negotiation */ function hook_language_negotiation_info() { return array( @@ -135,18 +148,21 @@ function hook_language_negotiation_info() { 'file' => drupal_get_path('module', 'custom') . '/custom.module', 'weight' => -4, 'types' => array('custom_language_type'), - 'name' => t('Custom language provider'), - 'description' => t('This is a custom language provider.'), + 'name' => t('Custom language negotiation provider'), + 'description' => t('This is a custom language negotiation provider.'), 'cache' => 0, ), ); } /** - * Perform alterations on language providers. + * Perform alterations on language negoiation providers. * * @param $language_providers - * Array of language provider definitions. + * Array of language negotiation provider definitions. + * + * @see hook_language_negotiation_info() + * @ingroup language_negotiation */ function hook_language_negotiation_info_alter(array &$language_providers) { if (isset($language_providers['custom_language_provider'])) {