uid && $user->language && array_key_exists($user->language,$languages)) { $i18n_lang = $user->language; } elseif (variable_get("i18n_browser",0) && $lang = i18n_get_browser_lang()) { $i18n_lang=$lang; } else { $i18n_lang= i18n_default_language(); } return $i18n_lang; } } /** * Minimum initialization */ if (!function_exists('_i18n_init')) { function _i18n_init(){ global $i18n_langpath; $path = _i18n_get_original_path(); $i18n_langpath = i18n_get_lang_prefix($path); } } /** * Language block * * This is a simple language switcher which knows nothing about translations */ function i18n_block($op = 'list', $delta = 0) { if ($op == 'list') { $blocks[0]['info'] = t('Language switcher (Interface only)'); } elseif($op == 'view') { $blocks['subject'] = t('Languages'); $query = drupal_query_string_encode($_GET, array('q')); $blocks['content'] = theme('item_list', i18n_get_links($_GET['q'], empty($query) ? NULL : $query)); } return $blocks; } /** * Implementation of hook_init() * * May do a redirect from home page for not to get wrong versions in cache * Warning: when in bootstrap mode, this may be called before i18n_get_lang() */ function i18n_init(){ global $i18n_langpath; // If not in bootstrap, variable init. This may go before the rest of the code because some variables may need to be loaded if(!_i18n_is_bootstrap()){ //include drupal_get_path('module', 'i18n').'/i18n.inc'; i18n_variable_init(); } $lang = i18n_get_lang(); $path = _i18n_get_original_path(); // Init selection mode i18n_selection_mode(variable_get('i18n_selection_mode', 'simple')); // Multi tables, for backwards compatibility and experimentation _i18n_set_db_prefix($lang); if ($path == '') { // Main page // Check for update or cron scripts to disable rewriting and redirection if(preg_match('|/(?!index\.php)\w+\.php|', request_uri())){ i18n_selection_mode('off'); } elseif ($lang != i18n_default_language()) { // Redirect to main page in $lang when it's not default language. _i18n_goto($lang); } else { $_GET['q'] = i18n_frontpage($lang); } } elseif ($lang == $path) { // When path is only language code $_GET['q'] = i18n_frontpage($lang); } elseif ($i18n_langpath) { //search alias with and without lang and remove lang. $_GET['q'] = i18n_get_normal_path($path); } } /** * Implementation of hook_help(). */ function i18n_help($section = 'admin/help#i18n' ) { switch ($section) { case 'admin/help#i18n' : $output = '

'.t('This module provides support for multilingual content in Drupal sites:').'

'; $output .= ''; $output .= '

'. t('For more information please read the on-line help pages.', array('@i18n' =>'http://drupal.org/node/133977')) .'

'; return $output; case 'admin/settings/i18n': $output .= '

'.t('To enable multilingual support for specific content types go to !configure_content_types.', array('!configure_content_types' => l(t('configure content types'), 'admin/content/types'), )).'

'; return $output; } } /** * Implementation of hook_menu(). * Modify rewriting conditions when viewing specific nodes */ function i18n_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array( 'path' => 'admin/settings/i18n', 'title' => t('Multilingual system'), 'description' => t('Configure multilingual content and translation.'), 'callback' => 'drupal_get_form', 'callback arguments' => array('i18n_admin_settings'), 'access' => user_access('administer site configuration'), ); $items[] = array( 'path' => 'admin/settings/i18n/main', 'title' => t('Internationalization'), 'type' => MENU_DEFAULT_LOCAL_TASK ); $items[] = array('path' => 'admin/settings/i18n/language', 'title' => t('Manage languages'), 'description' => t('Configure languages.'), 'callback' => 'locale_admin_manage', 'type' => MENU_LOCAL_TASK); } else { if (arg(0) == 'node') { if(isset($_POST['language']) && $_POST['language']) { $language = $_POST['language']; } elseif( is_numeric(arg(1)) && $node = node_load(arg(1)) ) { // Node language when loading specific nodes $language = $node->language; } if($language) i18n_selection_mode('node', db_escape_string($language)); } elseif(arg(0) == 'admin' && arg(0) == 'content' && user_access('administer all languages')) { // No restrictions for administration pages i18n_selection_mode('off'); } } 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; 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; } } } /** * Implementation of hook_taxonomy * * $edit parameter may be an array or an object !! */ function i18n_taxonomy($op, $type, $edit = NULL) { $edit = (array)$edit; switch ("$type/$op") { case 'term/insert': case 'term/update': $language = isset($edit['language']) ? $edit['language'] : ''; db_query("UPDATE {term_data} SET language='%s' WHERE tid=%d", $language, $edit['tid']); break; case 'vocabulary/insert': case 'vocabulary/update': $language = isset($edit['language']) ? $edit['language'] : ''; db_query("UPDATE {vocabulary} SET language='%s' WHERE vid=%d", $language, $edit['vid']); if ($language && $op == 'update') { db_query("UPDATE {term_data} SET language='%s' WHERE vid=%d", $edit['language'], $edit['vid']); drupal_set_message(t('Reset language for all terms.')); } break; } } /** * Implementation of hook_user() * * Switch to user's language after login */ function i18n_user($op, &$edit, &$account, $category = NULL) { if($op == 'login' && $account->language) { $_SESSION['language'] = $account->language; i18n_get_lang($account->language); } } /** * Form builder function. * * Some options have been removed from previous versions: * - Languages are now taken from locale module unless defined in settings file * - Language dependent tables are authomatically used if defined in settings file */ function i18n_admin_settings() { // Check languages $languages = variable_get('i18n_languages', array()); if (!count($languages) || ! count($languages['active']) > 1 ) { drupal_set_message(t('No languages enabled. Visit the !locale_admin page to set up your languages.', array('!locale_admin' => l(t('Manage languages'), 'admin/settings/locale/'))), 'error'); } $form['i18n_browser'] = array( '#type' => 'radios', '#title' => t('Browser language detection'), '#default_value' => variable_get('i18n_browser', 0), '#options' => array(t('Disabled'), t('Enabled' )), '#description' => t("User browser language for home page and links without language prefix."), ); // Content selection mode $form['i18n_selection_mode'] = array( '#type' => 'radios', '#title' => t('Content selection mode'), '#default_value' => variable_get('i18n_selection_mode', 'simple'), '#options' => _i18n_selection_mode(), '#description' => t('Determines which content to show depending on the current page language and the default language of the site.'), ); // Language icons $form['icons'] = array( '#type' => 'fieldset', '#title' => t('Language icons settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['icons']['i18n_icon_path'] = array( '#type' => 'textfield', '#title' => t('Language icons path'), '#default_value' => variable_get('i18n_icon_path', drupal_get_path('module', 'i18n').'/flags/*.png'), '#size' => 70, '#maxlength' => 180, '#description' => t('Path for language icons, relative to Drupal installation. \'*\' is a placeholder for language code.'), ); $form['icons']['i18n_icon_size'] = array( '#type' => 'textfield', '#title' => t('Language icons size'), '#default_value' => variable_get('i18n_icon_size', '16x12'), '#size' => 10, '#maxlength' => 10, '#description' => t('Image size for language icons, in the form "width x height".'), ); return system_settings_form($form); } /** * Simple i18n API */ /** * Get localized language list, sort alphabetically * * @param $all * TRUE for all languages, not only enabled */ function i18n_language_list($all = FALSE) { static $languages; $type = $all ? 'name' : 'active'; if(!isset($languages[$type])) { $languages[$type] = array_map('t', i18n_languages($type)); asort($languages[$type]); return $languages[$type]; } return $languages[$type]; } /** * Get list of supported languages * @param $all * TRUE to get all defined languages */ function i18n_supported_languages($all = FALSE) { return i18n_languages($all ? 'name' :'active'); } /** * Returns default language code */ function i18n_default_language(){ return i18n_languages('site_default'); } /** * Check whether language is RTL * * @param $language * Language to check, defaults to current language */ function i18n_language_rtl($language = NULL) { $language = $language ? $language : i18n_get_lang(); return i18n_language_property($language, 'rtl') ? TRUE : FALSE; } /** * Get language properties * * @param $code * Language code * @param $property * It may be 'name', 'native', 'ltr'... */ function i18n_language_property($code, $property = 'native') { $languages = i18n_languages($property); return $languages[$code]; } /** * Get locale languages plus i18n language settings * * @param $key * Data to be returned, defaults to 'active' * 'active' => array of enabled languages with native name * 'enabled' => array of enabled languages with english name * 'name' => all languages defined in locale module with english name * 'site_default' => code of default site language */ function i18n_languages($key = 'active') { static $languages; if (!$languages) { if($languages = variable_get('i18n_languages', 0)) { foreach($languages['name'] as $code => $name) { if($languages['enabled'][$code]) { $languages['active'][$code] = $name; } } } else { // It is possible that languages are not initialized if (function_exists('locale_supported_languages')) { $languages = locale_supported_languages(); } else { // Worst case scenario: locale module not loaded, for cached pages, at least this won't break everything unset($languages); // There's some PHP bug: http://www.zend.com/zend/week/week98.php $languages['name'] = array('en' => 'English'); } $languages['site_default'] = key($languages['name']); $languages['active'] = $languages['name']; $languages['native'] = $languages['name']; } // Sort everything alphabetically asort($languages['name']); asort($languages['active']); asort($languages['native']); } return $key ? $languages[$key] : $languages; } /** * Get language from browser settings, but only if it is a valid language */ function i18n_get_browser_lang() { $languages = i18n_supported_languages(); $exploded_server = explode(";", $_SERVER["HTTP_ACCEPT_LANGUAGE"]); $accept=explode(',', array_shift($exploded_server)); foreach ($accept as $lang) { if(empty($lang)) { continue; } elseif (array_key_exists($lang, $languages)) { return $lang; } elseif (array_key_exists(substr($lang, 0, 2), $languages)) { return substr($lang, 0, 2); } } } /** * Get language code from path. * * @param $path * @param $trim * TRUE to remove language code from $path */ function i18n_get_lang_prefix(&$path, $trim = FALSE) { $exploded_path = explode('/', $path); $maybelang = array_shift($exploded_path); $languages = i18n_languages(); if (array_key_exists($maybelang, $languages)){ if ($trim) { $path = trim(substr($path, strlen($maybelang)),'/'); } return $maybelang; } } /** * Language dependent front page * This function will search for aliases like 'en/home', 'es/home'... */ function i18n_frontpage($lang = NULL) { $lang = $lang ? $lang : _i18n_get_lang(); return i18n_get_normal_path($lang.'/'.variable_get('site_frontpage','node')); } /** * This function is similar to drupal_get_normal_path, but language-aware * Also removes language from path */ function i18n_get_normal_path($path) { $prefix = i18n_get_lang_prefix($path, TRUE); if(!$prefix || _i18n_is_bootstrap()){ // If bootstrap, drupal_lookup_path is not defined return $path; } // First, check alias with lang elseif($alias = drupal_lookup_path('source', $prefix.'/'.$path)){ i18n_get_lang_prefix($alias, TRUE); // In case alias has language return $alias; } // Check alias without lang elseif($alias = drupal_lookup_path('source', $path)){ i18n_get_lang_prefix($alias, TRUE); return $alias; } else { return $path; } } /** * More i18n API */ /** * Produces i18n paths, with language prefix * If path is empty or site frontpage, path = 'lang' * Check for frontpage and search for alias before adding language */ function i18n_path($path, $lang) { if (!$path || $path == i18n_frontpage($lang)) { return $lang; } elseif($alias = drupal_lookup_path('alias', $path)) { if($prefix = i18n_get_lang_prefix($alias)) { // This alias will be valid only if it has the same language return ($prefix == $lang) ? $alias : $lang.'/'.$path; } else { // Alias without language prefix return $lang.'/'.$alias; } } else { // Alias for language path will be searched later return $lang.'/'.$path; } } /** * Get node language */ function i18n_node_get_lang($nid, $default = '') { $lang = db_result(db_query('SELECT language FROM {i18n_node} WHERE nid=%d',$nid)); return $lang ? $lang : $default ; } /** * Get allowed languages for node * * This allows node types to define its own language list implementing hook 'language_list' */ function i18n_node_language_list($node) { if ($languages = node_invoke($node, 'language_list')) { return $languages; // The node module manages its own language list } elseif(variable_get('i18n_node_'.$node->type, 0) == LANGUAGE_SUPPORT_EXTENDED) { return i18n_language_list(TRUE); // All defined languages } else { return i18n_language_list(); // All enabled languages } } /** * Returns main language, two letter code */ function i18n_get_main_lang($lang = NULL){ $lang = $lang ? $lang : i18n_get_lang(); return substr($lang, 2); } /** * 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 == i18n_frontpage()) { $path = ''; } $names = $names ? $names : i18n_languages('native'); foreach (array_keys(i18n_supported_languages()) as $lang){ $links[$lang]= theme('i18n_link', $names[$lang], i18n_path($path, $lang), $lang, $query); } return $links; } /** * Returns list of enabled languages from locale module * * Some code borrowed from locale module. * And yes, if locale enabled, languages are cached twice. But better twice than never ;-) */ function _i18n_locale_supported_languages() { if(function_exists('locale_supported_languages')){ $languages = locale_supported_languages(); return $languages['name']; } else { $result = db_query('SELECT locale, name FROM {locales_meta} WHERE enabled = 1 ORDER BY isdefault DESC, name ASC'); while ($row = db_fetch_object($result)) { $enabled[$row->locale] = $row->name; } return $enabled; } } /** * Emulates drupal_goto, it may not be loaded yet */ function _i18n_goto($lang){ if(!function_exists('drupal_goto')){ require_once './includes/common.inc'; require_once './includes/path.inc'; } drupal_goto($lang); } /** * i18n_selection_mode * * Allows several modes for query rewriting and to change them programatically * off = No language conditions inserted * simple = Only current language and no language * mixed = Only current and default languages * preferred = Current language or else (if available) default language, and no language * strict = Only current language * default = Only default language * user = User defined, in the module's settings page * params = Gets the stored params * reset = Returns to previous * custom = add custom where clause, like "%alias.language = 'en'" */ function i18n_selection_mode($mode= NULL, $params= NULL){ static $current_mode = 'simple'; static $current_value = ''; static $store = array(); if(!$mode) { return $current_mode; } elseif($mode == 'params'){ return $current_value; } elseif($mode == 'reset'){ list($current_mode, $current_value) = array_pop($store); //drupal_set_message("i18n mode reset mode=$current_mode value=$current_value"); } else { array_push($store, array($current_mode, $current_value)); $current_mode = $mode; $current_value = $params; } } // List of selection modes function _i18n_selection_mode(){ return array( // Emphasize the first 2 ones, will be the most preferred. 'simple' => ''.t('Current language and no language').'', 'mixed' => ''.t('Current language (if available) or default language, and no language').'', 'default' => t('Only default language and no language'), 'strict' => t('Only current language'), 'off' => t('All content. No language conditions apply'), ); } // List of language support modes for content function _i18n_content_languages() { return array( LANGUAGE_SUPPORT_NONE => t('Disabled'), LANGUAGE_SUPPORT_NORMAL => t('Normal - All enabled languages will be allowed.'), LANGUAGE_SUPPORT_EXTENDED => t('Extended - All defined languages will be allowed.') ); } /** * @name Themeable functions * @{ */ /** * Produces a language link with the right flag */ function theme_i18n_link($text, $target, $lang, $query= NULL, $fragment = NULL){ $output = ''; $attributes = ($lang == i18n_get_lang()) ? array('class' => 'active') : NULL; $output .= l(theme('i18n_language_icon', $lang), $target, $attributes, $query, $fragment, FALSE, TRUE); $output .= " "; $output .= l($text, $target, $attributes, $query, $fragment, FALSE, TRUE); $output .= ''; return $output; } /** * Theme language icon * * This function can be overridden for no language icons */ function theme_i18n_language_icon($lang){ if ($path = variable_get('i18n_icon_path', drupal_get_path('module', 'i18n').'/flags/*.png')) { $languages = i18n_supported_languages(); $src = base_path().str_replace('*', $lang, $path); list($width, $height) = explode('x', variable_get('i18n_icon_size', '16x12')); $attribs = array('class' => 'i18n-icon', 'width' => $width, 'height' => $height, 'alt' => $languages[$lang]); return ""; } } /* @} */ /** * Implementation of conf_url_rewrite * * This is a conditional definition, just in case it is defined somewhere else. * If so, path rewriting won't work properly but at least it won't break Drupal */ if (!function_exists('custom_url_rewrite')) { function custom_url_rewrite($type, $path, $original) { return i18n_url_rewrite($type, $path, $original); } } /** * Rewrites path with current language and removes prefix if searching for source path */ function i18n_url_rewrite($type, $path, $original){ if ($type == 'alias' && !strpos($path, '://') && !i18n_get_lang_prefix($path)){ return $path ? i18n_get_lang() . '/'. $path : i18n_get_lang(); } elseif ($type == 'source') { if ($path == $original) { return i18n_get_normal_path($path); } else { // Path may have been dealiased but still have language prefix i18n_get_lang_prefix($path, TRUE); return $path; } } else { return $path; } } /** * Implementation of hook_db_rewrite_sql() */ function i18n_db_rewrite_sql($query, $primary_table, $primary_key){ // Some exceptions for query rewrites $mode = i18n_selection_mode(); // drupal_set_message("i18n_db_rewrite mode=$mode query=$query"); if ($mode == 'off') return; // Special case. Selection mode is 'strict' but this should be only for node queries if ($mode == 'strict' && $primary_table != 'n' && $primary_table != 'node') { $mode = 'simple'; } switch ($primary_table) { case 'n': case 'node': case 'nc': // For node_comment table, added in 5.2 // Node queries. // When loading specific nodes, language conditions shouldn't apply if (preg_match("/WHERE.*\s$primary_table.nid\s*=\s*(\d|%d)/", $query)) return; // If language conditions already there, get out if (preg_match("/i18n/", $query)) return; $result['join'] = "LEFT JOIN {i18n_node} i18n ON $primary_table.nid = i18n.nid"; // For 'mixed mode' and nodes we need to join in an aditional table and apply special conditions if ($mode == 'mixed') { $result['where'] = i18n_db_rewrite_where('i18n', 'simple'); if (i18n_get_lang() != i18n_default_language()) { $result['join'] .= " LEFT JOIN {i18n_node} i18n2 ON i18n.trid = i18n2.trid AND i18n2.language = '".i18n_get_lang()."'"; $result['where'] .= " OR (i18n.language = '". i18n_default_language() ."' AND i18n2.nid IS NULL)"; } } else { $result['where'] = i18n_db_rewrite_where('i18n', $mode); } return $result; case 't': case 'v': // Taxonomy queries // When loading specific terms, vocabs, language conditions shouldn't apply if (preg_match("/WHERE.* $primary_table\.tid\s*(=\s*\d|IN)/", $query)) return; // Taxonomy for specific node if (preg_match("/WHERE r\.nid = \%d/", $query)) return; $result['where'] = i18n_db_rewrite_where($primary_table, $mode); return $result; case 'm': // Should not apply for menu administration pages if (arg(0) == 'admin' && arg(1) == 'build' && arg(2) == 'menu') return; // Menu queries. Rewrite mode is always 'simple' to avoid trouble with cache $result['where'] = i18n_db_rewrite_where($primary_table, 'simple'); return $result; } } /** * Rewrites queries depending on rewriting mode */ function i18n_db_rewrite_where($alias, $mode){ // Get languages to simplify query building. $current = i18n_get_lang(); $default = i18n_default_language(); // If mode is mixed but current = default, it is the same as 'simple'. if ($mode == 'mixed' && $current == $default) { $mode = 'simple'; } switch($mode){ case 'simple': return "$alias.language ='$current' OR $alias.language ='' OR $alias.language IS NULL" ; case 'mixed': // This will be only for objects other than nodes return "$alias.language = '$current' OR $alias.language = '$default' OR $alias.language = '' OR $alias.language IS NULL"; case 'strict': return "$alias.language ='$current'" ; case 'node': case 'translation': return "$alias.language ='".i18n_selection_mode('params')."' OR $alias.language ='' OR $alias.language IS NULL" ; case 'default': return "$alias.language ='$default' OR $alias.language ='' OR $alias.language IS NULL" ; case 'custom': return str_replace('%alias', $alias, i18n_selection_mode('params')); } } /** * Implementation of hook_exit */ function i18n_exit(){ _i18n_variable_exit(); } /** * Implementation of hook_form_alter * * This is the place to add language fields to all forms */ function i18n_form_alter($form_id, &$form) { //drupal_set_message("DEBUG: i18n_form_alter form_id=$form_id "); switch($form_id){ case 'taxonomy_overview_vocabularies': $vocabularies = taxonomy_get_vocabularies(); $languages = i18n_supported_languages(); foreach ($vocabularies as $vocabulary) { if($vocabulary->language) $form[$vocabulary->vid]['type']['#value'] = $form[$vocabulary->vid]['type']['#value'].' ('.$languages[$vocabulary->language].')'; } break; case 'taxonomy_form_vocabulary': // Taxonomy vocabulary if(isset($form['vid'])) { $vocabulary = taxonomy_get_vocabulary($form['vid']['#value']); } $form['i18n'] = array('#type' => 'fieldset', '#title' => t('Multilingual options'), '#collapsible' => TRUE, '#weight' => -20); $form['i18n']['language'] = _i18n_language_select(isset($vocabulary) ? $vocabulary->language : i18n_get_lang(),t('This language will be set for all terms in this vocabulary')); break; case 'taxonomy_form_term': // Taxonomy term if(isset($form['tid']) && is_numeric($form['tid']['#value'])) { $term = taxonomy_get_term($form['tid']['#value']); } $form['language'] = _i18n_language_select(isset($term) ? $term->language : i18n_get_lang()); break; case 'node_type_form': $node_type = $form['old_type']['#value']; // Build a fieldset to allow some more options here $form['workflow']['i18n'] = array( '#type' => 'fieldset', '#title' => t('Multilingual options'), ); $form['workflow']['i18n']['i18n_node'] = array( '#type' => 'radios', '#title' => t('Multilingual content'), '#default_value' => variable_get('i18n_node_'.$node_type, 0), '#options' => _i18n_content_languages(), '#description' => t('Enables language field and translations for this content type.'), ); break; case '_locale_admin_manage_screen': // Locale language settings $languages = locale_supported_languages(TRUE, TRUE); $i18nlangs = variable_get('i18n_languages', array()); $form['native'] = array('#tree' => TRUE); foreach ($languages['name'] as $key => $lang) { $options[$key] = ''; $form['native'][$key] = array('#type' => 'textfield', '#default_value' => $i18nlangs['native'][$key] ? $i18nlangs['native'][$key] : $lang, '#size' => 15, '#maxlength' => 64, ); } $form['rtl'] = array( '#type' => 'checkboxes', '#options' => $options, '#default_value' => $i18nlangs['rtl'] ); $form['#base'] = 'i18n_admin_manage_screen'; if(!is_array($form['#submit'])) { $form['#submit'] = array('_locale_admin_manage_screen_submit' => array()); } $form['#submit'] = array('i18n_admin_manage_screen_submit' => array()) + $form['#submit']; break; case 'menu_edit_item_form': if ($mid = $form['mid']['#value']) { $language = db_result(db_query('SELECT language FROM {menu} WHERE mid = %d', $mid)); } else { $language = ''; } $form['language'] = _i18n_language_select($language, t('You can set a language for this menu item.')); $form['#submit'] = array('i18n_menu_edit_item_form_submit' => array()); break; default: // Node edit form 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 Preview 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; } else { unset($form['#node']->path); } } } // Multilingual variables in settings form if ($form['#base'] == 'system_settings_form' && $variables = variable_get('i18n_variables', 0)) { if(i18n_form_alter_settings($form, $variables)) { $form['#submit'] = array('i18n_variable_form_submit' => array()); } } } } /** * Implementation of hook_perm(). * * Permissions defined * - 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 */ function i18n_perm() { return array('administer all languages'); } /** * Implementation of hook_token_values(). */ function i18n_token_values($type, $object = NULL) { $values = array(); switch ($type) { case 'node': case 'taxonomy': $values['lang'] = i18n_node_get_lang($object->nid, ''); break; } return $values; } /** * Implementation of hook_token_list(). */ function i18n_token_list($type = 'all') { $tokens = array(); if ($type == 'node' || $type == 'all') { $tokens['node']['lang'] = t("Language code of the document."); } if ($type == 'taxonomy' || $type == 'all') { $tokens['taxonomy']['lang'] = t("Language code of the document."); } return $tokens; } /** * Process menu and menu item add/edit form submissions. */ function i18n_menu_edit_item_form_submit($form_id, $form_values) { $mid = menu_edit_item_save($form_values); db_query("UPDATE {menu} SET language = '%s' WHERE mid = %d", $form_values['language'], $mid); return 'admin/build/menu'; } /** * Theme the locale admin manager form. */ function theme_i18n_admin_manage_screen($form) { foreach ($form['name'] as $key => $element) { // Do not take form control structures. if (is_array($element) && element_child($key)) { $rows[] = array(check_plain($key), drupal_render($form['name'][$key]), drupal_render($form['native'][$key]), drupal_render($form['enabled'][$key]), drupal_render($form['site_default'][$key]), drupal_render($form['rtl'][$key]),($key != 'en' ? drupal_render($form['translation'][$key]) : t('n/a')), ($key != 'en' ? l(t('delete'), 'admin/settings/locale/language/delete/'. $key) : '')); } } $header = array(array('data' => t('Code')), array('data' => t('English name')), array('data' => t('Native name')), array('data' => t('Enabled')), array('data' => t('Default')), array('data' => t('RTL')), array('data' => t('Translated')), array('data' => t('Operations'))); $output = theme('table', $header, $rows); $output .= drupal_render($form); return $output; } /** * Save language settings in variable */ function i18n_admin_manage_screen_submit($form_id, $form_values) { // Save changes to existing languages. foreach(array('site_default', 'name', 'rtl', 'native', 'enabled') as $key) { $save[$key] = $form_values[$key]; } $save['name']['en'] = 'English'; $languages = locale_supported_languages(FALSE, TRUE); foreach($languages['name'] as $key => $lang) { // Nothing } variable_set('i18n_languages', $save); } /** * Check for multilingual variables in form */ function i18n_form_alter_settings(&$form, &$variables) { $result = 0; foreach(element_children($form) as $field) { if($form[$field]['#type'] == 'fieldset') { $result += i18n_form_alter_settings($form[$field], $variables); } elseif (in_array($field, $variables)) { $form[$field]['#description'] .= ' '.t('This is a multilingual variable.').''; $result++; } } return $result; } /** * Save multilingual variables and remove them from form */ function i18n_variable_form_submit($form_id, $form_values) { $op = isset($form_values['op']) ? $form_values['op'] : ''; $variables = variable_get('i18n_variables', array()); $language = i18n_get_lang(); foreach ($form_values as $key => $value) { if(in_array($key, $variables)) { if ($op == t('Reset to defaults')) { i18n_variable_del($key, $language); } else { if (is_array($value) && isset($form_values['array_filter'])) { $value = array_keys(array_filter($value)); } i18n_variable_set($key, $value, $language); } unset($form_values[$key]); } } // Re-submit form system_settings_form_submit($form_id, $form_values); } /** * Initialization of multilingual variables * * @param $language * 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($language = NULL, $prefix = ''){ global $conf; global $i18n_conf; $language = $language ? $language : _i18n_get_lang(); if($i18n_variables = variable_get('i18n_variables', '')){ if (!$i18n_conf) { $i18n_conf = array(); } $variables = _i18n_variable_init($language, $prefix); foreach($i18n_variables as $name){ $i18n_conf[$name] = isset($variables[$name]) ? $variables[$name] : (isset($conf[$name]) ? $conf[$name] : ''); } $conf = array_merge($conf, $i18n_conf); } } /** * Set a persistent language dependent variable. * * @param $name * The name of the variable to set. * @param $value * The value to set. This can be any PHP data type; these functions take care * of serialization as necessary. */ function i18n_variable_set($name, $value, $language) { global $conf, $i18n_conf; db_lock_table('i18n_variable'); db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $language); db_query("INSERT INTO {i18n_variable} (name, language, value) VALUES ('%s', '%s', '%s')", $name, $language, serialize($value)); db_unlock_tables(); cache_clear_all('variables:'.$language, 'cache'); $conf[$name] = $value; $i18n_conf[$name] = $value; } /** * Unset a persistent multilingual variable. * * @param $name * The name of the variable to undefine. */ function i18n_variable_del($name, $language) { global $conf, $i18n_conf; db_query("DELETE FROM {i18n_variable} WHERE name = '%s' AND language='%s'", $name, $language); cache_clear_all('variables:'.$language, 'cache'); unset($conf[$name]); unset($i18n_conf[$name]); } /** * Helper function to create language selector */ function _i18n_language_select($value ='', $description ='', $weight = -20, $languages = NULL){ $languages = $languages ? $languages : i18n_language_list(); return array( '#type' => 'select', '#title' => t('Language'), '#default_value' => $value, '#options' => array_merge(array('' => ''), $languages), '#description' => $description, '#weight' => $weight, ); } /** * Load language variables into array */ function _i18n_variable_init($language, $prefix = ''){ $variables = array(); $cacheid = 'variables:'.$language.($prefix ? ':'.$prefix : ''); if ($cached = cache_get($cacheid)) { $variables = unserialize($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); } cache_set($cacheid, 'cache', serialize($variables)); } return $variables; } /** * 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(); $refresh = FALSE; // Rewritten because array_diff_assoc may fail with array variables foreach($i18n_conf as $name => $value){ if($value != $conf[$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])); } } if($refresh) { cache_set('variables:'.$lang, 'cache', serialize($i18n_conf)); } } } /** * Check whether we are in bootstrap mode */ function _i18n_is_bootstrap(){ return !function_exists('drupal_get_headers'); } /** * Sets db_prefix to given language */ function _i18n_set_db_prefix($lang) { global $db_prefix, $db_prefix_i18n; if (is_array($db_prefix_i18n)) { $db_prefix = array_merge($db_prefix, str_replace('**', $lang, $db_prefix_i18n)); } } /** * To get the original path. * Cannot use $_GET["q"] cause it may have been already changed */ function _i18n_get_original_path() { return isset($_REQUEST["q"]) ? trim($_REQUEST["q"],"/") : ''; } /** * String handling functions (Object localization) * * These are a set of wrapper functions that will call i18nstrings if enabled * or use plain Drupal core's localization othewise. * * The differences with the default localization system: * - It will translate strings not from English but from the default language * - They're not plain strings, have some context information too */ /** * Translate configurable string, and store for l10n client. * * This is just a wrapper for backwards compatibility. For this function to do something useful * you need to enable i18nstrings module, otherwise it's just a slightly improved t() for i18n. It works * the same but forgets about English and translates when language != default and language == locale * * @param $strid * Textgroup and location glued with ':' * I.e. profile: * @param $default * String in default language. Default language may or may not be English * @param $langcode * Optional language code if different from current request language * @param $update * Whether to update/create the string */ function tt($strid, $default, $language = NULL, $update = FALSE) { global $locale; $language = $language ? $language : $locale; if (function_exists('i18nstrings_tt')) { return i18nstrings_tt($strid, $default, $language, $update); } elseif ($language == i18n_default_language() || $language != $locale) { // We just translate from default language, not to default language return $default; } else { // We cannot call t() here because it won't work for English when not default language return locale($default); } }