Code coverage for /20080809/modules/locale/locale.module

Line #Times calledCode
1
<?php
2
// $Id: locale.module,v 1.220 2008/07/24 16:25:18 dries Exp $
3
4
/**
5
 * @file
6
 *   Add language handling functionality and enables the translation of
the
7
 *   user interface to languages other than English.
8
 *
9
 *   When enabled, multiple languages can be set up. The site interface
10
 *   can be displayed in different languages, as well as nodes can have
languages
11
 *   assigned. The setup of languages and translations is completely web
based.
12
 *   Gettext portable object files are supported.
13
 */
14
15
/**
16
 * Language written left to right. Possible value of $language->direction.
17
 */
1882
define('LANGUAGE_LTR', 0);
19
20
/**
21
 * Language written right to left. Possible value of $language->direction.
22
 */
2382
define('LANGUAGE_RTL', 1);
24
25
26
//
---------------------------------------------------------------------------------
27
// Hook implementations
28
29
/**
30
 * Implementation of hook_help().
31
 */
3282
function locale_help($path, $arg) {
33
  switch ($path) {
3458
    case 'admin/help#locale':
351
      $output = '<p>' . t('The locale module allows your Drupal site to be
presented in languages other than the default English, a defining feature
of multi-lingual websites. The locale module works by examining text as it
is about to be displayed: when a translation of the text is available in
the language to be displayed, the translation is displayed rather than the
original text. When a translation is unavailable, the original text is
displayed, and then stored for later review by a translator.') . '</p>';
361
      $output .= '<p>' . t('Beyond translation of the Drupal interface, the
locale module provides a feature set tailored to the needs of a
multi-lingual site. Language negotiation allows your site to automatically
change language based on the domain or path used for each request. Users
may (optionally) select their preferred language on their <em>My
account</em> page, and your site can be configured to honor a web
browser\'s preferred language settings. Your site content can be created in
(and translated to) any enabled language, and each post may have a
language-appropriate alias for each of its translations. The locale module
works in concert with the <a href="@content-help">content translation
module</a> to manage translated content.', array('@content-help' =>
url('admin/help/translation'))) . '</p>';
371
      $output .= '<p>' . t('Translations may be provided by:') . '</p>';
381
      $output .= '<ul><li>' . t("translating the original text via the
locale module's integrated web interface, or") . '</li>';
391
      $output .= '<li>' . t('importing files from a set of existing
translations, known as a translation package. A translation package enables
the display of a specific version of Drupal in a specific language, and
contain files in the Gettext Portable Object (<em>.po</em>) format.
Although not all languages are available for every version of Drupal,
translation packages for many languages are available for download from the
<a href="@translations">Drupal translation page</a>.',
array('@translations' => 'http://drupal.org/project/translations')) .
'</li></ul>';
401
      $output .= '<p>' . t('If an existing translation package does not
meet your needs, the Gettext Portable Object (<em>.po</em>) files within a
package may be modified, or new <em>.po</em> files may be created, using a
desktop Gettext editor. The locale module\'s <a href="@import">import</a>
feature allows the translated strings from a new or modified <em>.po</em>
file to be added to your site. The locale module\'s <a
href="@export">export</a> feature generates files from your site\'s
translated strings, that can either be shared with others or edited offline
by a Gettext translation editor.', array('@import' =>
url('admin/build/translate/import'), '@export' =>
url('admin/build/translate/export'))) . '</p>';
411
      $output .= '<p>' . t('For more information, see the online handbook
entry for <a href="@locale">Locale module</a>.', array('@locale' =>
'http://drupal.org/handbook/modules/locale/')) . '</p>';
421
      return $output;
4358
    case 'admin/settings/language':
446
      $output = '<p>' . t("This page provides an overview of your site's
enabled languages. If multiple languages are available and enabled, the
text on your site interface may be translated, registered users may select
their preferred language on the <em>My account</em> page, and site authors
may indicate a specific language when creating posts. The site's default
language is used for anonymous visitors and for users who have not selected
a preferred language.") . '</p>';
456
      $output .= '<p>' . t('For each language available on the site, use
the <em>edit</em> link to configure language details, including name, an
optional language-specific path or domain, and whether the language is
natively presented either left-to-right or right-to-left. These languages
also appear in the <em>Language</em> selection when creating a post of a
content type with multilingual support.') . '</p>';
466
      $output .= '<p>' . t('Use the <a href="@add-language">add language
page</a> to enable additional languages (and automatically import files
from a translation package, if available), the <a href="@search">translate
interface page</a> to locate strings for manual translation, or the <a
href="@import">import page</a> to add translations from individual
<em>.po</em> files. A number of contributed translation packages containing
<em>.po</em> files are available on the <a href="@translations">Drupal.org
translations page</a>.', array('@add-language' =>
url('admin/settings/language/add'), '@search' =>
url('admin/build/translate/search'), '@import' =>
url('admin/build/translate/import'), '@translations' =>
'http://drupal.org/project/translations')) . '</p>';
476
      return $output;
4858
    case 'admin/settings/language/add':
492
      return '<p>' . t('Add all languages to be supported by your site. If
your desired language is not available in the <em>Language name</em>
drop-down, click <em>Custom language</em> and provide a language code and
other details manually. When providing a language code manually, be sure to
enter a standardized language code, since this code may be used by browsers
to determine an appropriate display language.') . '</p>';
5058
    case 'admin/settings/language/configure':
510
      $output = '<p>' . t("Language negotiation settings determine the
site's presentation language. Available options include:") . '</p>';
520
      $output .= '<ul><li>' . t('<strong>None.</strong> The default
language is used for site presentation, though users may (optionally)
select a preferred language on the <em>My Account</em> page. (User language
preferences will be used for site e-mails, if available.)') . '</li>';
530
      $output .= '<li>' . t('<strong>Path prefix only.</strong> The
presentation language is determined by examining the path for a language
code or other custom string that matches the path prefix (if any) specified
for each language. If a suitable prefix is not identified, the default
language is used. <em>Example: "example.com/de/contact" sets presentation
language to German based on the use of "de" within the path.</em>') .
'</li>';
540
      $output .= '<li>' . t("<strong>Path prefix with language
fallback.</strong> The presentation language is determined by examining the
path for a language code or other custom string that matches the path
prefix (if any) specified for each language. If a suitable prefix is not
identified, the display language is determined by the user's language
preferences from the <em>My Account</em> page, or by the browser's language
settings. If a presentation language cannot be determined, the default
language is used.") . '</t>';
550
      $output .= '<li>' . t('<strong>Domain name only.</strong> The
presentation language is determined by examining the domain used to access
the site, and comparing it to the language domain (if any) specified for
each language. If a match is not identified, the default language is used.
<em>Example: "http://de.example.com/contact" sets presentation language to
German based on the use of "http://de.example.com" in the domain.</em>') .
'</li></ul>';
560
      $output .= '<p>' . t('The path prefix or domain name for a language
may be set by editing the <a href="@languages">available languages</a>. In
the absence of an appropriate match, the site is displayed in the <a
href="@languages">default language</a>.', array('@languages' =>
url('admin/settings/language'))) . '</p>';
570
      return $output;
5858
    case 'admin/build/translate':
590
      $output = '<p>' . t('This page provides an overview of available
translatable strings. Drupal displays translatable strings in text groups;
modules may define additional text groups containing other translatable
strings. Because text groups provide a method of grouping related strings,
they are often used to focus translation efforts on specific areas of the
Drupal interface.') . '</p>';
600
      $output .= '<p>' . t('Review the <a href="@languages">languages
page</a> for more information on adding support for additional languages.',
array('@languages' => url('admin/settings/language'))) . '</p>';
610
      return $output;
6258
    case 'admin/build/translate/import':
630
      $output = '<p>' . t('This page imports the translated strings
contained in an individual Gettext Portable Object (<em>.po</em>) file.
Normally distributed as part of a translation package (each translation
package may contain several <em>.po</em> files), a <em>.po</em> file may
need to be imported after offline editing in a Gettext translation editor.
Importing an individual <em>.po</em> file may be a lengthy process.') .
'</p>';
640
      $output .= '<p>' . t('Note that the <em>.po</em> files within a
translation package are imported automatically (if available) when new
modules or themes are enabled, or as new languages are added. Since this
page only allows the import of one <em>.po</em> file at a time, it may be
simpler to download and extract a translation package into your Drupal
installation directory and <a href="@language-add">add the language</a>
(which automatically imports all <em>.po</em> files within the package).
Translation packages are available for download on the <a
href="@translations">Drupal translation page</a>.', array('@language-add'
=> url('admin/settings/language/add'), '@translations' =>
'http://drupal.org/project/translations')) . '</p>';
650
      return $output;
6658
    case 'admin/build/translate/export':
670
      return '<p>' . t('This page exports the translated strings used by
your site. An export file may be in Gettext Portable Object (<em>.po</em>)
form, which includes both the original string and the translation (used to
share translations with others), or in Gettext Portable Object Template
(<em>.pot</em>) form, which includes the original strings only (used to
create new translations with a Gettext translation editor).') . '</p>';
6858
    case 'admin/build/translate/search':
698
      return '<p>' . t('This page allows a translator to search for
specific translated and untranslated strings, and is used when creating or
editing translations. (Note: For translation tasks involving many strings,
it may be more convenient to <a href="@export">export</a> strings for
offline editing in a desktop Gettext translation editor.) Searches may be
limited to strings found within a specific text group or in a specific
language.', array('@export' => url('admin/build/translate/export'))) .
'</p>';
7058
    case 'admin/build/block/configure':
710
      if ($arg[4] == 'locale' && $arg[5] == 0) {
720
        return '<p>' . t('This block is only shown if <a
href="@languages">at least two languages are enabled</a> and <a
href="@configuration">language negotiation</a> is set to something other
than <em>None</em>.', array('@languages' => url('admin/settings/language'),
'@configuration' => url('admin/settings/language/configure'))) . '</p>';
730
      }
740
      break;
750
  }
7658
}
77
78
/**
79
 * Implementation of hook_menu().
80
 *
81
 * Locale module only provides administrative menu items, so all
82
 * menu items are invoked through locale_inc_callback().
83
 */
8482
function locale_menu() {
85
  // Manage languages
864
  $items['admin/settings/language'] = array(
874
    'title' => 'Languages',
884
    'description' => 'Configure languages for content and the user
interface.',
894
    'page callback' => 'locale_inc_callback',
904
    'page arguments' => array('drupal_get_form',
'locale_languages_overview_form'),
914
    'access arguments' => array('administer languages'),
92
  );
934
  $items['admin/settings/language/overview'] = array(
944
    'title' => 'List',
954
    'weight' => 0,
964
    'type' => MENU_DEFAULT_LOCAL_TASK,
97
  );
984
  $items['admin/settings/language/add'] = array(
994
    'title' => 'Add language',
1004
    'page callback' => 'locale_inc_callback',
1014
    'page arguments' => array('locale_languages_add_screen'), // two forms
concatenated
1024
    'access arguments' => array('administer languages'),
1034
    'weight' => 5,
1044
    'type' => MENU_LOCAL_TASK,
105
  );
1064
  $items['admin/settings/language/configure'] = array(
1074
    'title' => 'Configure',
1084
    'page callback' => 'locale_inc_callback',
1094
    'page arguments' => array('drupal_get_form',
'locale_languages_configure_form'),
1104
    'access arguments' => array('administer languages'),
1114
    'weight' => 10,
1124
    'type' => MENU_LOCAL_TASK,
113
  );
1144
  $items['admin/settings/language/edit/%'] = array(
1154
    'title' => 'Edit language',
1164
    'page callback' => 'locale_inc_callback',
1174
    'page arguments' => array('drupal_get_form',
'locale_languages_edit_form', 4),
1184
    'access arguments' => array('administer languages'),
1194
    'type' => MENU_CALLBACK,
120
  );
1214
  $items['admin/settings/language/delete/%'] = array(
1224
    'title' => 'Confirm',
1234
    'page callback' => 'locale_inc_callback',
1244
    'page arguments' => array('drupal_get_form',
'locale_languages_delete_form', 4),
1254
    'access arguments' => array('administer languages'),
1264
    'type' => MENU_CALLBACK,
127
  );
128
129
  // Translation functionality
1304
  $items['admin/build/translate'] = array(
1314
    'title' => 'Translate interface',
1324
    'description' => 'Translate the built in interface and optionally other
text.',
1334
    'page callback' => 'locale_inc_callback',
1344
    'page arguments' => array('locale_translate_overview_screen'), // not a
form, just a table
1354
    'access arguments' => array('translate interface'),
136
  );
1374
  $items['admin/build/translate/overview'] = array(
1384
    'title' => 'Overview',
1394
    'weight' => 0,
1404
    'type' => MENU_DEFAULT_LOCAL_TASK,
141
  );
1424
  $items['admin/build/translate/search'] = array(
1434
    'title' => 'Search',
1444
    'weight' => 10,
1454
    'type' => MENU_LOCAL_TASK,
1464
    'page callback' => 'locale_inc_callback',
1474
    'page arguments' => array('locale_translate_seek_screen'), // search
results and form concatenated
1484
    'access arguments' => array('translate interface'),
149
  );
1504
  $items['admin/build/translate/import'] = array(
1514
    'title' => 'Import',
1524
    'page callback' => 'locale_inc_callback',
1534
    'page arguments' => array('drupal_get_form',
'locale_translate_import_form'),
1544
    'access arguments' => array('translate interface'),
1554
    'weight' => 20,
1564
    'type' => MENU_LOCAL_TASK,
157
  );
1584
  $items['admin/build/translate/export'] = array(
1594
    'title' => 'Export',
1604
    'page callback' => 'locale_inc_callback',
1614
    'page arguments' => array('locale_translate_export_screen'), //
possibly multiple forms concatenated
1624
    'access arguments' => array('translate interface'),
1634
    'weight' => 30,
1644
    'type' => MENU_LOCAL_TASK,
165
  );
1664
  $items['admin/build/translate/edit/%'] = array(
1674
    'title' => 'Edit string',
1684
    'page callback' => 'locale_inc_callback',
1694
    'page arguments' => array('drupal_get_form',
'locale_translate_edit_form', 4),
1704
    'access arguments' => array('translate interface'),
1714
    'type' => MENU_CALLBACK,
172
  );
1734
  $items['admin/build/translate/delete/%'] = array(
1744
    'title' => 'Delete string',
1754
    'page callback' => 'locale_inc_callback',
1764
    'page arguments' => array('locale_translate_delete_page', 4),
1774
    'access arguments' => array('translate interface'),
1784
    'type' => MENU_CALLBACK,
179
  );
180
1814
  return $items;
1820
}
183
184
/**
185
 * Wrapper function to be able to set callbacks in locale.inc
186
 */
18782
function locale_inc_callback() {
18829
  $args = func_get_args();
18929
  $function = array_shift($args);
19029
  include_once './includes/locale.inc';
19129
  return call_user_func_array($function, $args);
1920
}
193
194
/**
195
 * Implementation of hook_perm().
196
 */
19782
function locale_perm() {
198
  return array(
1992
    'administer languages' => t('Manage the languages in which the website
content and interface text may be displayed.'),
2002
    'translate interface' => t('Translate the text of the website
interface.'),
2012
  );
2020
}
203
204
/**
205
 * Implementation of hook_locale().
206
 */
20782
function locale_locale($op = 'groups') {
208
  switch ($op) {
2098
    case 'groups':
2108
      return array('default' => t('Built-in interface'));
2110
  }
2120
}
213
214
/**
215
 * Implementation of hook_user().
216
 */
21782
function locale_user($type, $edit, &$user, $category = NULL) {
21871
  global $language;
219
220
  // If we have more then one language and either creating a user on the
221
  // admin interface or edit the user, show the language selector.
22271
  if (variable_get('language_count', 1) > 1 && ($type == 'register' &&
user_access('administer users') || $type == 'form' && $category ==
'account' )) {
2230
    $languages = language_list('enabled');
2240
    $languages = $languages[1];
225
226
    // If the user is being created, we set the user language to the page
language.
2270
    $user_preferred_language = $user ? user_preferred_language($user) :
$language;
228
2290
    $names = array();
2300
    foreach ($languages as $langcode => $item) {
2310
      $name = t($item->name);
2320
      $names[$langcode] = $name . ($item->native != $name ? ' (' .
$item->native . ')' : '');
2330
    }
2340
    $form['locale'] = array(
2350
      '#type' => 'fieldset',
2360
      '#title' => t('Language settings'),
2370
      '#weight' => 1,
238
    );
239
240
    // Get language negotiation settings.
2410
    $mode = variable_get('language_negotiation',
LANGUAGE_NEGOTIATION_NONE);
2420
    $form['locale']['language'] = array(
2430
      '#type' => (count($names) <= 5 ? 'radios' : 'select'),
2440
      '#title' => t('Language'),
2450
      '#default_value' => $user_preferred_language->language,
2460
      '#options' => $names,
2470
      '#description' => ($mode == LANGUAGE_NEGOTIATION_PATH) ? t("This
account's default language for e-mails, and preferred language for site
presentation.") : t("This account's default language for e-mails."),
248
    );
2490
    return $form;
2500
  }
25171
}
252
253
/**
254
 * Implementation of hook_form_alter(). Adds language fields to forms.
255
 */
25682
function locale_form_alter(&$form, $form_state, $form_id) {
257
  switch ($form_id) {
258
259
    // Language field for paths
26059
    case 'path_admin_form':
2610
      $form['language'] = array(
2620
        '#type' => 'select',
2630
        '#title' => t('Language'),
2640
        '#options' => array('' => t('All languages')) +
locale_language_list('name'),
2650
        '#default_value' => $form['language']['#value'],
2660
        '#weight' => -10,
2670
        '#description' => t('A path alias set for a specific language will
always be used when displaying this page in that language, and takes
precedence over path aliases set for <am>All languages</em>.'),
268
      );
2690
      break;
270
271
    // Language setting for content types
27259
    case 'node_type_form':
2733
      if (isset($form['identity']['type'])) {
2743
        $form['workflow']['language_content_type'] = array(
2753
          '#type' => 'radios',
2763
          '#title' => t('Multilingual support'),
2773
          '#default_value' => variable_get('language_content_type_' .
$form['#node_type']->type, 0),
2783
          '#options' => array(t('Disabled'), t('Enabled')),
2793
          '#description' => t('Enable multilingual support for this content
type. If enabled, a language selection field will be added to the editing
form, allowing you to select from one of the <a href="!languages">enabled
languages</a>. If disabled, new posts are saved with the default language.
Existing content will not be affected by changing this option.',
array('!languages' => url('admin/settings/language'))),
280
        );
2813
      }
2823
      break;
283
284
    // Language field for nodes
28556
    default:
28656
      if (isset($form['#id']) && $form['#id'] == 'node-form') {
2874
        if (isset($form['#node']->type) &&
variable_get('language_content_type_' . $form['#node']->type, 0)) {
2884
          $form['language'] = array(
2894
            '#type' => 'select',
2904
            '#title' => t('Language'),
2914
            '#default_value' => (isset($form['#node']->language) ?
$form['#node']->language : ''),
2924
            '#options' => array('' => t('Language neutral')) +
locale_language_list('name'),
293
          );
2944
        }
295
        // Node type without language selector: assign the default for new
nodes
2960
        elseif (!isset($form['#node']->nid)) {
2970
          $default = language_default();
2980
          $form['language'] = array(
2990
            '#type' => 'value',
3000
            '#value' => $default->language
3010
          );
3020
        }
3034
      }
30456
  }
30559
}
306
307
/**
308
 * Implementation of hook_theme().
309
 */
31082
function locale_theme() {
311
  return array(
312
    'locale_languages_overview_form' => array(
3132
      'arguments' => array('form' => array()),
3142
    ),
3152
  );
3160
}
317
318
//
---------------------------------------------------------------------------------
319
// Locale core functionality
320
321
/**
322
 * Provides interface translation services.
323
 *
324
 * This function is called from t() to translate a string if needed.
325
 *
326
 * @param $string
327
 *   A string to look up translation for. If omitted, all the
328
 *   cached strings will be returned in all languages already
329
 *   used on the page.
330
 * @param $langcode
331
 *   Language code to use for the lookup.
332
 * @param $reset
333
 *   Set to TRUE to reset the in-memory cache.
334
 */
33582
function locale($string = NULL, $langcode = NULL, $reset = FALSE) {
3361
  global $language;
3371
  static $locale_t;
338
3391
  if ($reset) {
340
    // Reset in-memory cache.
3411
    $locale_t = NULL;
3421
  }
343
3441
  if (!isset($string)) {
345
    // Return all cached strings if no string was specified
3461
    return $locale_t;
3470
  }
348
3491
  $langcode = isset($langcode) ? $langcode : $language->language;
350
351
  // Store database cached translations in a static var.
3521
  if (!isset($locale_t[$langcode])) {
3531
    $locale_t[$langcode] = array();
354
    // Disabling the usage of string caching allows a module to watch for
355
    // the exact list of strings used on a page. From a performance
356
    // perspective that is a really bad idea, so we have no user
357
    // interface for this. Be careful when turning this option off!
3581
    if (variable_get('locale_cache_strings', 1) == 1) {
3591
      if ($cache = cache_get('locale:' . $langcode, 'cache')) {
3600
        $locale_t[$langcode] = $cache->data;
3610
      }
362
      else {
363
        // Refresh database stored cache of translations for given
language.
364
        // We only store short strings used in current version, to improve
365
        // performance and consume less memory.
3661
        $result = db_query("SELECT s.source, t.translation, t.language FROM
{locales_source} s LEFT JOIN {locales_target} t ON s.lid = t.lid AND
t.language = '%s' WHERE s.textgroup = 'default' AND s.version = '%s' AND
LENGTH(s.source) < 75", $langcode, VERSION);
3671
        while ($data = db_fetch_object($result)) {
3681
          $locale_t[$langcode][$data->source] = (empty($data->translation)
? TRUE : $data->translation);
3691
        }
3701
        cache_set('locale:' . $langcode, $locale_t[$langcode]);
371
      }
3721
    }
3731
  }
374
375
  // If we have the translation cached, skip checking the database
3761
  if (!isset($locale_t[$langcode][$string])) {
377
378
    // We do not have this translation cached, so get it from the DB.
3791
    $translation = db_fetch_object(db_query("SELECT s.lid, t.translation,
s.version FROM {locales_source} s LEFT JOIN {locales_target} t ON s.lid =
t.lid AND t.language = '%s' WHERE s.source = '%s' AND s.textgroup =
'default'", $langcode, $string));
3801
    if ($translation) {
381
      // We have the source string at least.
382
      // Cache translation string or TRUE if no translation exists.
3830
      $locale_t[$langcode][$string] = (empty($translation->translation) ?
TRUE : $translation->translation);
384
3850
      if ($translation->version != VERSION) {
386
        // This is the first use of this string under current Drupal
version. Save version
387
        // and clear cache, to include the string into caching next time.
Saved version is
388
        // also a string-history information for later pruning of the
tables.
3890
        db_query("UPDATE {locales_source} SET version = '%s' WHERE lid =
%d", VERSION, $translation->lid);
3900
        cache_clear_all('locale:', 'cache', TRUE);
3910
      }
3920
    }
393
    else {
394
      // We don't have the source string, cache this as untranslated.
3951
      db_query("INSERT INTO {locales_source} (location, source, textgroup,
version) VALUES ('%s', '%s', 'default', '%s')", request_uri(), $string,
VERSION);
3961
      $locale_t[$langcode][$string] = TRUE;
397
      // Clear locale cache so this string can be added in a later
request.
3981
      cache_clear_all('locale:', 'cache', TRUE);
399
    }
4001
  }
401
4021
  return ($locale_t[$langcode][$string] === TRUE ? $string :
$locale_t[$langcode][$string]);
4030
}
404
405
/**
406
 * Returns plural form index for a specific number.
407
 *
408
 * The index is computed from the formula of this language.
409
 *
410
 * @param $count
411
 *   Number to return plural for.
412
 * @param $langcode
413
 *   Optional language code to translate to a language other than
414
 *   what is used to display the page.
415
 */
41682
function locale_get_plural($count, $langcode = NULL) {
4176
  global $language;
4186
  static $locale_formula, $plurals = array();
419
4206
  $langcode = $langcode ? $langcode : $language->language;
421
4226
  if (!isset($plurals[$langcode][$count])) {
4236
    if (!isset($locale_formula)) {
4246
      $language_list = language_list();
4256
      $locale_formula[$langcode] = $language_list[$langcode]->formula;
4266
    }
4276
    if ($locale_formula[$langcode]) {
4280
      $n = $count;
4290
      $plurals[$langcode][$count] = @eval('return intval(' .
$locale_formula[$langcode] . ');');
4300
      return $plurals[$langcode][$count];
4310
    }
432
    else {
4336
      $plurals[$langcode][$count] = -1;
4346
      return -1;
435
    }
4360
  }
4370
  return $plurals[$langcode][$count];
4380
}
439
440
441
/**
442
 * Returns a language name
443
 */
44482
function locale_language_name($lang) {
4450
  static $list = NULL;
4460
  if (!isset($list)) {
4470
    $list = locale_language_list();
4480
  }
4490
  return ($lang && isset($list[$lang])) ? $list[$lang] : t('All');
4500
}
451
452
/**
453
 * Returns array of language names
454
 *
455
 * @param $field
456
 *   'name' => names in current language, localized
457
 *   'native' => native names
458
 * @param $all
459
 *   Boolean to return all languages or only enabled ones
460
 */
46182
function locale_language_list($field = 'name', $all = FALSE) {
46212
  if ($all) {
4638
    $languages = language_list();
4648
  }
465
  else {
4664
    $languages = language_list('enabled');
4674
    $languages = $languages[1];
468
  }
46912
  $list = array();
47012
  foreach ($languages as $language) {
47112
    $list[$language->language] = ($field == 'name') ? t($language->name) :
$language->$field;
47212
  }
47312
  return $list;
4740
}
475
476
/**
477
 * Imports translations when new modules or themes are installed or
enabled.
478
 *
479
 * This function will either import translation for the component change
480
 * right away, or start a batch if more files need to be imported.
481
 *
482
 * @param $components
483
 *   An array of component (theme and/or module) names to import
484
 *   translations for.
485
 */
48682
function locale_system_update($components) {
4871
  include_once 'includes/locale.inc';
4881
  if ($batch = locale_batch_by_component($components)) {
4890
    batch_set($batch);
4900
  }
4911
}
492
493
/**
494
 * Update JavaScript translation file, if required, and add it to the
page.
495
 *
496
 * This function checks all JavaScript files currently added via
drupal_add_js()
497
 * and invokes parsing if they have not yet been parsed for Drupal.t()
498
 * and Drupal.formatPlural() calls. Also refreshes the JavaScript
translation
499
 * file if necessary, and adds it to the page.
500
 */
50182
function locale_update_js_files() {
50258
  global $language;
503
50458
  $dir = file_create_path(variable_get('locale_js_directory',
'languages'));
50558
  $parsed = variable_get('javascript_parsed', array());
506
507
  // The first three parameters are NULL in order to get an array with all
508
  // scopes. This is necessary to prevent recreation of JS translation
files
509
  // when new files are added for example in the footer.
51058
  $javascript = drupal_add_js(NULL, NULL, NULL);
51158
  $files = $new_files = FALSE;
512
51358
  foreach ($javascript as $scope) {
51420
    foreach ($scope as $type => $data) {
51520
      if ($type != 'setting' && $type != 'inline') {
51620
        foreach ($data as $filepath => $info) {
51720
          $files = TRUE;
51820
          if (!in_array($filepath, $parsed)) {
519
            // Don't parse our own translations files.
5208
            if (substr($filepath, 0, strlen($dir)) != $dir) {
5218
              locale_inc_callback('_locale_parse_js_file', $filepath);
5228
              watchdog('locale', 'Parsed JavaScript file %file.',
array('%file' => $filepath));
5238
              $parsed[] = $filepath;
5248
              $new_files = TRUE;
5258
            }
5268
          }
52720
        }
52820
      }
52920
    }
53020
  }
531
532
  // If there are any new source files we parsed, invalidate existing
533
  // JavaScript translation files for all languages, adding the refresh
534
  // flags into the existing array.
53558
  if ($new_files) {
5368
    $parsed += locale_inc_callback('_locale_invalidate_js');
5378
  }
538
539
  // If necessary, rebuild the translation file for the current language.
54058
  if (!empty($parsed['refresh:' . $language->language])) {
541
    // Don't clear the refresh flag on failure, so that another try will
542
    // be performed later.
5430
    if (locale_inc_callback('_locale_rebuild_js')) {
5440
      unset($parsed['refresh:' . $language->language]);
5450
    }
546
    // Store any changes after refresh was attempted.
5470
    variable_set('javascript_parsed', $parsed);
5480
  }
549
  // If no refresh was attempted, but we have new source files, we need
550
  // to store them too. This occurs if current page is in English.
55158
  else if ($new_files) {
5528
    variable_set('javascript_parsed', $parsed);
5538
  }
554
555
  // Add the translation JavaScript file to the page.
55658
  if ($files && !empty($language->javascript)) {
5570
    drupal_add_js($dir . '/' . $language->language . '_' .
$language->javascript . '.js', 'core');
5580
  }
55958
}
560
561
//
---------------------------------------------------------------------------------
562
// Language switcher block
563
564
/**
565
 * Implementation of hook_block().
566
 * Displays a language switcher. Translation links may be provided by other
modules.
567
 */
56882
function locale_block($op = 'list', $delta = '') {
5690
  if ($op == 'list') {
5700
    $block['language-switcher']['info'] = t('Language switcher');
571
    // Not worth caching.
5720
    $block['language-switcher']['cache'] = BLOCK_NO_CACHE;
5730
    return $block;
5740
  }
575
576
  // Only show if we have at least two languages and language dependent
577
  // web addresses, so we can actually link to other language versions.
5780
  elseif ($op == 'view' && variable_get('language_count', 1) > 1 &&
variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) !=
LANGUAGE_NEGOTIATION_NONE) {
5790
    $languages = language_list('enabled');
5800
    $links = array();
5810
    foreach ($languages[1] as $language) {
5820
      $links[$language->language] = array(
5830
        'href'       => $_GET['q'],
5840
        'title'      => $language->native,
5850
        'language'   => $language,
5860
        'attributes' => array('class' => 'language-link'),
587
      );
5880
    }
589
590
    // Allow modules to provide translations for specific links.
591
    // A translation link may need to point to a different path or use
592
    // a translated link text before going through l(), which will just
593
    // handle the path aliases.
5940
    drupal_alter('translation_link', $links, $_GET['q']);
595
5960
    $block['subject'] = t('Languages');
5970
    $block['content'] = theme('links', $links, array());
5980
    return $block;
5990
  }
6000
}
60182