diff --git a/includes/language.inc b/includes/language.inc index 20909f5..c5590ca 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,6 +13,95 @@ define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default'); /** + * @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 + */ + +/** * Return all the defined language types. * * @return @@ -33,8 +124,8 @@ function language_types_info() { * Return 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 @@ -122,7 +213,7 @@ function language_types_set() { } /** - * Check if a language provider is enabled. + * Check 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. @@ -240,7 +331,7 @@ function language_negotiation_purge() { * @param $type * The language negotiation type. * @param $language_providers - * An array of language provider weights keyed by id. + * An array of language provider weights keyed by provider ID. * @see language_provider_weight() */ function language_negotiation_set($type, $language_providers) { @@ -266,7 +357,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) { @@ -314,13 +405,14 @@ function language_negotiation_info() { * Helper function used to cache the language 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 method. */ function language_provider_invoke($provider_id, $provider = NULL) { $results = &drupal_static(__FUNCTION__); @@ -349,9 +441,10 @@ function language_provider_invoke($provider_id, $provider = NULL) { $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 method cache from being unintentionally altered. The + // same methods might be used with different language types based on + // configuration. return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id]; } @@ -370,10 +463,10 @@ 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. @@ -410,8 +503,8 @@ function language_from_default() { /** * Split 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. @@ -471,3 +564,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 6714793..0ded9cb 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 method identifiers to use to + * initialize this language. Defining this key makes the language type + * non-configurable, so it will always use the specified methods 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 methods. * * @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 + * An associative array of language negotiation method definitions. The keys + * are method identifiers, and the values are associative arrays definining + * each method, with the following elements: + * - types: An array of allowed language types. If a language negotiation * 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. + * - 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 + * method. See language_switcher_url() for an example. + * - url_rewrite: (optional) Name of the callback function that provides URL + * rewriting, if needed by this method. + * - file: The file where callback functions are defined (this file will be + * included before the callbacks are invoked). + * - weight: The default weight of the method. + * - name: The translated human-readable name for the method. + * - description: A translated longer description of the method. + * - config: An internal path pointing to the method's configuration page. + * - cache: The value Drupal's page cache should be set to for the current + * method to be invoked. + * + * @see hook_language_negotiation_info_alter() + * @ingroup language_negotiation */ function hook_language_negotiation_info() { return array( @@ -147,6 +160,9 @@ function hook_language_negotiation_info() { * * @param $language_providers * Array of language 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'])) {