Drupal PHP Cross Reference Content Management Systems

Source: /includes/language.inc - 484 lines - 14494 bytes - Summary - Text - Print

   1  <?php
   2  
   3  /**
   4   * @file
   5   * Multiple language handling functionality.
   6   */
   7  
   8  /**
   9   * No language negotiation. The default language is used.
  10   */
  11  define('LANGUAGE_NEGOTIATION_DEFAULT', 'language-default');
  12  
  13  /**
  14   * Return all the defined language types.
  15   *
  16   * @return
  17   *   An array of language type names. The name will be used as the global
  18   *   variable name the language value will be stored in.
  19   */
  20  function language_types_info() {
  21    $language_types = &drupal_static(__FUNCTION__);
  22  
  23    if (!isset($language_types)) {
  24      $language_types = module_invoke_all('language_types_info');
  25      // Let other modules alter the list of language types.
  26      drupal_alter('language_types_info', $language_types);
  27    }
  28  
  29    return $language_types;
  30  }
  31  
  32  /**
  33   * Return only the configurable language types.
  34   *
  35   * A language type maybe configurable or fixed. A fixed language type is a type
  36   * whose negotiation values are unchangeable and defined while defining the
  37   * language type itself.
  38   *
  39   * @param $stored
  40   *   Optional. By default retrieves values from the 'language_types' variable to
  41   *   avoid unnecessary hook invocations.
  42   *   If set to FALSE retrieves values from the actual language type definitions.
  43   *   This allows to react to alterations performed on the definitions by modules
  44   *   installed after the 'language_types' variable is set.
  45   *
  46   * @return
  47   *   An array of language type names.
  48   */
  49  function language_types_configurable($stored = TRUE) {
  50    $configurable = &drupal_static(__FUNCTION__);
  51  
  52    if ($stored && !isset($configurable)) {
  53      $types = variable_get('language_types', drupal_language_types());
  54      $configurable = array_keys(array_filter($types));
  55    }
  56  
  57    if (!$stored) {
  58      $result = array();
  59      foreach (language_types_info() as $type => $info) {
  60        if (!isset($info['fixed'])) {
  61          $result[] = $type;
  62        }
  63      }
  64      return $result;
  65    }
  66  
  67    return $configurable;
  68  }
  69  
  70  /**
  71   * Disable the given language types.
  72   *
  73   * @param $types
  74   *   An array of language types.
  75   */
  76  function language_types_disable($types) {
  77    $enabled_types = variable_get('language_types', drupal_language_types());
  78  
  79    foreach ($types as $type) {
  80      unset($enabled_types[$type]);
  81    }
  82  
  83    variable_set('language_types', $enabled_types);
  84  }
  85  
  86  /**
  87   * Updates the language type configuration.
  88   */
  89  function language_types_set() {
  90    // Ensure that we are getting the defined language negotiation information. An
  91    // invocation of module_enable() or module_disable() could outdate the cached
  92    // information.
  93    drupal_static_reset('language_types_info');
  94    drupal_static_reset('language_negotiation_info');
  95  
  96    // Determine which language types are configurable and which not by checking
  97    // whether the 'fixed' key is defined. Non-configurable (fixed) language types
  98    // have their language negotiation settings stored there.
  99    $defined_providers = language_negotiation_info();
 100    foreach (language_types_info() as $type => $info) {
 101      if (isset($info['fixed'])) {
 102        $language_types[$type] = FALSE;
 103        $negotiation = array();
 104        foreach ($info['fixed'] as $weight => $id) {
 105          if (isset($defined_providers[$id])) {
 106            $negotiation[$id] = $weight;
 107          }
 108        }
 109        language_negotiation_set($type, $negotiation);
 110      }
 111      else {
 112        $language_types[$type] = TRUE;
 113      }
 114    }
 115  
 116    // Save language types.
 117    variable_set('language_types', $language_types);
 118  
 119    // Ensure that subsequent calls of language_types_configurable() return the
 120    // updated language type information.
 121    drupal_static_reset('language_types_configurable');
 122  }
 123  
 124  /**
 125   * Check if a language provider is enabled.
 126   *
 127   * This has two possible behaviors:
 128   *  - If $provider_id is given return its ID if enabled, FALSE otherwise.
 129   *  - If no ID is passed the first enabled language provider is returned.
 130   *
 131   * @param $type
 132   *   The language negotiation type.
 133   * @param $provider_id
 134   *   The language provider ID.
 135   *
 136   * @return
 137   *   The provider ID if it is enabled, FALSE otherwise.
 138   */
 139  function language_negotiation_get($type, $provider_id = NULL) {
 140    $negotiation = variable_get("language_negotiation_$type", array());
 141  
 142    if (empty($negotiation)) {
 143      return empty($provider_id) ? LANGUAGE_NEGOTIATION_DEFAULT : FALSE;
 144    }
 145  
 146    if (empty($provider_id)) {
 147      return key($negotiation);
 148    }
 149  
 150    if (isset($negotiation[$provider_id])) {
 151      return $provider_id;
 152    }
 153  
 154    return FALSE;
 155  }
 156  
 157  /**
 158   * Check if the given language provider is enabled for any configurable language
 159   * type.
 160   *
 161   * @param $provider_id
 162   *   The language provider ID.
 163   *
 164   * @return
 165   *   TRUE if there is at least one language type for which the give language
 166   *   provider is enabled, FALSE otherwise.
 167   */
 168  function language_negotiation_get_any($provider_id) {
 169    foreach (language_types_configurable() as $type) {
 170      if (language_negotiation_get($type, $provider_id)) {
 171        return TRUE;
 172      }
 173    }
 174  
 175    return FALSE;
 176  }
 177  
 178  /**
 179   * Return the language switch links for the given language.
 180   *
 181   * @param $type
 182   *   The language negotiation type.
 183   * @param $path
 184   *   The internal path the switch links will be relative to.
 185   *
 186   * @return
 187   *   A keyed array of links ready to be themed.
 188   */
 189  function language_negotiation_get_switch_links($type, $path) {
 190    $links = FALSE;
 191    $negotiation = variable_get("language_negotiation_$type", array());
 192  
 193    // Only get the languages if we have more than one.
 194    if (count(language_list()) >= 2) {
 195      $language = language_initialize($type);
 196    }
 197  
 198    foreach ($negotiation as $id => $provider) {
 199      if (isset($provider['callbacks']['switcher'])) {
 200        if (isset($provider['file'])) {
 201          require_once DRUPAL_ROOT . '/' . $provider['file'];
 202        }
 203  
 204        $callback = $provider['callbacks']['switcher'];
 205        $result = $callback($type, $path);
 206  
 207        // Add support for WCAG 2.0's Language of Parts to add language identifiers.
 208        // http://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html
 209        foreach ($result as $langcode => $link) {
 210          $result[$langcode]['attributes']['lang'] = $langcode;
 211        }
 212  
 213        if (!empty($result)) {
 214          // Allow modules to provide translations for specific links.
 215          drupal_alter('language_switch_links', $result, $type, $path);
 216          $links = (object) array('links' => $result, 'provider' => $id);
 217          break;
 218        }
 219      }
 220    }
 221  
 222    return $links;
 223  }
 224  
 225  /**
 226   * Updates language configuration to remove any language provider that is no longer defined.
 227   */
 228  function language_negotiation_purge() {
 229    // Ensure that we are getting the defined language negotiation information. An
 230    // invocation of module_enable() or module_disable() could outdate the cached
 231    // information.
 232    drupal_static_reset('language_negotiation_info');
 233    drupal_static_reset('language_types_info');
 234  
 235    $defined_providers = language_negotiation_info();
 236    foreach (language_types_info() as $type => $type_info) {
 237      $weight = 0;
 238      $negotiation = array();
 239      foreach (variable_get("language_negotiation_$type", array()) as $id => $provider) {
 240        if (isset($defined_providers[$id])) {
 241          $negotiation[$id] = $weight++;
 242        }
 243      }
 244      language_negotiation_set($type, $negotiation);
 245    }
 246  }
 247  
 248  /**
 249   * Save a list of language providers.
 250   *
 251   * @param $type
 252   *   The language negotiation type.
 253   * @param $language_providers
 254   *   An array of language provider weights keyed by id.
 255   *   @see language_provider_weight()
 256   */
 257  function language_negotiation_set($type, $language_providers) {
 258    // Save only the necessary fields.
 259    $provider_fields = array('callbacks', 'file', 'cache');
 260  
 261    $negotiation = array();
 262    $providers_weight = array();
 263    $defined_providers = language_negotiation_info();
 264    $default_types = language_types_configurable(FALSE);
 265  
 266    // Initialize the providers weight list.
 267    foreach ($language_providers as $id => $provider) {
 268      $providers_weight[$id] = language_provider_weight($provider);
 269    }
 270  
 271    // Order providers list by weight.
 272    asort($providers_weight);
 273  
 274    foreach ($providers_weight as $id => $weight) {
 275      if (isset($defined_providers[$id])) {
 276        $provider = $defined_providers[$id];
 277        // If the provider does not express any preference about types, make it
 278        // available for any configurable type.
 279        $types = array_flip(isset($provider['types']) ? $provider['types'] : $default_types);
 280        // Check if the provider is defined and has the right type.
 281        if (isset($types[$type])) {
 282          $provider_data = array();
 283          foreach ($provider_fields as $field) {
 284            if (isset($provider[$field])) {
 285              $provider_data[$field] = $provider[$field];
 286            }
 287          }
 288          $negotiation[$id] = $provider_data;
 289        }
 290      }
 291    }
 292  
 293    variable_set("language_negotiation_$type", $negotiation);
 294  }
 295  
 296  /**
 297   * Return all the defined language providers.
 298   *
 299   * @return
 300   *   An array of language providers.
 301   */
 302  function language_negotiation_info() {
 303    $language_providers = &drupal_static(__FUNCTION__);
 304  
 305    if (!isset($language_providers)) {
 306      // Collect all the module-defined language negotiation providers.
 307      $language_providers = module_invoke_all('language_negotiation_info');
 308  
 309      // Add the default language provider.
 310      $language_providers[LANGUAGE_NEGOTIATION_DEFAULT] = array(
 311        'callbacks' => array('language' => 'language_from_default'),
 312        'weight' => 10,
 313        'name' => t('Default'),
 314        'description' => t('Use the default site language (@language_name).', array('@language_name' => language_default()->native)),
 315      );
 316  
 317      // Let other modules alter the list of language providers.
 318      drupal_alter('language_negotiation_info', $language_providers);
 319    }
 320  
 321    return $language_providers;
 322  }
 323  
 324  /**
 325   * Helper function used to cache the language providers results.
 326   *
 327   * @param $provider_id
 328   *   The language provider ID.
 329   * @param $provider
 330   *   The language provider to be invoked. If not passed it will be explicitly
 331   *   loaded through language_negotiation_info().
 332   *
 333   * @return
 334   *   The language provider's return value.
 335   */
 336  function language_provider_invoke($provider_id, $provider = NULL) {
 337    $results = &drupal_static(__FUNCTION__);
 338  
 339    if (!isset($results[$provider_id])) {
 340      global $user;
 341  
 342      // Get languages grouped by status and select only the enabled ones.
 343      $languages = language_list('enabled');
 344      $languages = $languages[1];
 345  
 346      if (!isset($provider)) {
 347        $providers = language_negotiation_info();
 348        $provider = $providers[$provider_id];
 349      }
 350  
 351      if (isset($provider['file'])) {
 352        require_once DRUPAL_ROOT . '/' . $provider['file'];
 353      }
 354  
 355      // If the language provider has no cache preference or this is satisfied
 356      // we can execute the callback.
 357      $cache = !isset($provider['cache']) || $user->uid || $provider['cache'] == variable_get('cache', 0);
 358      $callback = isset($provider['callbacks']['language']) ? $provider['callbacks']['language'] : FALSE;
 359      $langcode = $cache && function_exists($callback) ? $callback($languages) : FALSE;
 360      $results[$provider_id] = isset($languages[$langcode]) ? $languages[$langcode] : FALSE;
 361    }
 362  
 363    // Since objects are resources we need to return a clone to prevent the
 364    // provider cache to be unintentionally altered. The same providers might be
 365    // used with different language types based on configuration.
 366    return !empty($results[$provider_id]) ? clone($results[$provider_id]) : $results[$provider_id];
 367  }
 368  
 369  /**
 370   * Return the passed language provider weight or a default value.
 371   *
 372   * @param $provider
 373   *   A language provider data structure.
 374   *
 375   * @return
 376   *   A numeric weight.
 377   */
 378  function language_provider_weight($provider) {
 379    $default = is_numeric($provider) ? $provider : 0;
 380    return isset($provider['weight']) && is_numeric($provider['weight']) ? $provider['weight'] : $default;
 381  }
 382  
 383  /**
 384   * Choose a language for the given type based on language negotiation settings.
 385   *
 386   * @param $type
 387   *   The language type.
 388   *
 389   * @return
 390   *   The negotiated language object.
 391   */
 392  function language_initialize($type) {
 393    // Execute the language providers in the order they were set up and return the
 394    // first valid language found.
 395    $negotiation = variable_get("language_negotiation_$type", array());
 396  
 397    foreach ($negotiation as $provider_id => $provider) {
 398      $language = language_provider_invoke($provider_id, $provider);
 399      if ($language) {
 400        $language->provider = $provider_id;
 401        return $language;
 402      }
 403    }
 404  
 405    // If no other language was found use the default one.
 406    $language = language_default();
 407    $language->provider = LANGUAGE_NEGOTIATION_DEFAULT;
 408    return $language;
 409  }
 410  
 411  /**
 412   * Default language provider.
 413   *
 414   * @return
 415   *   The default language code.
 416   */
 417  function language_from_default() {
 418    return language_default()->language;
 419  }
 420  
 421  /**
 422   * Splits the given path into prefix and actual path.
 423   *
 424   * Parse the given path and return the language object identified by the
 425   * prefix and the actual path.
 426   *
 427   * @param $path
 428   *   The path to split.
 429   * @param $languages
 430   *   An array of valid languages.
 431   *
 432   * @return
 433   *   An array composed of:
 434   *    - A language object corresponding to the identified prefix on success,
 435   *      FALSE otherwise.
 436   *    - The path without the prefix on success, the given path otherwise.
 437   */
 438  function language_url_split_prefix($path, $languages) {
 439    $args = empty($path) ? array() : explode('/', $path);
 440    $prefix = array_shift($args);
 441  
 442    // Search prefix within enabled languages.
 443    foreach ($languages as $language) {
 444      if (!empty($language->prefix) && $language->prefix == $prefix) {
 445        // Rebuild $path with the language removed.
 446        return array($language, implode('/', $args));
 447      }
 448    }
 449  
 450    return array(FALSE, $path);
 451  }
 452  
 453  /**
 454   * Returns the possible fallback languages ordered by language weight.
 455   *
 456   * @param
 457   *   (optional) The language type. Defaults to LANGUAGE_TYPE_CONTENT.
 458   *
 459   * @return
 460   *   An array of language codes.
 461   */
 462  function language_fallback_get_candidates($type = LANGUAGE_TYPE_CONTENT) {
 463    $fallback_candidates = &drupal_static(__FUNCTION__);
 464  
 465    if (!isset($fallback_candidates)) {
 466      $fallback_candidates = array();
 467  
 468      // Get languages ordered by weight.
 469      // Use array keys to avoid duplicated entries.
 470      foreach (language_list('weight') as $languages) {
 471        foreach ($languages as $language) {
 472          $fallback_candidates[$language->language] = NULL;
 473        }
 474      }
 475  
 476      $fallback_candidates = array_keys($fallback_candidates);
 477      $fallback_candidates[] = LANGUAGE_NONE;
 478  
 479      // Let other modules hook in and add/change candidates.
 480      drupal_alter('language_fallback_candidates', $fallback_candidates);
 481    }
 482  
 483    return $fallback_candidates;
 484  }

title

Description

title

Description

title

Description

title

title

Body