'switch', 'title' => t('Localizer'), 'callback' => 'localizer_switch', 'access' => user_access('access localizer'), 'type' => MENU_CALLBACK); $items[] = array( 'path' => 'node/'. arg(1) .'/localizer', 'title' => t('translation'), 'callback' => 'localizer_node_page', 'access' => user_access('administer localizer'), 'type' => MENU_LOCAL_TASK, 'weight' => 3); } localizer_menu_translate_all(); return $items; } /** * Implementation of hook nodeapi. * The translation mechanism acts here, for the "load" $op */ function localizer_nodeapi(&$node, $op, $teaser, $page) { global $locale; $localeinurl = explode('/', $_REQUEST['q']); $localeinurl = $localeinurl[0]; $valid_locales = localizer_supported_languages(); if(array_key_exists($localeinurl, $valid_locales)) { $locale = localizer_changelocale($localeinurl); } if(array_key_exists('locale', $_GET)) { $locale = localizer_changelocale($_GET['locale']); } switch ($op) { case 'load': $node->localizer_locale = db_result(db_query('SELECT locale FROM {localizer} WHERE nid = %d', $node->nid)); if($locale != $node->localizer_locale) { $pid = db_result(db_query('SELECT pid FROM {localizer} WHERE nid = %d', $node->nid)); if($pid) { $nid = db_result(db_query("SELECT nid FROM {localizer} WHERE pid = %d AND locale= '%s'", $pid, $locale)); if($nid) { $node=node_load($nid); } } } $object = db_fetch_object(db_query('SELECT locale, pid FROM {localizer} WHERE nid = %d', $node->nid)); return array('localizer_locale' => $object->locale, 'localizer_pid' => $object->pid); break; case 'insert': if($node->localizer_pid == 0){ $node->localizer_pid = $node->nid; } db_query("INSERT INTO {localizer} (nid, locale, pid) VALUES (%d, '%s', %d)", $node->nid, $node->localizer_locale, $node->localizer_pid); break; case 'update': if($node->localizer_pid == 0){ $node->localizer_pid = $node->nid; } db_query('DELETE FROM {localizer} WHERE nid = %d', $node->nid); db_query("INSERT INTO {localizer} (nid, locale, pid) VALUES (%d, '%s', %d)", $node->nid, $node->localizer_locale, $node->localizer_pid); break; case 'delete': db_query('DELETE FROM {localizer} WHERE nid = %d', $node->nid); break; } } /** * Modify the form for every node adding the necessary fields for localizer module : pid and locale */ function localizer_form_alter($form_id, &$form) { if (!isset($form['type'])) { return; } switch ($form_id) { case $form['type']['#value'] .'_node_form': global $locale; if(arg(3) == 'localizer' && user_access('administer localizer')) { // We are translating a node in the form : node/add/type/translation/nid/lang global $user; $source_nid = arg(4); $target_locale = arg(5); $node = node_load($source_nid); $node->nid = NULL; $node->uid = $user->uid; $node->created = 0; $node->menu = NULL; $node->path = NULL; $node->title = localizer_t($node->title, NULL ,$locale); $node->localizer_locale = $target_locale; $locale=$target_locale; $_SESSION['current_locale']=$target_locale; node_save($node); drupal_goto('node/'. $node->nid . '/edit'); } $options = localizer_supported_languages(); if(!isset($form['#node']->localizer_locale)) { $form['#node']->localizer_locale = $locale; } $form['localizer_locale'] = array( '#type' => 'select', '#title' => t('Locale'), '#default_value' => $form['#node']->localizer_locale, '#options' => $options, '#required' => TRUE, '#weight' => 0, ); break; } } /** * Hook for the submit of the form, updating the pid of the node */ function localizer_node_form_submit($form_id, $form_values){ $op = $_POST['op']; $localizer_pid = $form_values['localizer_pid']; $nid = $form_values['nid']; if( $localizer_pid && $nid ) { db_query("UPDATE {localizer} SET pid = %d WHERE nid=%d", $localizer_pid, $nid); drupal_set_message(t('The translation has been saved')); } } /** * Translates all user's menus items */ function localizer_menu_translate_all(){ global $_menu; global $user; global $locale; foreach($_menu['items'] as $mid => $item) { if($item['type'] & MENU_CREATED_BY_ADMIN) { $expanded = false; $path = $item['path']; $reqpath = $_REQUEST['q']; $drupalpath = drupal_get_normal_path($reqpath); if($drupalpath == $path) { $expanded = true; } if(!$expanded) { $drupalpath = drupal_get_normal_path(localizer_pathwithoutlocale($reqpath)); if($drupalpath == $path) { $expanded = true; } } if(!$expanded) { $languages = localizer_supported_languages(); foreach($languages as $langprefix=>$langname) { if(!$expanded) { $drupalpath = drupal_get_normal_path(localizer_pathwithlocale($reqpath, $langprefix)); if($drupalpath == $path) { $expanded = true; break; } } } } if($expanded) { localizer_expandmenu($mid); $_menu['items'][$mid]['path'] = drupal_get_normal_path($reqpath); } $_menu['items'][$mid]['title'] = t($_menu['items'][$mid]['title']); } } } function localizer_expandmenu($_mid) { global $_menu; if($_mid>0) { $_menu['visible'][$pid]['type'] = MENU_EXPANDED; $_menu['visible'][$_mid]['type'] = MENU_EXPANDED; $pid = $_menu['visible'][$_mid]['pid']; localizer_expandmenu($pid); } } /** * Sets the intial language in the order : session, user preferences or browser detect */ function i18n_get_lang() { global $user; $languages = localizer_supported_languages(); if (isset($_SESSION['current_locale']) && $languages[$_SESSION['current_locale']]) { return $_SESSION['current_locale']; } else if ($user->uid && $languages[$user->language]) { return $user->language; } else if (variable_get('localizer_detect_browser', TRUE) && ($lang = localizer_get_browser_lang())) { return $lang; } else { return key($languages); } } /** * Lists the supported languages form the locale module */ function localizer_supported_languages() { static $languages; if(!isset($languages)) { if (function_exists('locale')) { $languages = locale_supported_languages(); $languages = $languages['name']; } else { $languages = array('en' => 'English'); } } return $languages; } /** * Returns is the locale provided is valid */ function localizer_isvalidlocale($_locale = '') { static $valid_locales; $valid_locales = localizer_supported_languages(); if(($_locale!= '') && array_key_exists($_locale, $valid_locales)){ return true; } else { return false; } } /** * Returns the path without the locale */ function localizer_pathwithoutlocale($_path) { $exploded_path = explode('/', $_path); $localeinpath = $exploded_path[0]; if(localizer_isvalidlocale($localeinpath)){ array_shift($exploded_path); return implode("/", $exploded_path); } else { return $_path; } } /** * Returns the path with the locale prefixed */ function localizer_pathwithlocale($_path, $_locale) { if(localizer_isvalidlocale($_locale)) { return $_locale . '/' . localizer_pathwithoutlocale($_path); } else { return $_path; } } /** * Returns the locale contained in the path */ function localizer_localeinpath($_path) { $exploded_path = explode('/', $_path); $localeinpath = $exploded_path[0]; if(localizer_isvalidlocale($localeinpath)){ return $localeinpath; } else { return ''; } } /** * Get the language of the browser */ function localizer_get_browser_lang() { $languages = localizer_supported_languages(); $exploded_server = explode(";",$_SERVER["HTTP_ACCEPT_LANGUAGE"]); $accept=explode(',',array_shift($exploded_server)); ; foreach ($accept as $lang) { $lang=substr($lang,0,2); if (!empty($lang) && array_key_exists($lang,$languages)) { return $lang; } } return NULL; } /** * Hook for switching the language through the block * @param switch_to the locale of the new selected language */ function localizer_switch($switch_to) { localizer_changelocale($switch_to); drupal_goto(); } /** * Generate HTML for the localizer block * @param op the operation from the URL * @param delta offset * @returns block HTML */ function localizer_block($op = 'list', $delta = 0, $edit = array()) { global $user; switch ($op) { case 'list': $block[0]['info'] = t('Select language'); break; case 'view': if($delta == 0 && !($user->uid && variable_get('localizer_hide_block', FALSE))) { $block['subject'] = t('Select language'); $block['content'] = theme('item_list', localizer_get_links(variable_get('localizer_show_flags', TRUE), variable_get('localizer_name',TRUE), variable_get('localizer_separator', ' '))); } break; } return $block; } /** * Generate HTML for language change * @out prints HTML code on standard output * @returns HTML code */ function localizer_changelanguageblock($out=true) { $output = theme('item_list', localizer_get_links(variable_get('localizer_show_flags', TRUE), variable_get('localizer_name',TRUE), variable_get('localizer_separator', ' '))); if($out) { echo $output; } return $output; } /** * Creates the links for the switching language block * @param flags shows the languages flags * @param names shows the languages names * @param separator text to use as separator between the flag and the name * @returns links in HTML format */ function localizer_get_links($flags = 1, $names = 1, $separator = ' ') { global $locale; $languages = localizer_supported_languages(); $destination = localizer_get_destination(); if($destination == ''){ $destination = variable_get('site_frontpage', 'node'); } $path = explode("?", $destination); $path = $path[0]; foreach ($languages as $lang => $langname) { if($lang != $locale) { if(drupal_get_normal_path($lang . "/" . $path) != ($lang . "/" . $path)){ $locale_destination = $lang . "/" . $destination; } else { $locale_destination = $destination; } $langname = localizer_t($langname, 0, $lang); $flag = $flags ? localizer_flag($lang, array('alt' => $langname)) : '' ; $separator = ($langname != '' && $flag != '') ? $separator : ''; $pos = strpos($locale_destination, 'destination='); if($pos === FALSE) { $locale_destination = "destination=" . urlencode($locale_destination); $links[]= l("$flag$separator$langname", 'switch/'.$lang, array('title' => t('Switch language to %lang', array('%lang' => $langname))), $locale_destination , NULL, NULL, TRUE); } else { $locale_path = $_REQUEST['q']; $destination = urldecode($destination); $destination = substr($destination, strlen('destination=')); $locale_destination = "destination=" . urlencode($locale_path . '?destination=' . $destination); $links[]= l("$flag$separator$langname", 'switch/'.$lang, array('title' => t('Switch language to %lang', array('%lang' => $langname))), $locale_destination , NULL, NULL, TRUE); } } } return $links; } /** * Create the HTML a language's flag * @param lang the language of the flag * @param attribs additional attributes * @returns HTML code */ function localizer_flag($lang, $attribs = array()) { if ($path = variable_get('localizer_flags_path', drupal_get_path('module', 'localizer') . '/flags/*.png')) { $src = base_path() . str_replace('*', $lang, $path); list($width, $height) = explode('x', variable_get('localizer_flags_size', '16x12')); $attribs = array_merge(array('class' => 'localizer-flag', 'width' => $width, 'height' => $height, 'alt' => ''), $attribs); $html = ""; return $html; } } /** * Hook settings for the module */ function localizer_settings() { $form['localizer_detect_browser'] = array ( '#type' => 'checkbox', '#title' => t('Browser language detection'), '#default_value' => variable_get('localizer_detect_browser', 1), ); $form['localizer_hide_block'] = array ( '#type' => 'checkbox', '#title' => t('Hide block for authenticated user'), '#default_value' => variable_get('localizer_hide_block', 1), ); $form['localizer_name'] = array ( '#type' => 'checkbox', '#title' => t('Display language name'), '#default_value' => variable_get('localizer_name', 1), ); $form['localizer_show_flags'] = array ( '#type' => 'checkbox', '#title' => t('Show flags'), '#default_value' => variable_get('localizer_show_flags', 1), ); $form['localizer_show_flags'] = array ( '#type' => 'textfield', '#title' => t('Flag and language separator'), '#default_value' => variable_get('localizer_separator', ' '), '#size' => 5, '#maxlength' => 10, '#description' => 'Token separating the flag and languagename.', ); $form['localizer_flags_path'] = array ( '#type' => 'textfield', '#title' => t('Flag icons path'), '#default_value' => variable_get('localizer_flags_path', drupal_get_path('module', 'localizer') . '/flags/*.png'), '#size' => 50, '#maxlength' => 180, '#description' => 'Path for flag icons, relative to Drupal installation. \'*\' is a placeholder for language code.', ); $form['localizer_flags_size'] = array ( '#type' => 'textfield', '#title' => t('Flag icons size'), '#default_value' => variable_get('localizer_flags_size', variable_get('localizer_flags_size', '16x12')), '#size' => 10, '#maxlength' => 10, '#description' => 'Image size for flags, in the form "width x height".', ); return $form; } /** * Hook for the overview of a node. * Implements the translations tab interface */ function localizer_node_overview($node) { $languages = localizer_supported_languages(); unset($languages[$node->localizer_locale]); $output = t('

Current translations

'); $header = array(t('Language'), t('Title'), t('Options')); foreach($languages as $lang => $langname){ $options = array(); $trnid = db_result(db_query("SELECT nid FROM {localizer} WHERE pid = %d AND locale= '%s'", $node->localizer_pid, $lang)); if($trnid) { $trnode = db_fetch_object(db_query('SELECT n.nid, n.title, n.status, l.locale FROM {node} n INNER JOIN {localizer} l ON n.nid = l.nid AND n.nid = %d', $trnid)); $title = l($trnode->title, 'node/'. $trnode->nid, NULL, 'locale=' . $trnode->locale); } else { $title = t('Not translated'); $options[] = l(t('create translation'), "node/add/$node->type/localizer/$node->nid/$lang"); } $options[] = l(t('select node'), "node/$node->nid/localizer/select/$lang"); $rows[] = array($langname, $title, implode(" | ", $options)); } $output .= theme('table', $header, $rows); if($node->localizer_pid != $node->nid){ $form['submit'] = array('#type' => 'submit', '#value' => t('Remove'), '#suffix' => t('Remove node from this translation set')); $output .= drupal_get_form(NULL, $form); } return $output; } /**. * Intercepts all the calls for the page. */ function localizer_node_page() { $args = func_get_args(); $op = isset($_POST['op']) ? $_POST['op'] : $args[0]; $edit = $_POST['edit']; $nid = arg(1); $node = node_load($nid); drupal_set_title($node->title); $output = ''; switch($op){ case 'select': $output .= localizer_node_overview($node); $output .= localizer_node_form($node, $args[1]); break; case t('Save'): $output .= localizer_node_form($node, $args[1]); break; case 'remove': case t('Remove'): db_query("UPDATE {localizer} SET pid = %d WHERE nid=%d", $node->nid, $node->nid); drupal_set_message("The node has been removed from the translation set"); drupal_goto("node/$node->nid/localizer"); default: $output .= localizer_node_overview($node); } print theme('page', $output); } /** * Prepares the interface for select a translation node. */ function localizer_node_form($node, $locale){ $form['node'] = array('#type' => 'value', '#value' =>$node); $form['localizer_pid'] = array('#type' => 'hidden', '#value' => $node->localizer_pid); $languages = localizer_supported_languages(); $result = pager_query(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n INNER JOIN {localizer} l ON n.nid=l.nid WHERE l.locale = '%s' ORDER BY n.title"), 40, 0, NULL, $locale); while($trnode = db_fetch_object($result)){ $list[$trnode->nid] = l($trnode->title, "node/$trnode->nid") ; } if($list){ $translations = localizer_node_get_translations($node->nid); $form['nodes']['nid'] = array( '#type' => 'radios', '#title' => t('Select translation for %language', array('%language' => $languages[$locale])), '#default_value' => isset($translations[$locale]) ? $translations[$locale]->nid : '', '#options' => $list); $form['pager'] = array('#value' => theme('pager')); $form['submit'] = array('#type' => 'submit', '#value' => t('Save')); return drupal_get_form('localizer_node_form', $form); } else { return t("

No nodes available in %language

", array('%language' => $languages[$locale]) ); } } /** * Gets the translations for the current node * @param nid the id of the node * @param getitself includes also the node in the list */ function localizer_node_get_translations($nid, $getitself = FALSE) { $pid = db_result(db_query('SELECT pid FROM {localizer} WHERE nid = %d', $nid)); if($getitself) { $result = db_query('SELECT n.nid, n.title, n.status, l.locale FROM {node} n INNER JOIN {localizer} l ON n.nid = l.nid AND l.pid = %d', $pid); } else { $result = db_query('SELECT n.nid, n.title, n.status, l.locale FROM {node} n INNER JOIN {localizer} l ON n.nid = l.nid AND l.pid = %d AND l.nid <> %d', $pid, $_nid); } $items = array(); while ($node = db_fetch_object($result)) { $items[$node->locale] = $node; } return $items; } /** * Change the global locale * @param string the new locale * @param _locale the locale to use for the translation * @returns the global locale */ function localizer_changelocale($_locale = '') { global $locale; static $valid_locales; $valid_locales = localizer_supported_languages(); if(($_locale != '') && ($_locale != $locale) && (array_key_exists($_locale, $valid_locales))) { $locale=$_locale; $_SESSION['current_locale']=$locale; } return $locale; } function localizer_get_destination() { if (isset($_REQUEST['destination'])) { return 'destination='. urlencode($_REQUEST['destination']); } else { // Use $_REQUEST here to retrieve the original path. $path = isset($_REQUEST['q']) ? $_REQUEST['q'] : ''; $path = localizer_pathwithoutlocale($_REQUEST['q']); $query = drupal_query_string_encode($_GET, array('q')); if ($query != '') { $path .= '?'. $query; } return $path; } } //Rewrite of some core functions /** * Translates a string a substitute the arguments * @param string the string to translate * @param args array of additional arguments to substitute * @param _locale the locale to use for the translation */ function localizer_t($string, $args = 0, $_locale = '') { global $locale; if($_locale == '') { $_locale = $locale; } if (function_exists('localizer_locale') && $_locale != 'en') { $string = localizer_locale($string, $_locale); } if (!$args) { return $string; } else { return strtr($string, $args); } } /** * Translates a string * @param string the stirng to translate * @param _locale the locale to use for the translation */ function localizer_locale($string, $_locale = '') { global $locale; if($_locale == '') { $_locale = $locale; }; $cache = cache_get("locale:$_locale"); if ($cache == 0) { locale_refresh_cache(); $cache = cache_get("locale:$_locale"); } $locale_t = unserialize($cache->data); // We have the translation cached (if it is TRUE, then there is no // translation, so there is no point in checking the database) if (isset($locale_t[$string])) { $string = ($locale_t[$string] === TRUE ? $string : $locale_t[$string]); } // We do not have this translation cached, so get it from the DB. else { $result = db_query("SELECT s.lid, t.translation FROM {locales_source} s INNER JOIN {locales_target} t ON s.lid = t.lid WHERE s.source = '%s' AND t.locale = '%s'", $string, $_locale); // Translation found if ($trans = db_fetch_object($result)) { if (!empty($trans->translation)) { $locale_t[$string] = $trans->translation; $string = $trans->translation; } } // Either we have no such source string, or no translation else { $result = db_query("SELECT lid, source FROM {locales_source} WHERE source = '%s'", $string); // We have no such translation if ($obj = db_fetch_object($result)) { if ($_locale) { db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '')", $obj->lid, $_locale); } } // We have no such source string else { db_query("INSERT INTO {locales_source} (location, source) VALUES ('%s', '%s')", request_uri(), $string); if ($_locale) { $lid = db_fetch_object(db_query("SELECT lid FROM {locales_source} WHERE source = '%s'", $string)); db_query("INSERT INTO {locales_target} (lid, locale, translation) VALUES (%d, '%s', '')", $lid->lid, $_locale); } } // Clear locale cache in DB cache_clear_all("locale:$_locale"); } } return $string; } ?>