<?php
-// $Id$
/**
* @file
- * Internationalization (i18n) module
+ * Internationalization (i18n) module.
*
* This module extends multilingual support being the base module for the i18n package.
* - Multilingual variables
define('LANGUAGE_SUPPORT_NONE', 0);
define('LANGUAGE_SUPPORT_NORMAL', 1);
define('LANGUAGE_SUPPORT_EXTENDED', 2);
+define('LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED', 3);
+
+/**
+ * Implementation of hook_boot()
+ *
+ * Initialize variables, that will be used to decide on site_frontpage
+ */
+function i18n_boot() {
+ drupal_bootstrap(DRUPAL_BOOTSTRAP_LANGUAGE);
+ _i18n_init();
+}
/**
* Implementation of hook_init().
*
- * Will initialize language dependent variables.
- * Modify rewriting conditions when viewing specific nodes.
- *
* Special fix for site_frontpage, that may have been used before the language variables are loaded.
*/
function i18n_init() {
- // If not in bootstrap, variable init.
+ // If not in bootstrap, variable init. Otherwise we are serving a cached page so we don't need anything else.
if (!_i18n_is_bootstrap()) {
- $default_frontpage = variable_get('site_frontpage', 'node');
+ _i18n_init(TRUE);
+ _i18n_init_mode();
+ }
+}
+/**
+ * Initialize multilingual variables and use them for site_frontpage
+ *
+ * Special fix for site_frontpage, that may have been used before the language variables are loaded.
+ */
+function _i18n_init($check_frontpage = FALSE) {
+ static $done, $default_frontpage;
+
+ // Prevent this function from running twice;
+ if (!isset($done)) {
+ $done = TRUE;
+ $default_frontpage = variable_get('site_frontpage', 'node');
i18n_variable_init();
-
- // Now we check whether this is the frontpage and it should be a different one.
- if ($default_frontpage != variable_get('site_frontpage', 'node') && $_GET['q'] == drupal_get_normal_path($default_frontpage)) {
- $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
- }
+ }
+ // We do aditional frontpage check if this has run after first bootstrap phase.
+ // But if this runs in hook_boot we should be ok
+ if ($check_frontpage && $default_frontpage != variable_get('site_frontpage', 'node') && $_GET['q'] == drupal_get_normal_path($default_frontpage)) {
+ $_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
}
}
/**
+ * Initialize selection mode
+ */
+function _i18n_init_mode() {
+ if (i18n_selection_mode() != 'off') {
+ // Node language when loading specific nodes or creating translations.
+ if (arg(0) == 'node' ) {
+ // We shouldn't call menu_get_object() because it may end up calling i18n_selection_mode(), see #614548
+ // Also we better don't do the full node loading here because there may be missing modules (init)
+ if (is_numeric(arg(1)) && (arg(2) == 'edit') && ($lang = i18n_node_get_lang(arg(1)))) {
+ i18n_selection_mode('node', $lang);
+ }
+ elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language'])) {
+ i18n_selection_mode('translation', db_escape_string($_GET['language']));
+ }
+ }
+ elseif (arg(0) == 'admin') {
+ // There are some exceptions for admin pages.
+ if (arg(1) == 'content' && user_access('administer all languages')) {
+ // No restrictions for administration pages.
+ i18n_selection_mode('off');
+ }
+ elseif (arg(1) == 'build' && (arg(2) == 'menu-customize' || arg(2) == 'menu')) {
+ // All nodes available when editing custom menu items.
+ i18n_selection_mode('off');
+ }
+ }
+ }
+}
+/**
* Implementation of hook_help().
*/
function i18n_help($path = 'admin/help#i18n', $arg) {
$output .= '<li>'. t('Shows content depending on page language.') .'</li>';
$output .= '<li>'. t('Handles multilingual variables.') .'</li>';
$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>';
- $output .= '<li>'. t('Provides a block for language selection and two theme functions: <i>i18n_flags</i> and <i>i18n_links</i>.') .'</li>';
+ $output .= '<li>'. t('Provides a block for language selection and two theme functions: <em>i18n_flags</em> and <em>i18n_links</em>.') .'</li>';
$output .= '</ul>';
$output .= '<p>'. t('This is the base module for several others adding different features:') .'</p>';
$output .= '<ul>';
$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>';
return $output;
- case 'admin/settings/i18n':
+ case 'admin/settings/language/i18n':
$output = '<ul>';
- $output .= '<li>'. t('To manage languages go to the <a href="@configure_languages">languages configuration page</a>.', array('@configure_languages' => url('admin/settings/language'))) .'</li>';
$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>';
$output .= '</ul>';
return $output;
* Implementation of hook_menu().
*/
function i18n_menu() {
- $items['admin/settings/i18n'] = array(
+ $items['admin/settings/language/i18n'] = array(
'title' => 'Multilingual system',
'description' => 'Configure extended options for multilingual content and translations.',
'page callback' => 'drupal_get_form',
'page arguments' => array('i18n_admin_settings'),
'access arguments' => array('administer site configuration'),
'file' => 'i18n.admin.inc',
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 10,
);
- $items['admin/settings/i18n/main'] = array(
- 'title' => 'Internationalization',
+ $items['admin/settings/language/i18n/configure'] = array(
+ 'title' => 'Options',
+ 'description' => 'Configure extended options for multilingual content and translations.',
+ //'page callback' => 'drupal_get_form',
+ //'page arguments' => array('i18n_admin_settings'),
+ //'access arguments' => array('administer site configuration'),
+ 'file' => 'i18n.admin.inc',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
-
+ $items['admin/settings/language/i18n/variables'] = array(
+ 'title' => 'Variables',
+ 'description' => 'Multilingual variables.',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('i18n_admin_variables_form'),
+ 'access arguments' => array('administer site configuration'),
+ 'file' => 'i18n.admin.inc',
+ 'type' => MENU_LOCAL_TASK,
+ );
+ // Autocomplete callback for nodes
+ $items['i18n/node/autocomplete'] = array(
+ 'title' => 'Node title autocomplete',
+ 'page callback' => 'i18n_node_autocomplete',
+ 'access arguments' => array('access content'),
+ 'type' => MENU_CALLBACK,
+ 'file' => 'i18n.pages.inc',
+ );
return $items;
}
* Take over the node translation page.
*/
function i18n_menu_alter(&$items) {
- // dsm($router_items);
- /*
$items['node/%node/translate']['page callback'] = 'i18n_translation_node_overview';
$items['node/%node/translate']['file'] = 'i18n.pages.inc';
$items['node/%node/translate']['module'] = 'i18n';
- */
- /**
- $items = array();
- $items['node/%node/translate'] = array(
- 'title' => 'Translate',
- 'page callback' => 'translation_node_overview',
- 'page arguments' => array(1),
- 'access callback' => '_translation_tab_access',
- 'access arguments' => array(1),
- 'type' => MENU_LOCAL_TASK,
- 'weight' => 2,
- 'file' => 'i18n.pages.inc',
- );
- return $items;
- */
}
/**
* Implementation of hook_nodeapi().
*/
-/*
-function i18n_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
- if (variable_get("i18n_node_$node->type", 0)) {
- switch ($op) {
- case 'load':
- return db_fetch_array(db_query("SELECT trid, language, status AS i18n_status FROM {i18n_node} WHERE nid=%d", $node->nid));
-
- case 'insert':
- case 'update':
- db_query("DELETE FROM {i18n_node} WHERE nid=%d",$node->nid);
- if ($node->language){
- // Assign a trid from the beginning
- db_query("INSERT INTO {i18n_node} (nid, trid, language, status) VALUES(%d, '%d', '%s', '%d')", $node->nid, $node->trid, $node->language, $node->i18n_status);
- }
- // Handle menu items. Fixes duplication issue and language for menu items which happens when editing nodes in languages other than current.
- if (isset($node->menu) && !$node->menu['delete'] && $node->menu['title']) {
- $item = $node->menu;
- $item['path'] = ($item['path']) ? $item['path'] : "node/$node->nid";
- $item['type'] = $item['type'] | MENU_MODIFIED_BY_ADMIN;
- if ($item['mid']) {
- // Update menu item.
- 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']);
- drupal_set_message(t('The menu item %title has been updated with node language.', array('%title' => $item['title'])));
- }
- elseif (SAVED_NEW == menu_save_item($item)) {
- // Creating new menu item with node language.
- db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $node->language, $item['mid']);
- drupal_set_message(t('The menu item %title has been added with node language.', array('%title' => $item['title'])));
- }
- menu_rebuild();
- unset($node->menu); // Avoid further processing by menu module.
- }
- // Pathauto integration. Dynamic replacement of variables to allow different patterns per language.
- if (module_exists('path') && module_exists('pathauto')) {
- // Language for pathauto variables is either node language or default language.
- $language = $node->language ? $node->language : i18n_default_language();
- if ($language != i18n_get_lang()) {
- i18n_variable_init($language, 'pathauto_node');
- }
- }
- break;
-
- case 'delete':
- db_query('DELETE FROM {i18n_node} WHERE nid=%d', $node->nid);
- break;
+function i18n_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
+ global $language;
- case 'prepare':
- // Book pages, set the right language nodes and outlines.
- if (arg(3) == 'parent' && is_numeric(arg(4)) && ($parent = node_load(arg(4))) && $parent->language) {
- $node->language = $parent->language;
- i18n_selection_mode('node', $parent->language);
- }
- break;
- }
+ if (variable_get('language_content_type_' . $node->type, 0)) {
+ // Set current language for new nodes if option enabled
+ if ($op == 'prepare' && empty($node->nid) && empty($node->language) && variable_get('i18n_newnode_current_' . $node->type, 0)) {
+ $node->language = $language->language;
+ }
}
-}*/
+}
/**
* Implementation of hook_alter_translation_link().
// Check for a node related path, and for its translations.
if ((preg_match("!^node/([0-9]+)(/.+|)$!", $path, $matches)) && ($node = node_load((int)$matches[1])) && !empty($node->tnid)) {
- $languages = language_list();
- $extended = array();
- foreach (translation_node_get_translations($node->tnid) as $langcode => $translation_node) {
- if (!isset($links[$langcode]) && isset($languages[$langcode])) {
- $extended[$langcode] = array(
- 'href' => 'node/'. $translation_node->nid . $matches[2],
- 'language' => $language,
- 'language_icon' => $languages[$langcode],
- 'title' => $languages[$langcode]->native,
- 'attributes' => array('class' => 'language-link'),
- );
+ // make sure language support is set to LANGUAGE_SUPPORT_EXTENDED, so links
+ // dont get added for LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED
+ if (variable_get('i18n_node_'. $node->type, LANGUAGE_SUPPORT_NORMAL) == LANGUAGE_SUPPORT_EXTENDED) {
+ $languages = language_list();
+ $extended = array();
+ foreach (translation_node_get_translations($node->tnid) as $langcode => $translation_node) {
+ if (!isset($links[$langcode]) && isset($languages[$langcode])) {
+ $extended[$langcode] = array(
+ 'href' => 'node/'. $translation_node->nid . $matches[2],
+ 'language' => $language,
+ 'language_icon' => $languages[$langcode],
+ 'title' => $languages[$langcode]->native,
+ 'attributes' => array('class' => 'language-link'),
+ );
+ }
}
+ // This will run after languageicon module, so we add icon in case that one is enabled.
+ if ($extended && function_exists('languageicons_translation_link_alter')) {
+ languageicons_translation_link_alter($extended, $path);
+ }
+ $links = array_merge($links, $extended);
}
- // This will run after languageicon module, so we add icon in case that one is enabled.
- if ($extended && function_exists('languageicons_translation_link_alter')) {
- languageicons_translation_link_alter($extended, $path);
- }
- $links = array_merge($links, $extended);
}
}
function i18n_link_alter(&$links, $node) {
global $language;
- if ($node->tnid) {
+ $language_support = variable_get('i18n_node_'. $node->type, LANGUAGE_SUPPORT_NORMAL);
+
+ // Hide node translation links.
+ if (variable_get('i18n_hide_translation_links', 0) == 1) {
+ foreach ($links as $module => $link) {
+ if (strpos($module, 'node_translation') === 0) {
+ unset($links[$module]);
+ }
+ }
+ }
+
+ if (!empty($node->tnid)) {
foreach (array_keys(i18n_language_list('extended')) as $langcode) {
$index = 'node_translation_'. $langcode;
if (!empty($links[$index])) {
- $links[$index]['language'] = $language;
+ if ($language_support != LANGUAGE_SUPPORT_EXTENDED && $links[$index]['language']->enabled == 0) {
+ unset($links[$index]);
+ }
+ else {
+ $links[$index]['language'] = $language;
+ }
}
}
}
*/
function i18n_user($op, &$edit, &$account, $category = NULL) {
if ($op == 'login' && $account->language) {
- $_SESSION['language'] = $account->language;
i18n_get_lang($account->language);
}
}
/**
+ * Implementation of hook_elements().
+ *
+ * Add a process callback for textfields.
+ */
+function i18n_elements() {
+ $type = array();
+ $type['textfield'] = array('#process' => array('i18n_textfield_process'));
+ return $type;
+}
+
+/**
+ * Process callback for textfield elements.
+ *
+ * When editing or translating a node, set Javascript to rewrite autocomplete
+ * paths to use the node language prefix rather than the current content one.
+ */
+function i18n_textfield_process($element) {
+ global $language;
+ static $sent = FALSE;
+
+ // Ensure we send the Javascript only once.
+ if (!$sent && isset($element['#autocomplete_path']) && !empty($element['#autocomplete_path']) && variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE) != LANGUAGE_NEGOTIATION_NONE) {
+ // Add a JS file for node forms.
+ // Determine if we are either editing or translating an existing node.
+ // We can't act on regular node creation because we don't have a specified
+ // node language.
+ $node_edit = $node = menu_get_object() && arg(2) == 'edit' && isset($node->language) && !empty($node->language);
+ $node_translate = arg(0) == 'node' && arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language']);
+ if ($node_edit || $node_translate) {
+ $node_language = $node_edit ? $node->language : $_GET['language'];
+ // Only needed if the node language is different from the interface one.
+ if ($node_language != $language->language) {
+ $languages = language_list();
+ if (isset($languages[$node_language])) {
+ drupal_add_js(drupal_get_path('module', 'i18n') . '/i18n.js');
+ // Pass the interface and content language base paths.
+ // Remove any trailing forward slash. Doing so prevents a mismatch
+ // that occurs when a language has no prefix and hence gets a path
+ // with a trailing forward slash.
+ $interface = rtrim(url('', array('absolute' => TRUE)), '/');
+ $content = rtrim(url('', array('absolute' => TRUE, 'language' => $languages[$node_language])), '/');
+ $data = array('interface_path' => $interface, 'content_path' => $content);
+ drupal_add_js(array('i18n' => $data), 'setting');
+ }
+ }
+ }
+ $sent = TRUE;
+ }
+ return $element;
+}
+
+/**
* Simple i18n API
*/
function i18n_node_language_list($node, $translate = FALSE) {
// Check if the node module manages its own language list.
$languages = node_invoke($node, 'language_list', $translate);
+
if (!$languages) {
- if (variable_get('i18n_node_'. $node->type, 0) == LANGUAGE_SUPPORT_EXTENDED) {
+ if (variable_get('i18n_node_'. $node->type, 0) >= LANGUAGE_SUPPORT_EXTENDED) {
$languages = locale_language_list('name', TRUE); // All defined languages
}
else {
unset($languages[$langcode]);
}
}
- $languages = array('' => t('Language neutral')) + $languages;
+ // Language may be locked for this node type, restrict options to current one
+ if (variable_get('i18n_lock_node_' . $node->type, 0) && !empty($node->language) && !empty($languages[$node->language])) {
+ $languages = array($node->language => $languages[$node->language]);
+ }
+ // Check language required for this type (no language neutral)
+ elseif (!variable_get('i18n_required_node_' . $node->type, 0)) {
+ $languages = array('' => t('Language neutral')) + $languages;
+ }
}
return $languages;
}
/**
- * Function i18n_get_links().
- *
- * Returns an array of links for all languages, with or without names/flags.
- *
- * @param $path
- * Drupal internal path.
- * @param $query
- * Query string.
- * @param $names
- * Names to use for the links. Defaults to native language names.
- */
-function i18n_get_links($path = '', $query = NULL, $names = NULL) {
- if ($path == variable_get('site_frontpage', 'node')) {
- $path = '';
- }
- $names = $names ? $names : locale_language_list('native');
- foreach (array_keys(i18n_supported_languages()) as $lang) {
- $links[$lang] = theme('i18n_link', $names[$lang], i18n_path($path, $lang), $lang, $query);
- }
- return $links;
-}
-
-/**
* Selection mode for content.
*
* Warning: when used with params they need to be escaped, as some values are thrown directly in queries.
* custom = add custom where clause, like "%alias.language = 'en'".
*/
function i18n_selection_mode($mode = NULL, $params = NULL) {
- static $current_mode = NULL;
+ static $current_mode;
static $current_value = '';
static $store = array();
- // Initialization, first time this runs with no explicit mode.
- if (!$current_mode && !$mode) {
+ // Initialization, first time this runs
+ if (!isset($current_mode)) {
$current_mode = variable_get('i18n_selection_mode', 'simple');
- if ($current_mode != 'off') {
- // Node language when loading specific nodes or creating translations.
- if (arg(0) == 'node' ) {
- if (($node = menu_get_object('node')) && $node->language) {
- $current_mode = 'node';
- $current_value = $node->language;
- }
- elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language']) && empty($_POST)) {
- $current_mode = 'translation';
- $current_value = db_escape_string($_GET['language']);
- }
- }
- elseif (arg(0) == 'admin') {
- // There are some exceptions for admin pages.
- if (arg(1) == 'content' && user_access('administer all languages')) {
- // No restrictions for administration pages.
- $current_mode = 'off';
- }
- elseif (arg(1) == 'build' && arg(2) == 'menu-customize') {
- // All nodes available when editing custom menu items.
- $current_mode = 'off';
- }
- }
- }
}
if (!$mode) {
// Mixed mode is a bit more complex, we need to join in one more table
// and add some more conditions, but only if language is not default.
- if ($mode == 'mixed' && i18n_get_lang() != i18n_default_language()) {
- $result['join'] = "LEFT JOIN {node} i18n ON $primary_table.tnid = i18n.tnid AND i18n.language = '". i18n_get_lang() ."'";
+ if ($mode == 'mixed') {
$result['where'] = i18n_db_rewrite_where($primary_table, 'node', 'simple');
- // So we show also nodes that have default language.
- $result['where'] .= " OR ($primary_table.language = '". i18n_default_language() ."' AND i18n.nid IS NULL)";
+ if (i18n_get_lang() != i18n_default_language()) {
+ $result['join'] = "LEFT JOIN {node} i18n ON $primary_table.tnid > 0 AND $primary_table.tnid = i18n.tnid AND i18n.language = '". i18n_get_lang() ."'";
+ // So we show also nodes that have default language.
+ $result['where'] .= " OR $primary_table.language = '". i18n_default_language() ."' AND i18n.nid IS NULL";
+ }
}
else {
$result['where'] = i18n_db_rewrite_where($primary_table, 'node', $mode);
}
/**
+ * Implementation of hook_preprocess_page().
+ *
+ * Add the language code to the classes for the <body> tag. Unfortunately, some
+ * themes will not respect the variable we're modifying to achieve this - in
+ * particular, Garland and Minelli do not.
+ */
+function i18n_preprocess_page(&$variables) {
+ if (isset($variables['body_classes'])) {
+ global $language;
+ $variables['body_classes'] .= ' i18n-' . $language->language;
+ }
+}
+
+/**
* Implementation of hook_exit().
*/
function i18n_exit() {
* This is the place to add language fields to all forms.
*/
function i18n_form_alter(&$form, $form_state, $form_id) {
+ global $language;
+
switch ($form_id) {
case 'node_type_form':
+ $disabled = !variable_get('language_content_type_'. $form['#node_type']->type, 0);
+ $form['i18n'] = array(
+ '#type' => 'fieldset',
+ '#title' => t('Multilanguage options'),
+ '#collapsible' => TRUE,
+ '#collapsed' => TRUE,
+ '#description' => t('Extended multilingual options provided by Internationalization module.'),
+ '#disabled' => $disabled,
+ );
+ // Add disabled message
+ if ($disabled) {
+ $form['i18n']['#description'] .= ' <em>' . t('These will be available only when you enable Multilingual support in Workflow settings above.') . '</em>';
+ }
+ // Some settings about node languages
+ $form['i18n']['options'] = array(
+ '#title' => t('Options for node language'),
+ '#type' => 'fieldset',
+ '#disabled' => $disabled,
+ );
+ $form['i18n']['options']['i18n_newnode_current'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Set current language as default for new content.'),
+ '#default_value' => variable_get('i18n_newnode_current_' . $form['#node_type']->type, 0),
+ '#disabled' => $disabled,
+ );
+ $form['i18n']['options']['i18n_required_node'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Require language (Do not allow Language Neutral).'),
+ '#default_value' => variable_get('i18n_required_node_' . $form['#node_type']->type, 0),
+ '#disabled' => $disabled,
+ );
+ $form['i18n']['options']['i18n_lock_node'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Lock language (Cannot be changed).'),
+ '#default_value' => variable_get('i18n_lock_node_' . $form['#node_type']->type, 0),
+ '#disabled' => $disabled,
+ );
// Add extended language support option to content type form.
- $form['workflow']['i18n_node'] = array(
+ $form['i18n']['i18n_node'] = array(
'#type' => 'radios',
'#title' => t('Extended language support'),
'#default_value' => variable_get('i18n_node_'. $form['#node_type']->type, LANGUAGE_SUPPORT_NORMAL),
'#options' => _i18n_content_language_options(),
- '#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.')
+ '#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.'),
+ '#disabled' => $disabled,
);
break;
default:
- // Extended language for node edit form.
+ // Extensions for node edit forms
if (isset($form['#id']) && $form['#id'] == 'node-form') {
- if (isset($form['#node']->type) && variable_get('language_content_type_'. $form['#node']->type, 0)) {
- $form['language']['#options'] = i18n_node_language_list($form['#node'], TRUE);
- }
- }
- /** @ TO DO Upgrade
- if (isset($form['type']) && $form['type']['#value'] .'_node_form' == $form_id && $node = $form['#node']) {
- // Language field
- if (variable_get('i18n_node_'.$form['type']['#value'], 0) && !isset($form['i18n']['language'])) {
- // Language field
- $form['i18n'] = array(
- '#type' => 'fieldset',
- '#title' => t('Multilingual settings'),
- '#collapsible' => TRUE,
- '#collapsed' => FALSE,
- '#weight' => -4
- );
- // Language will default to current only when creating a node.
- $language = isset($form['#node']->language) ? $form['#node']->language : (arg(1)=='add' ? i18n_get_lang() : '');
- $form['i18n']['language'] = _i18n_language_select($language, t('If you change the language, you must click on <i>Preview</i> to get the right categories & terms for that language.'), -4, i18n_node_language_list($node));
- $form['i18n']['trid'] = array(
- '#type' => 'value',
- '#value' => $form['#node']->trid
- );
- }
- // Correction for lang/node/nid aliases generated by path module.
- // if ($form['#node']->path && $form['#node']->path == i18n_get_lang().'/node/'.$form['#node']->nid) {
- if ($node->path) {
- $alias = drupal_lookup_path('alias', 'node/'.$node->nid);
- if($alias && $alias != 'node/'.$node->nid) {
- $form['#node']->path = $alias;
+ if (isset($form['#node']->type)) {
+ if (variable_get('language_content_type_'. $form['#node']->type, 0)) {
+ if (!empty($form['language']['#options'])) {
+ $form['language']['#options'] = i18n_node_language_list($form['#node'], TRUE);
+ }
}
- else {
- unset($form['#node']->path);
+ elseif (!isset($form['#node']->nid)) {
+ // Set language to empty for not multilingual nodes when creating
+ $form['language'] = array('#type' => 'value', '#value' => '');
}
}
}
- */
+
// Multilingual variables in settings form.
- if (isset($form['#theme']) && $form['#theme'] == 'system_settings_form' && $variables = variable_get('i18n_variables', 0)) {
- if (i18n_form_alter_settings($form, $variables)) {
- $form['#submit'][] = 'i18n_variable_form_submit';
+ if (isset($form['#theme']) && $form['#theme'] == 'system_settings_form' && $variables = i18n_variable()) {
+ if ($i18n_variables = i18n_form_alter_settings($form, $variables)) {
+ array_unshift($form['#submit'], 'i18n_variable_form_submit');
+ $form['#i18n_variables'] = $i18n_variables;
}
}
}
* - administer all languages
* Disables language conditions for administration pages, so the user can view objects for all languages at the same time.
* This applies for: menu items, taxonomy
+ * - administer translations
+ * Will allow to add/remove existing nodes to/from translation sets.
*/
function i18n_perm() {
- return array('administer all languages');
+ return array('administer all languages', 'administer translations');
+}
+
+/**
+ * Implementation of hook_theme().
+ */
+function i18n_theme() {
+ return array(
+ 'i18n_node_select_translation' => array(
+ 'arguments' => array('element' => NULL),
+ 'file' => 'i18n.pages.inc',
+ ),
+ );
}
/**
* Check for multilingual variables in form.
*/
function i18n_form_alter_settings(&$form, &$variables) {
- $result = 0;
+ $result = array();
foreach (element_children($form) as $field) {
- if (isset($form[$field]['#type']) && $form[$field]['#type'] == 'fieldset') {
+ if (count(element_children($form[$field])) && empty($form[$field]['#tree'])) {
$result += i18n_form_alter_settings($form[$field], $variables);
}
elseif (in_array($field, $variables)) {
+ // Add form field class: i18n-variable
+ $form[$field]['#attributes']['class'] = !empty($form[$field]['#attributes']['class']) ? $form[$field]['#attributes']['class'] . ' i18n-variable' : 'i18n-variable';
+ $form[$field]['#description'] = !empty($form[$field]['#description']) ? $form[$field]['#description'] : '';
$form[$field]['#description'] .= ' <strong>'. t('This is a multilingual variable.') .'</strong>';
- $result++;
+ // Addd field => name to result
+ $result[$field] = !empty($form[$field]['#title']) ? $form[$field]['#title'] : $field;
}
}
return $result;
*/
function i18n_variable_form_submit($form, &$form_state) {
$op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
- $variables = variable_get('i18n_variables', array());
+ $variables = i18n_variable();
$language = i18n_get_lang();
+ $is_default = $language == language_default('language');
foreach ($form_state['values'] as $key => $value) {
- if (in_array($key, $variables)) {
+ if (i18n_variable($key)) {
if ($op == t('Reset to defaults')) {
i18n_variable_del($key, $language);
}
}
i18n_variable_set($key, $value, $language);
}
- unset($form_state['values'][$key]);
+ // If current is default language, we allow global (without language) variables to be set too
+ if (!$is_default) {
+ unset($form_state['values'][$key]);
+ }
}
}
- // Re-submit form
- // system_settings_form_submit($form_id, $form_values);
+ // The form will go now through system_settings_form_submit()
}
/**
* Initialization of multilingual variables.
*
- * @param $language
+ * @param $langcode
* Language to retrieve variables. Defaults to current language.
- * @param $prefix
- * Variable name prefix to load just a selected group of variables.
*/
-function i18n_variable_init($langcode = NULL, $prefix = '') {
+function i18n_variable_init($langcode = NULL) {
global $conf;
- global $i18n_conf;
$langcode = $langcode ? $langcode : i18n_get_lang();
- if ($i18n_variables = variable_get('i18n_variables', '')) {
- if (!$i18n_conf) {
- $i18n_conf = array();
+ if ($variables = _i18n_variable_init($langcode)) {
+ $conf = array_merge($conf, $variables);
+ }
+}
+
+/**
+ * Get language from context.
+ */
+function _i18n_get_context_lang() {
+ // Node language when loading specific nodes or creating translations.
+ if (arg(0) == 'node' ) {
+ if (($node = menu_get_object('node')) && $node->language) {
+ return $node->language;
}
- $variables = _i18n_variable_init($langcode, $prefix);
- foreach ($i18n_variables as $name) {
- $i18n_conf[$name] = isset($variables[$name]) ? $variables[$name] : (isset($conf[$name]) ? $conf[$name] : '');
+ elseif (arg(1) == 'add' && !empty($_GET['translation']) && !empty($_GET['language'])) {
+ return $_GET['language'];
}
-
- $conf = array_merge($conf, $i18n_conf);
}
}
/**
* Load language variables into array.
*/
-function _i18n_variable_init($language, $prefix = '') {
- $variables = array();
- $cacheid = 'variables:'. $language . ($prefix ? ':'. $prefix : '');
- if ($cached = cache_get($cacheid)) {
- $variables = $cached->data;
- }
- else {
- $result = db_query("SELECT * FROM {i18n_variable} WHERE language='%s' AND name LIKE '%s%'", $language, $prefix);
- while ($variable = db_fetch_object($result)) {
- $variables[$variable->name] = unserialize($variable->value);
+function _i18n_variable_init($langcode) {
+ global $i18n_conf;
+
+ if (!isset($i18n_conf[$langcode])) {
+ $cacheid = 'variables:'. $langcode;
+ if ($cached = cache_get($cacheid)) {
+ $i18n_conf[$langcode] = $cached->data;
+ }
+ else {
+ $result = db_query("SELECT * FROM {i18n_variable} WHERE language = '%s'", $langcode);
+ $i18n_conf[$langcode] = array();
+ while ($variable = db_fetch_object($result)) {
+ $i18n_conf[$langcode][$variable->name] = unserialize($variable->value);
+ }
+ cache_set($cacheid, $i18n_conf[$langcode]);
}
- cache_set($cacheid, $variables);
}
- return $variables;
+
+ return $i18n_conf[$langcode];
}
/**
* Save multilingual variables that may have been changed by other methods than settings pages.
*/
function _i18n_variable_exit() {
- global $i18n_conf;
- global $conf;
- if ($i18n_conf) {
- $lang = i18n_get_lang();
+ global $conf, $i18n_conf;
+
+ $langcode = i18n_get_lang();
+ if (isset($i18n_conf[$langcode])) {
$refresh = FALSE;
// Rewritten because array_diff_assoc may fail with array variables.
- foreach ($i18n_conf as $name => $value) {
- if ($value != $conf[$name]) {
+ foreach (i18n_variable() as $name) {
+ if (isset($conf[$name]) && isset($i18n_conf[$langcode][$name]) && $conf[$name] != $i18n_conf[$langcode][$name]) {
$refresh = TRUE;
- $i18n_conf[$name] = $conf[$name];
- db_query("DELETE FROM {i18n_variable} WHERE name='%s' AND language='%s'", $name, $lang );
- db_query("INSERT INTO {i18n_variable} (language, name, value) VALUES('%s', '%s', '%s')", $lang, $name, serialize($conf[$name]));
+ $i18n_conf[$langcode][$name] = $conf[$name];
+ db_query("DELETE FROM {i18n_variable} WHERE name='%s' AND language='%s'", $name, $langcode);
+ db_query("INSERT INTO {i18n_variable} (language, name, value) VALUES('%s', '%s', '%s')", $langcode, $name, serialize($conf[$name]));
}
}
if ($refresh) {
- cache_set('variables:'. $lang, $i18n_conf);
+ cache_set('variables:'. $langcode, $i18n_conf[$langcode]);
}
}
}
/**
- * Check whether we are in bootstrap mode
+ * Check whether we are in bootstrap mode.
*/
function _i18n_is_bootstrap() {
return !function_exists('drupal_get_headers');
}
/**
- * Drupal 6, backwards compatibility layer
+ * Drupal 6, backwards compatibility layer.
+ *
* @ TO DO Fully upgrade all the modules and remove
*/
*/
/**
- * Returns language lists
+ * Returns language lists.
*/
function i18n_language_list($type = 'enabled', $field = 'name') {
switch ($type) {
}
/**
+ * Get list of multilingual variables or check whether a variable is multilingual
+ */
+function i18n_variable($name = NULL) {
+ $variables = variable_get('i18n_variables', array());
+ return $name ? in_array($name, $variables) : $variables;
+}
+
+/**
* Set a persistent language dependent variable.
*
* @param $name
function i18n_variable_set($name, $value, $langcode) {
global $conf, $i18n_conf;
- db_lock_table('i18n_variable');
- db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
- db_query("INSERT INTO {i18n_variable} (name, language, value) VALUES ('%s', '%s', '%s')", $name, $langcode, serialize($value));
- db_unlock_tables();
-
+ $serialized_value = serialize($value);
+ db_query("UPDATE {i18n_variable} SET value = '%s' WHERE name = '%s' AND language = '%s'", $serialized_value, $name, $langcode);
+ if (!db_affected_rows()) {
+ @db_query("INSERT INTO {i18n_variable} (name, language, value) VALUES ('%s', '%s', '%s')", $name, $langcode, $serialized_value);
+ }
cache_clear_all('variables:'. $langcode, 'cache');
+ $i18n_conf[$langcode][$name] = $value;
+ if ($langcode == i18n_get_lang()) {
+ $conf[$name] = $value;
+ }
+}
- $conf[$name] = $value;
- $i18n_conf[$name] = $value;
+/**
+ * Get single multilingual variable
+ */
+function i18n_variable_get($name, $langcode, $default = NULL) {
+ if ($variables = _i18n_variable_init($langcode)) {
+ return isset($variables[$name]) ? $variables[$name] : $default;
+ }
+ else {
+ return $default;
+ }
}
/**
* @param $name
* The name of the variable to undefine.
* @param $langcode
- * Language code.
+ * Optional language code. If not set it will delete the variable for all languages.
*/
-function i18n_variable_del($name, $langcode) {
+function i18n_variable_del($name, $langcode = NULL) {
global $conf, $i18n_conf;
- db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
- cache_clear_all('variables:'. $langcode, 'cache');
-
- unset($conf[$name]);
- unset($i18n_conf[$name]);
+ if ($langcode) {
+ db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $langcode);
+ cache_clear_all('variables:'. $langcode, 'cache');
+ unset($i18n_conf[$langcode][$name]);
+ // If current language, unset also global conf
+ if ($langcode == i18n_get_lang()) {
+ unset($conf[$name]);
+ }
+ }
+ else {
+ db_query("DELETE FROM {i18n_variable} WHERE name = '%s'", $name);
+ if (db_affected_rows()) {
+ cache_clear_all('variables:', 'cache', TRUE);
+ if (is_array($i18n_conf)) {
+ foreach (array_keys($i18n_conf) as $lang) {
+ unset($i18n_conf[$lang][$name]);
+ }
+ }
+ }
+ }
}
/**
function _i18n_content_language_options() {
return array(
LANGUAGE_SUPPORT_NORMAL => t('Normal - All enabled languages will be allowed.'),
- LANGUAGE_SUPPORT_EXTENDED => t('Extended - All defined languages will be allowed.')
+ LANGUAGE_SUPPORT_EXTENDED => t('Extended - All defined languages will be allowed.'),
+ LANGUAGE_SUPPORT_EXTENDED_NOT_DISPLAYED => t('Extended, but not displayed - All defined languages will be allowed for input, but not displayed in links.'),
);
}