--- i18n.module 2007-10-30 19:12:35.000000000 +0200 +++ i18n.module.php 2008-02-25 22:42:48.000000000 +0200 @@ -16,57 +16,66 @@ define('LANGUAGE_SUPPORT_EXTENDED', 2); /** * Module initialization - * + * * Get language from path if exists and Initialize i18n system */ /** * This one expects to be called first from common.inc + * + * @return */ function i18n_get_lang($setlanguage = NULL) { static $i18n_language; - //see if the language is already set. - if ($setlanguage) { + if (($setlanguage = @trim($setlanguage))) { $i18n_language = $setlanguage; - } elseif ($i18n_language) { - return $i18n_language; - } else { + } + elseif (!isset($i18n_language)) { _i18n_init(); - return $i18n_language = _i18n_get_lang(); + $i18n_language = _i18n_get_lang(); } + return $i18n_language; } /** * Minimum initialization + * + * @return void */ function _i18n_init(){ global $i18n_langpath; - $path = _i18n_get_original_path(); - $i18n_langpath = i18n_get_lang_prefix($path); -} + if (!isset($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) { +function i18n_block($op = 'list', $delta = 0, $edit = array()) { if ($op == 'list') { $blocks[0]['info'] = t('Language switcher'); } 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)); + $query = empty($query) ? NULL : $query; + $links = i18n_get_links($_GET['q'], $query); + $blocks['subject'] = t('Languages'); + $blocks['content'] = theme('item_list', $links); } 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() + * + * @return void */ function i18n_init(){ global $i18n_langpath; @@ -86,9 +95,13 @@ function i18n_init(){ _i18n_goto($lang); } else { $_GET['q'] = i18n_frontpage($lang); - } + } } elseif ($lang == $path) { // When path is only language code $_GET['q'] = i18n_frontpage($lang); + if ($lang == i18n_default_language()) { + i18n_get_lang_prefix($path, TRUE); + _i18n_goto($path); + } } elseif ($i18n_langpath) { //search alias with and without lang and remove lang. @@ -97,8 +110,11 @@ function i18n_init(){ // If not in bootstrap, variable init if(!_i18n_is_bootstrap()){ //include drupal_get_path('module', 'i18n').'/i18n.inc'; - i18n_variable_init(); - } + i18n_variable_init(); + } + if (!_i18n_add_lang_prefix($lang) && i18n_get_lang_prefix($path, TRUE)) { + _i18n_goto($path); + } } /** @@ -115,7 +131,7 @@ function i18n_help($section = 'admin/hel $output .= '
'. t('For more information please read the on-line help pages.', array('@i18n' =>'http://drupal.org/node/31631')) .'
'; return $output; @@ -133,24 +149,24 @@ 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'), - ); + '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 - ); + '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 { + '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']; @@ -173,7 +189,7 @@ function i18n_menu($may_cache) { */ function i18n_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { if (variable_get("i18n_node_$node->type", 0)) { - switch ($op) { + 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': @@ -189,13 +205,13 @@ function i18n_nodeapi(&$node, $op, $teas $item['path'] = ($item['path']) ? $item['path'] : "node/$node->nid"; $item['type'] = $item['type'] | MENU_MODIFIED_BY_ADMIN; if ($item['mid']) { - // Update menu item + // 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']))); + 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 @@ -209,7 +225,7 @@ function i18n_nodeapi(&$node, $op, $teas } } break; - case 'delete': + case 'delete': db_query('DELETE FROM {i18n_node} WHERE nid=%d', $node->nid); break; case 'prepare': @@ -217,16 +233,16 @@ function i18n_nodeapi(&$node, $op, $teas 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) { @@ -234,24 +250,24 @@ function i18n_taxonomy($op, $type, $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']); + $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/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; + $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) { @@ -263,64 +279,83 @@ function i18n_user($op, &$edit, &$accoun /** * 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 + * + * @return array + * Drupal Form */ -function i18n_admin_settings() { +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."), + '#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."), ); - + // Language icons $form['icons'] = array( - '#type' => 'fieldset', - '#title' => t('Language icons settings'), - '#collapsible' => TRUE, - '#collapsed' => FALSE, + '#type' => 'fieldset', + '#title' => t('Language icons settings'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, ); $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.'), + '#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".'), + '#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".'), + ); + + // Language prefix + $form['prefix'] = array( + '#type' => 'fieldset', + '#title' => t('Language prefix'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, + '#description' => t('Note: If you wish comparability with navigation mode (without language prefix), when module i18n is disabled, disable settings.'), + ); + $form['prefix']['i18n_prefix_default'] = array( + '#type' => 'radios', + '#title' => t('Language prefix for default language'), + '#default_value' => variable_get('i18n_prefix_default', 0), + '#options' => array(t('Disabled'), t('Enabled' )), + '#description' => t("Add a language prefix to Drupal paths when the current language is the default language. Some established sites or single language sites with default language is not English may wish to disable language prefix of Drupal paths when enabling i18n module."), ); // Advanced options $form['advanced'] = array( - '#type' => 'fieldset', - '#title' => t('Advanced settings'), - '#collapsible' => TRUE, - '#collapsed' => TRUE, + '#type' => 'fieldset', + '#title' => t('Advanced settings'), + '#collapsible' => TRUE, + '#collapsed' => TRUE, ); $form['advanced']['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 language.'), + '#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 language.'), ); - + return system_settings_form($form); } @@ -330,7 +365,7 @@ function i18n_admin_settings() { /** * Get localized language list, sort alphabetically - * + * * @param $all * TRUE for all languages, not only enabled */ @@ -355,15 +390,18 @@ function i18n_supported_languages($all = } /** - * Returns default language + * Returns default language. + * + * @return string + * Default language code. */ function i18n_default_language(){ - return i18n_languages('site_default'); + return i18n_languages('site_default'); } /** * Check whether language is RTL - * + * * @param $language * Language to check, defaults to current language */ @@ -374,9 +412,9 @@ function i18n_language_rtl($language = N /** * Get language properties - * + * * @param $code - * Language code + * Language code. * @param $property * It may be 'name', 'native', 'ltr'... */ @@ -387,7 +425,7 @@ function i18n_language_property($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 @@ -427,59 +465,90 @@ function i18n_languages($key = 'active') /** * Get language from browser settings, but only if it is a valid language + * + * @return string + * Language code. */ 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); + static $browser_lang; + if (!isset($browser_lang)) { + $languages = i18n_supported_languages(); + $exploded_server = explode(";", $_SERVER["HTTP_ACCEPT_LANGUAGE"]); + $accept = explode(',', array_shift($exploded_server)); + $browser_lang = ''; + foreach ($accept as $lang) { + if (($lang = @trim($lang)) && + (array_key_exists(($lang = strtolower($lang)), $languages) + || array_key_exists(($lang = substr($lang, 0, 2)), $languages))) { + $browser_lang = $lang; + break; + } } } + return $browser_lang; } /** * Get language code from path. * * @param $path + * Drupal path. * @param $trim - * TRUE to remove language code from $path + * TRUE to remove language code from $path. + * + * @return string + * Language code. */ function i18n_get_lang_prefix(&$path, $trim = FALSE) { $exploded_path = explode('/', $path); - $maybelang = array_shift($exploded_path); + $maybelang = @strtolower(array_shift($exploded_path)); $languages = i18n_languages(); - if (array_key_exists($maybelang, $languages)){ - if ($trim) { - $path = trim(substr($path, strlen($maybelang)),'/'); - } - return $maybelang; + if (!array_key_exists($maybelang, $languages)){ + $maybelang = ''; // NO Language code. + } elseif ($trim) { + $path = substr($path, strlen($maybelang) + 1); } + return $maybelang; } /** * Language dependent front page - * This function will search for aliases like 'en/home', 'es/home'... + * This function will search for aliases like 'en/home', 'es/home'..., + * but for default language return aliase without prefix + * + * @param string [optional] $lang + * ISO 639 language code. + * + * @return string + * Language dependent path of front page. */ function i18n_frontpage($lang = NULL) { - $lang = $lang ? $lang : _i18n_get_lang(); - return i18n_get_normal_path($lang.'/'.variable_get('site_frontpage','node')); + static $paths = array(); + $lang = $lang ? strtolower(@trim($lang)) : _i18n_get_lang(); + if (!isset($paths[$lang])) { + $path = _i18n_add_lang_prefix($lang) + ? $lang.'/'.variable_get('site_frontpage','node') + : variable_get('site_frontpage','node'); + $paths[$lang] = i18n_get_normal_path($path); + } + return $paths[$lang]; } /** * This function is similar to drupal_get_normal_path, but language-aware * Also removes language from path + * + * @param string $path + * Drupal path. + * + * @return string + * Drupal 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; + 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 @@ -488,7 +557,7 @@ function i18n_get_normal_path($path) { elseif($alias = drupal_lookup_path('source', $path)){ i18n_get_lang_prefix($alias, TRUE); return $alias; - } + } else { return $path; } @@ -502,20 +571,26 @@ function i18n_get_normal_path($path) { * 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 + * + * @param string $path + * Drupal Path + * @param string $lang + * Language prefix + * + * @return string + * Drupal path with language prefix. */ -function i18n_path($path, $lang) { +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; - } + return _i18n_add_lang_prefix($lang) ? $lang : ''; + } + if(($alias = drupal_lookup_path('alias', $path)) && (!($prefix = i18n_get_lang_prefix($alias, TRUE)) || ($prefix && $prefix == $lang))) { + $path = $alias; + } + if (_i18n_add_lang_prefix($lang)) { + $path = $lang .'/'. $path; + } + return $path; } /** @@ -528,7 +603,7 @@ function i18n_node_get_lang($nid, $defau /** * 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) { @@ -551,9 +626,9 @@ function i18n_get_main_lang($lang = NULL /** * Function i18n_get_links - * + * * Returns an array of links for all languages, with or without names/flags - * + * * @param $path * Drupal internal path * @param $query @@ -566,10 +641,11 @@ function i18n_get_links($path = '', $que $path = ''; } $names = $names ? $names : i18n_languages('native'); + $links = array(); foreach (array_keys(i18n_supported_languages()) as $lang){ $links[$lang]= theme('i18n_link', $names[$lang], i18n_path($path, $lang), $lang, $query); } - return $links; + return $links; } /** @@ -597,14 +673,14 @@ function _i18n_locale_supported_language function _i18n_goto($lang){ if(!function_exists('drupal_goto')){ require_once './includes/common.inc'; - require_once './includes/path.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 @@ -620,7 +696,7 @@ function i18n_selection_mode($mode= NULL static $current_mode = 'simple'; static $current_value = ''; static $store = array(); - + if(!$mode) { return $current_mode; } elseif($mode == 'params'){ @@ -632,16 +708,16 @@ function i18n_selection_mode($mode= NULL array_push($store, array($current_mode, $current_value)); $current_mode = $mode; $current_value = $params; - } + } } // List of selection modes function _i18n_selection_mode(){ return array( 'simple' => t('Only current language and no language'), 'mixed' => t('Only current and default languages and no language'), - 'default' => t('Only 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'), + 'off' => t('All content. No language conditions apply'), ); } // List of language support modes for content @@ -657,7 +733,7 @@ function _i18n_content_languages() { * @name Themeable functions * @{ */ - + /** * Produces a language link with the right flag */ @@ -673,7 +749,7 @@ function theme_i18n_link($text, $target, /** * Theme language icon - * + * * This function can be overridden for no language icons */ function theme_i18n_language_icon($lang){ @@ -683,14 +759,14 @@ function theme_i18n_language_icon($lang) list($width, $height) = explode('x', variable_get('i18n_icon_size', '16x12')); $attribs = array('class' => 'i18n-icon', 'width' => $width, 'height' => $height, 'alt' => $languages[$lang]); return "