Ukrainian translations per submodule 100% translated for 6.1 i18n module branch
[project/i18n.git] / i18n.module
CommitLineData
78e8cd8d
JR
1<?php
2// $Id$
55209b2f 3
78e8cd8d 4/**
afcc0a25 5 * @file
78e8cd8d
JR
6 * Internationalization (i18n) module
7 *
818652bd
JR
8 * This module extends multilingual support being the base module for the i18n package.
9 * - Multilingual variables
10 * - Extended languages for nodes
11 * - Extended language API
136d636d 12 *
78e8cd8d
JR
13 * @author Jose A. Reyero, 2004
14 */
15
afcc0a25
JR
16// Some constants. Language support modes for content
17define('LANGUAGE_SUPPORT_NONE', 0);
18define('LANGUAGE_SUPPORT_NORMAL', 1);
19define('LANGUAGE_SUPPORT_EXTENDED', 2);
5196f381 20define('LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED', 3);
90d529a0 21/**
98f49db3 22 * Implementation of hook_init().
136d636d 23 *
98f49db3 24 * Will initialize language dependent variables.
25 * Modify rewriting conditions when viewing specific nodes.
136d636d 26 *
98f49db3 27 * Special fix for site_frontpage, that may have been used before the language variables are loaded.
937ec95a 28 */
98f49db3 29function i18n_init() {
09e0b4d5
JR
30 global $language;
31
98f49db3 32 // If not in bootstrap, variable init.
33 if (!_i18n_is_bootstrap()) {
b28c2734 34 $default_frontpage = variable_get('site_frontpage', 'node');
136d636d 35
b28c2734 36 i18n_variable_init();
136d636d 37
98f49db3 38 // Now we check whether this is the frontpage and it should be a different one.
b28c2734
JR
39 if ($default_frontpage != variable_get('site_frontpage', 'node') && $_GET['q'] == drupal_get_normal_path($default_frontpage)) {
40 $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
41 }
afcc0a25 42 }
90d529a0 43}
3128d317 44
6681618a
JR
45/**
46 * Implementation of hook_help().
47 */
affdb36b
JR
48function i18n_help($path = 'admin/help#i18n', $arg) {
49 switch ($path) {
d469e0bb 50 case 'admin/help#i18n' :
98f49db3 51 $output = '<p>'. t('This module improves support for multilingual content in Drupal sites:') .'</p>';
98e35ee4 52 $output .= '<ul>';
10973c0b 53 $output .= '<li>'. t('Shows content depending on page language.') .'</li>';
54 $output .= '<li>'. t('Handles multilingual variables.') .'</li>';
98f49db3 55 $output .= '<li>'. t('Extended language option for chosen content types. For these content types transations will be allowed for all defined languages, not only for enabled ones.') .'</li>';
1d637c88 56 $output .= '<li>'. t('Provides a block for language selection and two theme functions: <em>i18n_flags</em> and <em>i18n_links</em>.') .'</li>';
818652bd 57 $output .= '</ul>';
98f49db3 58 $output .= '<p>'. t('This is the base module for several others adding different features:') .'</p>';
136d636d 59 $output .= '<ul>';
77fa73f1 60 $output .= '<li>'. t('Multilingual menu items.') .'</li>';
61 $output .= '<li>'. t('Multilingual taxonomy adds a language field for taxonomy vocabularies and terms.') .'</li>';
98e35ee4 62 $output .= '</ul>';
98f49db3 63 $output .= '<p>'. t('For more information, see the online handbook entry for <a href="@i18n">Internationalization module</a>.', array('@i18n' => 'http://drupal.org/node/133977')) .'</p>';
98e35ee4 64 return $output;
ac10f554 65
0b07a5e3 66 case 'admin/settings/language/i18n':
818652bd 67 $output = '<ul>';
98f49db3 68 $output .= '<li>'. t('To enable multilingual support for specific content types go to <a href="@configure_content_types">configure content types</a>.', array('@configure_content_types' => url('admin/content/types'))) .'</li>';
69 $output .= '</ul>';
38f996de 70 return $output;
6681618a 71 }
6681618a
JR
72}
73
74/**
8dcb741b 75 * Implementation of hook_menu().
8dcb741b 76 */
afcc0a25 77function i18n_menu() {
0b07a5e3 78 $items['admin/settings/language/i18n'] = array(
afcc0a25 79 'title' => 'Multilingual system',
818652bd
JR
80 'description' => 'Configure extended options for multilingual content and translations.',
81 'page callback' => 'drupal_get_form',
82 'page arguments' => array('i18n_admin_settings'),
83 'access arguments' => array('administer site configuration'),
84 'file' => 'i18n.admin.inc',
e40ff52f 85 'type' => MENU_LOCAL_TASK,
0b07a5e3
JR
86 'weight' => 10,
87 );
88 $items['admin/settings/language/i18n/configure'] = array(
89 'title' => 'Multilingual system',
90 'description' => 'Configure extended options for multilingual content and translations.',
91 //'page callback' => 'drupal_get_form',
92 //'page arguments' => array('i18n_admin_settings'),
93 //'access arguments' => array('administer site configuration'),
94 'file' => 'i18n.admin.inc',
95 'type' => MENU_DEFAULT_LOCAL_TASK,
afcc0a25 96 );
1d40cadd
JR
97 // Autocomplete callback for nodes
98 $items['i18n/node/autocomplete'] = array(
99 'title' => 'Node title autocomplete',
100 'page callback' => 'i18n_node_autocomplete',
101 'access arguments' => array('access content'),
102 'type' => MENU_CALLBACK,
103 'file' => 'i18n.pages.inc',
104 );
8dcb741b
JR
105 return $items;
106}
98e35ee4 107
8dcb741b 108/**
818652bd 109 * Implementation of hook_menu_alter().
136d636d 110 *
98f49db3 111 * Take over the node translation page.
818652bd
JR
112 */
113function i18n_menu_alter(&$items) {
818652bd
JR
114 $items['node/%node/translate']['page callback'] = 'i18n_translation_node_overview';
115 $items['node/%node/translate']['file'] = 'i18n.pages.inc';
116 $items['node/%node/translate']['module'] = 'i18n';
818652bd
JR
117}
118
119/**
98e35ee4
JR
120 * Implementation of hook_nodeapi().
121 */
afcc0a25 122/*
98e35ee4
JR
123function i18n_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
124 if (variable_get("i18n_node_$node->type", 0)) {
98f49db3 125 switch ($op) {
98e35ee4
JR
126 case 'load':
127 return db_fetch_array(db_query("SELECT trid, language, status AS i18n_status FROM {i18n_node} WHERE nid=%d", $node->nid));
98f49db3 128
98e35ee4
JR
129 case 'insert':
130 case 'update':
131 db_query("DELETE FROM {i18n_node} WHERE nid=%d",$node->nid);
afcc0a25
JR
132 if ($node->language){
133 // Assign a trid from the beginning
98e35ee4
JR
134 db_query("INSERT INTO {i18n_node} (nid, trid, language, status) VALUES(%d, '%d', '%s', '%d')", $node->nid, $node->trid, $node->language, $node->i18n_status);
135 }
afcc0a25
JR
136 // Handle menu items. Fixes duplication issue and language for menu items which happens when editing nodes in languages other than current.
137 if (isset($node->menu) && !$node->menu['delete'] && $node->menu['title']) {
138 $item = $node->menu;
139 $item['path'] = ($item['path']) ? $item['path'] : "node/$node->nid";
140 $item['type'] = $item['type'] | MENU_MODIFIED_BY_ADMIN;
141 if ($item['mid']) {
98f49db3 142 // Update menu item.
afcc0a25
JR
143 db_query("UPDATE {menu} SET pid = %d, path = '%s', title = '%s', description = '%s', weight = %d, type = %d, language = '%s' WHERE mid = %d", $item['pid'], $item['path'], $item['title'], $item['description'], $item['weight'], $item['type'], $node->language, $item['mid']);
144 drupal_set_message(t('The menu item %title has been updated with node language.', array('%title' => $item['title'])));
98f49db3 145 }
146 elseif (SAVED_NEW == menu_save_item($item)) {
147 // Creating new menu item with node language.
afcc0a25 148 db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $node->language, $item['mid']);
136d636d 149 drupal_set_message(t('The menu item %title has been added with node language.', array('%title' => $item['title'])));
afcc0a25
JR
150 }
151 menu_rebuild();
98f49db3 152 unset($node->menu); // Avoid further processing by menu module.
afcc0a25 153 }
98f49db3 154 // Pathauto integration. Dynamic replacement of variables to allow different patterns per language.
afcc0a25 155 if (module_exists('path') && module_exists('pathauto')) {
98f49db3 156 // Language for pathauto variables is either node language or default language.
afcc0a25
JR
157 $language = $node->language ? $node->language : i18n_default_language();
158 if ($language != i18n_get_lang()) {
159 i18n_variable_init($language, 'pathauto_node');
160 }
161 }
98e35ee4 162 break;
98f49db3 163
136d636d 164 case 'delete':
98e35ee4
JR
165 db_query('DELETE FROM {i18n_node} WHERE nid=%d', $node->nid);
166 break;
98f49db3 167
afcc0a25 168 case 'prepare':
98f49db3 169 // Book pages, set the right language nodes and outlines.
afcc0a25
JR
170 if (arg(3) == 'parent' && is_numeric(arg(4)) && ($parent = node_load(arg(4))) && $parent->language) {
171 $node->language = $parent->language;
172 i18n_selection_mode('node', $parent->language);
136d636d 173 }
afcc0a25 174 break;
98e35ee4 175 }
136d636d 176 }
98f49db3 177}*/
98e35ee4
JR
178
179/**
818652bd
JR
180 * Implementation of hook_alter_translation_link().
181 *
98f49db3 182 * Handles links for extended language. The links will have current language.
818652bd
JR
183 */
184function i18n_translation_link_alter(&$links, $path) {
185 global $language;
136d636d 186
818652bd
JR
187 // Check for a node related path, and for its translations.
188 if ((preg_match("!^node/([0-9]+)(/.+|)$!", $path, $matches)) && ($node = node_load((int)$matches[1])) && !empty($node->tnid)) {
1d40cadd 189 // make sure language support is set to LANGUAGE_SUPPORT_EXTENDED, so links
5196f381
JR
190 // dont get added for LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED
191 if (variable_get('i18n_node_'. $node->type, LANGUAGE_SUPPORT_NORMAL) == LANGUAGE_SUPPORT_EXTENDED) {
192 $languages = language_list();
193 $extended = array();
194 foreach (translation_node_get_translations($node->tnid) as $langcode => $translation_node) {
195 if (!isset($links[$langcode]) && isset($languages[$langcode])) {
196 $extended[$langcode] = array(
197 'href' => 'node/'. $translation_node->nid . $matches[2],
198 'language' => $language,
199 'language_icon' => $languages[$langcode],
200 'title' => $languages[$langcode]->native,
201 'attributes' => array('class' => 'language-link'),
202 );
203 }
818652bd 204 }
5196f381
JR
205 // This will run after languageicon module, so we add icon in case that one is enabled.
206 if ($extended && function_exists('languageicons_translation_link_alter')) {
207 languageicons_translation_link_alter($extended, $path);
208 }
209 $links = array_merge($links, $extended);
818652bd 210 }
818652bd
JR
211 }
212}
213
214/**
215 * Implementation of hook_link_alter().
216 *
98f49db3 217 * Handles links for extended languages. Sets current interface language.
818652bd
JR
218 */
219function i18n_link_alter(&$links, $node) {
220 global $language;
136d636d 221
5196f381
JR
222 $language_support = variable_get('i18n_node_'. $node->type, LANGUAGE_SUPPORT_NORMAL);
223
224 // Hide node translation links.
225 if (variable_get('i18n_hide_translation_links', 0) == 1) {
226 foreach ($links as $module => $link) {
227 if (strpos($module, 'node_translation') === 0) {
228 unset($links[$module]);
229 }
230 }
231 }
232
1e456352 233 if (!empty($node->tnid)) {
818652bd 234 foreach (array_keys(i18n_language_list('extended')) as $langcode) {
98f49db3 235 $index = 'node_translation_'. $langcode;
818652bd 236 if (!empty($links[$index])) {
5196f381
JR
237 if ($language_support != LANGUAGE_SUPPORT_EXTENDED && $links[$index]['language']->enabled == 0) {
238 unset($links[$index]);
239 }
240 else {
241 $links[$index]['language'] = $language;
242 }
818652bd
JR
243 }
244 }
245 }
246}
247
248/**
98f49db3 249 * Implementation of hook_user().
136d636d 250 *
98f49db3 251 * Switch to user's language after login.
afcc0a25
JR
252 */
253function i18n_user($op, &$edit, &$account, $category = NULL) {
98f49db3 254 if ($op == 'login' && $account->language) {
afcc0a25
JR
255 $_SESSION['language'] = $account->language;
256 i18n_get_lang($account->language);
98e35ee4 257 }
74c2972e
JR
258}
259
260/**
ac152d40
NR
261 * Implementation of hook_elements().
262 *
263 * Add a process callback for textfields.
264 */
265function i18n_elements() {
266 $type = array();
267 $type['textfield'] = array('#process' => array('i18n_textfield_process'));
268 return $type;
269}
270
271/**
272 * Process callback for textfield elements.
273 *
274 * When editing or translating a node, set Javascript to rewrite autocomplete
275 * paths to use the node language prefix rather than the current content one.
276 */
277function i18n_textfield_process($element) {
278 global $language;
279 static $sent = FALSE;
280
281 // Ensure we send the Javascript only once.
282 if (!$sent && isset($element['#autocomplete_path']) && !empty($element['#autocomplete_path']) && variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) != LANGUAGE_NEGOTIATION_NONE) {
283 // Add a JS file for node forms.
284 // Determine if we are either editing or translating an existing node.
285 // We can't act on regular node creation because we don't have a specified
286 // node language.
287 $node_edit = $node = menu_get_object() && arg(2) == 'edit' && isset($node->language) && !empty($node->language);
288 $node_translate = arg(0) == 'node' && arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language']);
289 if ($node_edit || $node_translate) {
290 $node_language = $node_edit ? $node->language : $_GET['language'];
291 // Only needed if the node language is different from the interface one.
292 if ($node->language != $language->language) {
293 $languages = language_list();
294 if (isset($languages[$node_language])) {
295 drupal_add_js(drupal_get_path('module', 'i18n') . '/i18n.js');
296 // Pass the interface and content language base paths.
297 // Remove any trailing forward slash. Doing so prevents a mismatch
298 // that occurs when a language has no prefix and hence gets a path
299 // with a trailing forward slash.
300 $interface = rtrim(url('', array('absolute' => TRUE)), '/');
301 $content = rtrim(url('', array('absolute' => TRUE, 'language' => $languages[$node_language])), '/');
302 $data = array('interface_path' => $interface, 'content_path' => $content);
303 drupal_add_js(array('i18n' => $data), 'setting');
304 }
305 }
306 }
307 $sent = TRUE;
308 }
309 return $element;
310}
311
312/**
81f2a50c 313 * Simple i18n API
78e8cd8d 314 */
6681618a 315
98e35ee4 316/**
98f49db3 317 * Get language properties.
136d636d 318 *
98e35ee4 319 * @param $code
98f49db3 320 * Language code.
98e35ee4
JR
321 * @param $property
322 * It may be 'name', 'native', 'ltr'...
323 */
818652bd
JR
324function i18n_language_property($code, $property) {
325 $languages = language_list();
16ae3caa 326 return isset($languages[$code]->$property) ? $languages[$code]->$property : NULL;
98e35ee4
JR
327}
328
329/**
98f49db3 330 * Get node language.
90d529a0 331 */
90d529a0 332function i18n_node_get_lang($nid, $default = '') {
98f49db3 333 $lang = db_result(db_query('SELECT language FROM {node} WHERE nid = %d', $nid));
90d529a0
JR
334 return $lang ? $lang : $default ;
335}
336
337/**
98f49db3 338 * Get allowed languages for node.
136d636d 339 *
98f49db3 340 * This allows node types to define its own language list implementing hook 'language_list'.
136d636d 341 *
818652bd 342 * @param $node
98f49db3 343 * Node to retrieve language list for.
818652bd 344 * @param $translate
98f49db3 345 * Only languages available for translation. Filter out existing translations.
818652bd
JR
346 */
347function i18n_node_language_list($node, $translate = FALSE) {
98f49db3 348 // Check if the node module manages its own language list.
818652bd
JR
349 $languages = node_invoke($node, 'language_list', $translate);
350 if (!$languages) {
0698d0c8 351 if (variable_get('i18n_node_'. $node->type, 0) >= LANGUAGE_SUPPORT_EXTENDED) {
818652bd 352 $languages = locale_language_list('name', TRUE); // All defined languages
98f49db3 353 }
354 else {
818652bd
JR
355 $languages = locale_language_list(); // All enabled languages
356 }
357 if ($translate && isset($node->tnid) && $node->tnid && ($translations = translation_node_get_translations($node->tnid))) {
358 unset($translations[$node->language]);
359 foreach (array_keys($translations) as $langcode) {
360 unset($languages[$langcode]);
361 }
362 }
363 $languages = array('' => t('Language neutral')) + $languages;
afcc0a25 364 }
818652bd
JR
365
366 return $languages;
90d529a0
JR
367}
368
369/**
ee361f1b 370 * Selection mode for content.
136d636d 371 *
98f49db3 372 * Warning: when used with params they need to be escaped, as some values are thrown directly in queries.
136d636d 373 *
98f49db3 374 * Allows several modes for query rewriting and to change them programatically.
375 * off = No language conditions inserted.
376 * simple = Only current language and no language.
377 * mixed = Only current and default languages.
378 * strict = Only current language.
379 * default = Only default language.
380 * user = User defined, in the module's settings page.
381 * params = Gets the stored params.
382 * reset = Returns to previous.
383 * custom = add custom where clause, like "%alias.language = 'en'".
384 */
385function i18n_selection_mode($mode = NULL, $params = NULL) {
ee361f1b 386 static $current_mode = NULL;
8dcb741b
JR
387 static $current_value = '';
388 static $store = array();
136d636d 389
98f49db3 390 // Initialization, first time this runs with no explicit mode.
ee361f1b
JR
391 if (!$current_mode && !$mode) {
392 $current_mode = variable_get('i18n_selection_mode', 'simple');
799a2597 393 if ($current_mode != 'off') {
98f49db3 394 // Node language when loading specific nodes or creating translations.
799a2597 395 if (arg(0) == 'node' ) {
affdb36b 396 if (($node = menu_get_object('node')) && $node->language) {
799a2597
JR
397 $current_mode = 'node';
398 $current_value = $node->language;
98f49db3 399 }
09e0b4d5 400 elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language'])) {
799a2597
JR
401 $current_mode = 'translation';
402 $current_value = db_escape_string($_GET['language']);
136d636d 403 }
98f49db3 404 }
405 elseif (arg(0) == 'admin') {
406 // There are some exceptions for admin pages.
799a2597 407 if (arg(1) == 'content' && user_access('administer all languages')) {
98f49db3 408 // No restrictions for administration pages.
799a2597 409 $current_mode = 'off';
98f49db3 410 }
411 elseif (arg(1) == 'build' && arg(2) == 'menu-customize') {
412 // All nodes available when editing custom menu items.
799a2597
JR
413 $current_mode = 'off';
414 }
ee361f1b 415 }
136d636d 416 }
ee361f1b 417 }
136d636d 418
98f49db3 419 if (!$mode) {
8dcb741b 420 return $current_mode;
98f49db3 421 }
422 elseif ($mode == 'params') {
8dcb741b 423 return $current_value;
98f49db3 424 }
425 elseif ($mode == 'reset') {
8dcb741b 426 list($current_mode, $current_value) = array_pop($store);
98f49db3 427 }
428 else {
8dcb741b
JR
429 array_push($store, array($current_mode, $current_value));
430 $current_mode = $mode;
431 $current_value = $params;
136d636d 432 }
81f2a50c 433}
74c2972e
JR
434
435/**
98f49db3 436 * Implementation of hook_db_rewrite_sql().
136d636d 437 *
98f49db3 438 * Rewrite node queries so language selection options are enforced.
74c2972e 439 */
98f49db3 440function i18n_db_rewrite_sql($query, $primary_table, $primary_key, $args = array()) {
441 // If mode is 'off' = no rewrite, we cannot return any empty 'where' string so check here.
88d92733
JR
442 $mode = i18n_selection_mode();
443 if ($mode == 'off') return;
136d636d 444
98f49db3 445 // Disable language conditions for views.
446 if (array_key_exists('view', $args)) return;
a1bb6aa6 447
74c2972e
JR
448 switch ($primary_table) {
449 case 'n':
450 case 'node':
98f49db3 451 // No rewrite for queries with subselect ? (views count queries).
452 // @ TO DO Actually these queries look un-rewrittable, check with other developers.
5aaad3de 453 if (preg_match("/FROM \(SELECT/", $query)) return;
98f49db3 454 // No rewrite for translation module queries.
818652bd 455 if (preg_match("/.*FROM {node} $primary_table WHERE.*$primary_table\.tnid/", $query)) return;
98f49db3 456 // When loading specific nodes, language conditions shouldn't apply.
afcc0a25 457 if (preg_match("/WHERE.*\s$primary_table.nid\s*=\s*(\d|%d)/", $query)) return;
98f49db3 458 // If language conditions already there, get out.
afcc0a25 459 if (preg_match("/i18n/", $query)) return;
136d636d 460
461
0ef28a15 462 // Mixed mode is a bit more complex, we need to join in one more table
98f49db3 463 // and add some more conditions, but only if language is not default.
a838e19d 464 if ($mode == 'mixed') {
0ef28a15 465 $result['where'] = i18n_db_rewrite_where($primary_table, 'node', 'simple');
a838e19d 466 if (i18n_get_lang() != i18n_default_language()) {
6bdc58de 467 $result['join'] = "LEFT JOIN {node} i18n ON $primary_table.tnid > 0 AND $primary_table.tnid = i18n.tnid AND i18n.language = '". i18n_get_lang() ."'";
a838e19d 468 // So we show also nodes that have default language.
6bdc58de 469 $result['where'] .= " OR $primary_table.language = '". i18n_default_language() ."' AND i18n.nid IS NULL";
a838e19d 470 }
98f49db3 471 }
472 else {
0ef28a15
JR
473 $result['where'] = i18n_db_rewrite_where($primary_table, 'node', $mode);
474 }
afcc0a25 475 return $result;
74c2972e
JR
476 }
477}
478
98e35ee4 479/**
98f49db3 480 * Rewrites queries depending on rewriting mode.
98e35ee4 481 */
98f49db3 482function i18n_db_rewrite_where($alias, $type, $mode = NULL) {
afcc0a25 483 if (!$mode) {
98f49db3 484 // Some exceptions for query rewrites.
afcc0a25 485 $mode = i18n_selection_mode();
136d636d 486 }
0ef28a15 487
98f49db3 488 // Get languages to simplify query building.
0ef28a15
JR
489 $current = i18n_get_lang();
490 $default = i18n_default_language();
136d636d 491
88d92733 492 if ($mode == 'strict' && $type != 'node') {
98f49db3 493 // Special case. Selection mode is 'strict' but this should be only for node queries.
88d92733 494 $mode = 'simple';
136d636d 495 }
0ef28a15 496 elseif ($mode == 'mixed' && $current == $default) {
98f49db3 497 // If mode is mixed but current = default, is the same as 'simple'.
0ef28a15
JR
498 $mode = 'simple';
499 }
136d636d 500
98f49db3 501 switch ($mode) {
afcc0a25
JR
502 case 'off':
503 return '';
98f49db3 504
74c2972e 505 case 'simple':
0ef28a15 506 return "$alias.language ='$current' OR $alias.language ='' OR $alias.language IS NULL" ;
98f49db3 507
74c2972e 508 case 'mixed':
0ef28a15 509 return "$alias.language ='$current' OR $alias.language ='$default' OR $alias.language ='' OR $alias.language IS NULL" ;
98f49db3 510
74c2972e 511 case 'strict':
0ef28a15 512 return "$alias.language ='$current'" ;
98f49db3 513
74c2972e
JR
514 case 'node':
515 case 'translation':
98f49db3 516 return "$alias.language ='". i18n_selection_mode('params') ."' OR $alias.language ='' OR $alias.language IS NULL" ;
517
74c2972e 518 case 'default':
0ef28a15 519 return "$alias.language ='$default' OR $alias.language ='' OR $alias.language IS NULL" ;
98f49db3 520
74c2972e 521 case 'custom':
afcc0a25 522 return str_replace('%alias', $alias, i18n_selection_mode('params'));
136d636d 523 }
74c2972e
JR
524}
525
526/**
98f49db3 527 * Implementation of hook_exit().
74c2972e 528 */
98f49db3 529function i18n_exit() {
38f996de 530 _i18n_variable_exit();
74c2972e
JR
531}
532
533/**
818652bd 534 * Implementation of hook_form_alter();
136d636d 535 *
98f49db3 536 * This is the place to add language fields to all forms.
74c2972e 537 */
afcc0a25 538function i18n_form_alter(&$form, $form_state, $form_id) {
98f49db3 539 switch ($form_id) {
540 case 'node_type_form':
541 // Add extended language support option to content type form.
542 $form['workflow']['i18n_node'] = array(
543 '#type' => 'radios',
544 '#title' => t('Extended language support'),
545 '#default_value' => variable_get('i18n_node_'. $form['#node_type']->type, LANGUAGE_SUPPORT_NORMAL),
546 '#options' => _i18n_content_language_options(),
547 '#description' => t('If enabled, all defined languages will be allowed for this content type in addition to only enabled ones. This is useful to have more languages for content than for the interface.')
548 );
549 break;
afcc0a25 550
74c2972e 551 default:
a1887ef3 552 // Extensions for node edit forms
818652bd 553 if (isset($form['#id']) && $form['#id'] == 'node-form') {
a1887ef3
JR
554 if (isset($form['#node']->type)) {
555 // Set language to empty for not multilingual nodes when creating
556 if (!isset($form['#node']->nid) && !variable_get('language_content_type_'. $form['#node']->type, 0)) {
557 $form['language'] = array('#type' => 'value', '#value' => '');
98f49db3 558 }
a1887ef3
JR
559 // Extended language, add all languages to the list
560 if (!empty($form['language']['#options']) && variable_get('language_content_type_'. $form['#node']->type, 0)) {
561 $form['language']['#options'] = i18n_node_language_list($form['#node'], TRUE);
74c2972e 562 }
74c2972e 563 }
74c2972e 564 }
a1887ef3 565
98f49db3 566 // Multilingual variables in settings form.
afcc0a25
JR
567 if (isset($form['#theme']) && $form['#theme'] == 'system_settings_form' && $variables = variable_get('i18n_variables', 0)) {
568 if (i18n_form_alter_settings($form, $variables)) {
569 $form['#submit'][] = 'i18n_variable_form_submit';
98e35ee4
JR
570 }
571 }
136d636d 572 }
74c2972e
JR
573}
574
575/**
afcc0a25 576 * Implementation of hook_perm().
136d636d 577 *
afcc0a25
JR
578 * Permissions defined
579 * - administer all languages
580 * Disables language conditions for administration pages, so the user can view objects for all languages at the same time.
581 * This applies for: menu items, taxonomy
1d40cadd
JR
582 * - administer translations
583 * Will allow to add/remove existing nodes to/from translation sets.
afcc0a25
JR
584 */
585function i18n_perm() {
1d40cadd
JR
586 return array('administer all languages', 'administer translations');
587}
588
589/**
590 * Implementation of hook_theme()
591 */
592function i18n_theme() {
593 return array(
594 'i18n_node_select_translation' => array(
595 'arguments' => array('element' => NULL),
596 'file' => 'i18n.pages.inc',
597 ),
598 );
afcc0a25 599}
98f49db3 600
afcc0a25
JR
601/**
602 * Process menu and menu item add/edit form submissions.
603 */
affdb36b
JR
604function i18n_menu_edit_item_form_submit($form, &$form_state) {
605 $mid = menu_edit_item_save($form_state['values']);
606 db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $form_state['values']['language'], $mid);
afcc0a25
JR
607 return 'admin/build/menu';
608}
609
610/**
98f49db3 611 * Check for multilingual variables in form.
98e35ee4
JR
612 */
613function i18n_form_alter_settings(&$form, &$variables) {
614 $result = 0;
afcc0a25 615 foreach (element_children($form) as $field) {
98f49db3 616 if (isset($form[$field]['#type']) && $form[$field]['#type'] == 'fieldset') {
98e35ee4
JR
617 $result += i18n_form_alter_settings($form[$field], $variables);
618 }
619 elseif (in_array($field, $variables)) {
98f49db3 620 $form[$field]['#description'] .= ' <strong>'. t('This is a multilingual variable.') .'</strong>';
98e35ee4
JR
621 $result++;
622 }
623 }
624 return $result;
625}
626
627/**
98f49db3 628 * Save multilingual variables and remove them from form.
98e35ee4 629 */
afcc0a25 630function i18n_variable_form_submit($form, &$form_state) {
affdb36b 631 $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
98e35ee4
JR
632 $variables = variable_get('i18n_variables', array());
633 $language = i18n_get_lang();
affdb36b 634 foreach ($form_state['values'] as $key => $value) {
afcc0a25 635 if (in_array($key, $variables)) {
98e35ee4
JR
636 if ($op == t('Reset to defaults')) {
637 i18n_variable_del($key, $language);
638 }
639 else {
affdb36b 640 if (is_array($value) && isset($form_state['values']['array_filter'])) {
98e35ee4 641 $value = array_keys(array_filter($value));
74c2972e 642 }
98e35ee4 643 i18n_variable_set($key, $value, $language);
74c2972e 644 }
affdb36b 645 unset($form_state['values'][$key]);
136d636d 646 }
98e35ee4
JR
647 }
648 // Re-submit form
afcc0a25 649 // system_settings_form_submit($form_id, $form_values);
98e35ee4
JR
650}
651
652/**
98f49db3 653 * Initialization of multilingual variables.
136d636d 654 *
afcc0a25 655 * @param $language
98f49db3 656 * Language to retrieve variables. Defaults to current language.
afcc0a25 657 * @param $prefix
98f49db3 658 * Variable name prefix to load just a selected group of variables.
38f996de 659 */
98f49db3 660function i18n_variable_init($langcode = NULL, $prefix = '') {
38f996de
JR
661 global $conf;
662 global $i18n_conf;
136d636d 663
b28c2734 664 $langcode = $langcode ? $langcode : i18n_get_lang();
98f49db3 665 if ($i18n_variables = variable_get('i18n_variables', '')) {
afcc0a25
JR
666 if (!$i18n_conf) {
667 $i18n_conf = array();
668 }
b28c2734 669 $variables = _i18n_variable_init($langcode, $prefix);
98f49db3 670 foreach ($i18n_variables as $name) {
38f996de
JR
671 $i18n_conf[$name] = isset($variables[$name]) ? $variables[$name] : (isset($conf[$name]) ? $conf[$name] : '');
672 }
b28c2734 673
38f996de
JR
674 $conf = array_merge($conf, $i18n_conf);
675 }
676}
677
74c2972e 678/**
57f0a2c1
JR
679 * Get language from context
680 */
681function _i18n_get_context_lang() {
682 // Node language when loading specific nodes or creating translations.
683 if (arg(0) == 'node' ) {
684 if (($node = menu_get_object('node')) && $node->language) {
685 return $node->language;
686 }
687 elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language'])) {
688 return $_GET['language'];
689 }
690 }
691}
692
693/**
98f49db3 694 * Helper function to create language selector.
74c2972e 695 */
98f49db3 696function _i18n_language_select($value ='', $description ='', $weight = -20, $languages = NULL) {
818652bd 697 $languages = $languages ? $languages : locale_language_list();
74c2972e 698 return array(
98f49db3 699 '#type' => 'select',
700 '#title' => t('Language'),
701 '#default_value' => $value,
702 '#options' => array_merge(array('' => ''), $languages),
703 '#description' => $description,
704 '#weight' => $weight,
74c2972e
JR
705 );
706}
707
afcc0a25 708/**
98f49db3 709 * Load language variables into array.
afcc0a25 710 */
98f49db3 711function _i18n_variable_init($language, $prefix = '') {
74c2972e 712 $variables = array();
98f49db3 713 $cacheid = 'variables:'. $language . ($prefix ? ':'. $prefix : '');
afcc0a25
JR
714 if ($cached = cache_get($cacheid)) {
715 $variables = $cached->data;
74c2972e
JR
716 }
717 else {
afcc0a25 718 $result = db_query("SELECT * FROM {i18n_variable} WHERE language='%s' AND name LIKE '%s%'", $language, $prefix);
74c2972e
JR
719 while ($variable = db_fetch_object($result)) {
720 $variables[$variable->name] = unserialize($variable->value);
721 }
afcc0a25 722 cache_set($cacheid, $variables);
74c2972e 723 }
afcc0a25 724 return $variables;
74c2972e
JR
725}
726
38f996de 727/**
98f49db3 728 * Save multilingual variables that may have been changed by other methods than settings pages.
38f996de 729 */
98f49db3 730function _i18n_variable_exit() {
74c2972e
JR
731 global $i18n_conf;
732 global $conf;
98f49db3 733 if ($i18n_conf) {
afcc0a25 734 $lang = i18n_get_lang();
74c2972e 735 $refresh = FALSE;
98f49db3 736 // Rewritten because array_diff_assoc may fail with array variables.
737 foreach ($i18n_conf as $name => $value) {
738 if ($value != $conf[$name]) {
74c2972e
JR
739 $refresh = TRUE;
740 $i18n_conf[$name] = $conf[$name];
741 db_query("DELETE FROM {i18n_variable} WHERE name='%s' AND language='%s'", $name, $lang );
742 db_query("INSERT INTO {i18n_variable} (language, name, value) VALUES('%s', '%s', '%s')", $lang, $name, serialize($conf[$name]));
743 }
744 }
98f49db3 745 if ($refresh) {
746 cache_set('variables:'. $lang, $i18n_conf);
74c2972e
JR
747 }
748 }
7027e3b5 749}
afcc0a25
JR
750
751/**
752 * Check whether we are in bootstrap mode
136d636d 753 */
98f49db3 754function _i18n_is_bootstrap() {
afcc0a25 755 return !function_exists('drupal_get_headers');
136d636d 756}
afcc0a25
JR
757
758/**
afcc0a25
JR
759 * Drupal 6, backwards compatibility layer
760 * @ TO DO Fully upgrade all the modules and remove
761 */
818652bd 762
afcc0a25
JR
763/**
764 * This one expects to be called first from common.inc
765 */
818652bd 766function i18n_get_lang() {
afcc0a25 767 global $language;
afcc0a25
JR
768 return $language->language;
769}
770
5aaad3de 771/**
818652bd
JR
772 * @defgroup i18n_api Extended language API
773 * @{
774 * This is an extended language API to be used by modules in i18n package.
afcc0a25 775 */
818652bd
JR
776
777/**
778 * Returns language lists
779 */
780function i18n_language_list($type = 'enabled', $field = 'name') {
781 switch ($type) {
782 case 'enabled':
783 return locale_language_list($field);
98f49db3 784
818652bd
JR
785 case 'extended':
786 $enabled = locale_language_list($field);
787 $defined = locale_language_list($field, TRUE);
788 return array_diff_assoc($defined, $enabled);
afcc0a25 789 }
818652bd 790}
5aaad3de 791
818652bd 792/**
98f49db3 793 * Returns default language code.
818652bd 794 */
98f49db3 795function i18n_default_language() {
136d636d 796 return language_default('language');
afcc0a25
JR
797}
798
799/**
98f49db3 800 * Get list of supported languages, native name.
136d636d 801 *
afcc0a25 802 * @param $all
98f49db3 803 * TRUE to get all defined languages.
afcc0a25
JR
804 */
805function i18n_supported_languages($all = FALSE) {
818652bd 806 return locale_language_list('native', $all);
afcc0a25
JR
807}
808
809/**
afcc0a25
JR
810 * Set a persistent language dependent variable.
811 *
812 * @param $name
813 * The name of the variable to set.
814 * @param $value
815 * The value to set. This can be any PHP data type; these functions take care
816 * of serialization as necessary.
817 * @param $langcode
98f49db3 818 * Language code.
afcc0a25
JR
819 */
820function i18n_variable_set($name, $value, $langcode) {
821 global $conf, $i18n_conf;
822
823 db_lock_table('i18n_variable');
824 db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
825 db_query("INSERT INTO {i18n_variable} (name, language, value) VALUES ('%s', '%s', '%s')", $name, $langcode, serialize($value));
826 db_unlock_tables();
827
98f49db3 828 cache_clear_all('variables:'. $langcode, 'cache');
afcc0a25
JR
829
830 $conf[$name] = $value;
831 $i18n_conf[$name] = $value;
832}
833
834/**
835 * Unset a persistent multilingual variable.
836 *
837 * @param $name
838 * The name of the variable to undefine.
839 * @param $langcode
98f49db3 840 * Language code.
afcc0a25
JR
841 */
842function i18n_variable_del($name, $langcode) {
843 global $conf, $i18n_conf;
844
845 db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
98f49db3 846 cache_clear_all('variables:'. $langcode, 'cache');
afcc0a25
JR
847
848 unset($conf[$name]);
849 unset($i18n_conf[$name]);
850}
851
852/**
98f49db3 853 * Utility. Get part of array variable.
afcc0a25
JR
854 */
855function i18n_array_variable_get($name, $element, $default = NULL) {
856 if (($values = variable_get($name, array())) && isset($values[$element])) {
857 return $values[$element];
98f49db3 858 }
859 else {
afcc0a25 860 return $default;
136d636d 861 }
afcc0a25
JR
862}
863
864/**
98f49db3 865 * Utility. Set part of array variable.
afcc0a25
JR
866 */
867function i18n_array_variable_set($name, $element, $value) {
868 $values = variable_get($name, array());
869 $values[$element] = $value;
870 variable_set($name, $values);
871}
872
873/**
874 * @} End of "defgroup i18n_api".
875 */
e562cb3d 876
98f49db3 877/**
878 * List of language support modes for content.
879 */
e562cb3d
JR
880function _i18n_content_language_options() {
881 return array(
882 LANGUAGE_SUPPORT_NORMAL => t('Normal - All enabled languages will be allowed.'),
5196f381
JR
883 LANGUAGE_SUPPORT_EXTENDED => t('Extended - All defined languages will be allowed.'),
884 LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED => t('Extended, but not displayed - All defined languages will be allowed for input, but not displayed in links.'),
e562cb3d 885 );
5aaad3de 886}