<?php /** */ $g_app_root = realpath(dirname(__FILE__)); define('G_APP_ROOT', $g_app_root); define('G_VHOST', $_SERVER['SERVER_NAME']); // languages for home // $langs = array() is now in /_nav/lib.php // TODO (rda) define fallback languages for each language // for instance, pt-br could fallback on pt and pt on pt-br (but without // a cycle) then on es, etc. $i18n_fallback_rules = array( 'pt-br' => 'pt', 'pt' => 'pt-br' ); $domains_lang = array( 'mageia.fr' => 'fr', 'mageia.it' => 'it', 'mageia.ro' => 'ro', ); require_once ('_nav/lib.php'); /** * Redirect to a localized path, depending on incoming TLD. * Only manages redirections to main home path. * * @param string $tld * @param array $domains_lang * @param string $vhost * * @return void */ function tld_redirect($tld, $domains_lang, $vhost) { domain_redirect('mageia.' . $tld, $domains_lang, $vhost); } /** * Redirect to a localized path, depending on incoming full domain. * Only manages redirections to main home path. * * @param string $host * @param array $domains_lang * @param string $vhost * * @return void */ function domain_redirect($host, $domains_lang, $vhost) { $host = str_replace('www.', '', $host); if (array_key_exists($host, $domains_lang)) { $path = $domains_lang[$host] . '/'; header ('HTTP/1.1 301 Moved Permanently'); } else { $path = '?langs'; } header(sprintf('Location: %s://%s/%s', 'https', $vhost, $path)); die; } /** * Redirect to a localized path, after browser Accept-Language prefs. * Return the path. * Do not exit the process. * * @param array $langs list of languages * @param string $page optional path to which we want to redirect * @param string $default_locale * @param string $force_accept_language replace remote browser HTTP_ACCEPT_LANGUAGE request header * @param boolean $do_redirect * * @return string */ function relocate($langs, $page = '', $default_locale = 'en', $force_accept_language = null, $do_redirect = true) { require_once 'localeDetection.class.php'; $locale = new ChooseLocale(array_keys($langs), $force_accept_language); $locale->setDefaultLocale($default_locale); $relocate = sprintf('/%s/%s', $locale->getCompatibleLocale(), $page); $relocate = str_replace('//', '/', $relocate); if ('cli' != PHP_SAPI && $do_redirect) { header('Location: ' . $relocate); die; } return $relocate; } /** * Create string pt_br from string pt-br and alike but leave the rest as is * Return string. * Do not exit the process. * * @param string $locale which we want to change * @param boolean $version_of_locale_uppercase optional, true if we want second part in uppercase (pt_BR) * * @return string */ function locale_hyphen_underscore($locale, $version_of_locale_uppercase = false) { preg_match("/(..)(-)(..)/", $locale, $parsed_locale); if(isset($parsed_locale[3])) { return $parsed_locale[1] . '_' . ($version_of_locale_uppercase ? strtoupper($parsed_locale[3]) : $parsed_locale[3]); } else { return $locale; } } /** * Create string pt-br from string pt_br or pt_BR and alike but leave the rest as is * Return string. * Do not exit the process. * * @param string $locale which we want to change * * @return string */ function locale_underscore_to_hyphen($locale) { preg_match("/(..)(_)(..)/", $locale, $parsed_locale); if(isset($parsed_locale[3])) { return $parsed_locale[1] . '-' . strtolower($parsed_locale[3]); } else { return $locale; } } /** * Returns sanitized specified $_GET variable by name if it exists and strip tags from it * * @param string name of a $_GET vaiable * * @return string sanitized string, empty on empty string or on error in filtering */ function get_sane_string($str){ return (string) filter_input(INPUT_GET, $str, FILTER_SANITIZE_STRING); } /** */ function show_langs($langs) { header('Content-Type: text/html; charset=utf-8'); $count = count($langs); $s = <<<S <!DOCTYPE html> <html lang="en"> <head> <charset="utf-8"> <meta name="robots" content="noindex,nosnippet"> <title>Mageia</title> </head> <body> <p><a href="/">Mageia.org</a> is currently available in {$count} languages:</p> <ul> S; foreach ($langs as $k => $v) { $s .= sprintf('<li><a href="/%s/" hreflang="%s">%s</a></li>', $k, $k, $v); } echo $s, '</ul><hr />', '<p>If you would like to help improving this Web site or its translations, ', 'check out our <a href="/langs/report.php">translation report page</a> ', '<a href="https://wiki.mageia.org/en/Web_team">Web</a> and ', '<a href="https://wiki.mageia.org/en/Internationalisation_Team_(i18n)">localization</a> teams!</p>', '<p>Your browser Accept-Language is: ', $_SERVER['HTTP_ACCEPT_LANGUAGE'], '.</p>', '<hr /></body></html>'; } /** * Class regrouping basic methods for i18n strings in their current forms. * */ class i18n { /** * @param string $request_uri * * @return string */ public static function get_language_from_url($request_uri) { $l = explode('/', $request_uri); return $l[1]; } /** * Return language strings in $strings that match $lang, * and merge with pre-loaded strings matching $fallback_lang. * * @param array $strings array('fr' => array(strings...), 'en' => array(...)) * @param string $lang * @param string $fallback_lang * * @return array */ public static function get_strings($strings, $lang, $fallback_rules = null) { $use_lang = self::get_fallback_language($lang, array_keys($strings), $fallback_rules); return array_merge($strings['en'], $strings[$use_lang]); } /** * Return a language we know we have support for, or a fallback language. * * Important note: this is supposed to be used only once in a row; do not * chain this method over itself as you may end up with an infinite loop * (depends on $fallback_rules contents). * * TODO (rda) implement this into an object, so we can check several langs * in a row for a same document, with several fallback hops, without a cycle. * * @param string $lang language we wish to use * @param array $known_langs list of languages we support * @param mixed $fallback_rules * * @return string */ public static function get_fallback_language($lang, $known_langs, $fallback_rules = null) { $ret = 'en'; if (in_array($lang, $known_langs)) { $ret = $lang; } else { if (is_string($fallback_rules)) { $ret = $fallback_rules; } elseif (is_array($fallback_rules) && array_key_exists($lang, $fallback_rules)) { $ret = $fallback_rules[$lang]; } if (!in_array($ret, $known_langs)) $ret = 'en'; } return $ret; } /** * Get a translated string to output. * * Use it when you need to capture the string to output. * * Examples: * * echo _t("Hello."), _t("How are you?"); * * * @param string $s string to localize * @param array $opt translated strings list * @param string $post string suffix. Useful to prevent non-breaking lines. * * @return null|string */ public static function _t($s = null, $opt = null, $post = ' ') { return self::_d($s, $opt) . $post; } /** * Lookup for translated string for $s * in global array $_t (yes, ugly) * OR in $opt param. * * $_t or $opt is the list of string for the current locale. * * Use it when you need to get the exact, char-specific translation text. * * Examples: * * _d('http://mageia.org/en/'); * _d('http://blog.mageia.org/en/feed'); * * @param string $s * @param array $opt * * @return string * * FIXME Yes, it's terribly wrong/evil to rely on an unknown global $_t. * Solution? rethink the whole i18n thing in an integrated one. */ public static function _d($s = null, $opt = null) { if ($s == '') return null; if (!is_null($opt)) { $_t = $opt; } else { global $_t; } $ret = array_key_exists($s, $_t) ? $_t[$s] : $s; return trim(str_replace(array('{ok}', '{OK}', '{Ok}', '{oK}'), '', $ret)); } /** * Output a localized string $s, with optional $args. * * Use it when you need to just output a string. * * Examples: * * _e("Hello"); * _e("Hello %d %d", array(1, 2)); * * @param string $s * @param array $args * * @return null */ public static function _e($s = null, $args = null) { if (is_array($args)) echo vsprintf(_t($s), $args); else echo self::_t($s); } /** * Output a localized string $s, sprintf'ed with $args, HTML-wrapped in $tag. * * Use it when you need to wrap your text is HTML, and this is faster. * * Examples: * * _h("Hello"); * _h("Hello %s", array("Alice")); * _h("Title", null, "h1"); * * @param string $s string to echo * @param array $args optional params to $s * @param string $tag optional tag to wrap $s into * * @return null */ public static function _h($s, $args = null, $tag = 'p') { $s = self::_t($s); $s = is_array($args) ? vsprintf($s, $args) : $s; $close_tag = explode(' ', $tag); $close_tag = array_shift($close_tag); echo sprintf('<%s>%s</%s>', $tag, $s, $close_tag); } /** * Get all locales from given file. * * @param string $file * @param string $return_duplicates optional switch * * @return array */ public static function _lang_return($file, $return_duplicates = false) { $strings = array(); if (file_exists($file)) { $f = file($file); foreach ($f as $k => $v) { $C = substr($v, 0, 1); if ($C === '#') continue; if ($C === ';' && !empty($f[$k+1])) { $j = trim(substr($v, 1)); $j = str_replace(array("\'", "\""), array("'", '"'), $j); if ($return_duplicates && !empty($strings[$j])) { $duplicates[] = $j; } $strings[$j] = trim($f[$k+1]); } } if (!empty($duplicates)) { $strings['duplicates'] = $duplicates; } } return $strings; } /** * Load requested $locale, from $domain lang file, into global $_t array. * * @param string $locale * @param string $domain * * @return boolean * * @todo use i18n::get_fallback_language() or eq. */ public static function _lang_load($locale, $domain) { if ($locale == 'en') return true; $lang_file = sprintf('%s/langs/%s/%s.%s.lang', G_APP_ROOT, $locale, $domain, $locale); if (file_exists($lang_file)) { global $_t; if (!isset($_t) || !is_array($_t)) $_t = array(); $_t = array_merge($_t, self::_lang_return($lang_file)); return true; } return false; } } // shorthand helpers, to make legacy calls work. function _t($s = null, $opt = null, $post = ' ') { return i18n::_t($s, $opt, $post); } function _d($s = null, $opt = null) { return i18n::_d($s, $opt); } function _e($s = null, $args = null) { return i18n::_e($s, $args); } function _h($s = null, $args = null, $tag = 'p') { return i18n::_h($s, $args, $tag); } function _lang_load($locale, $domain) { return i18n::_lang_load($locale, $domain); } /** * Create dictionary from gettext file * Return array. * Do not exit the process. * * @param string $locale from which we want to create dictionary * @param mixed $name_of_translation string for one gettext filename or array for more * * @return array */ function read_translation_file($locale, $name_of_translation) { if(is_array($name_of_translation)) { $dictionary = array(); foreach($name_of_translation as $single_filename) { $dictionary = array_merge($dictionary, read_translation_file($locale, $single_filename)); } return $dictionary; } else { if ($name_of_translation == '../_nav/langs/en') { $path_filename = '/_nav/langs/' . $locale . '.po'; } else { $path_filename = '/langs/' . $locale . '/' . $name_of_translation . '.po'; } if ($locale == 'en') { $path_filename .= 't'; } $dictionary_from_file = phpmo_parse_po_file(G_APP_ROOT . $path_filename); if (is_array($dictionary_from_file)) { return $dictionary_from_file; } else { return array(); // in case of missing l10n file or it's parsing error } } } /** * Returns a translated string from global $dictionary * it can append space if needed * * Note that it trims {ok} for translations equal to original too. * * Use it when you need to capture the string to output. * * Examples: * echo _r("Hello!", ' ') . _r("How are you?") * which should return translated: Hello! How are you? * * @param string $string_for_translation which we want to translate * @param string $sufix append (usually space) * * @return string translated to current locale */ function _r($string_for_translation, $sufix = '') { global $dictionary; $escapeded_string = str_replace(array('"'), array('\\"'), $string_for_translation); if(!empty($dictionary[$escapeded_string][0][0])) { $find = array('\\"', '\n', ' ', '{ok}', '{OK}', '{Ok}', '{oK}'); $replace = array('"','<br>', ' '); $prepared_string = trim(str_replace($find, $replace, $dictionary[$escapeded_string][0][0])); } if(empty($prepared_string)) { $prepared_string = $string_for_translation; } if(!empty($sufix)) { $prepared_string .= $sufix; } return $prepared_string; } /** * Higher level function for _r() to echo a translated string from global $dictionary * used also to wrap the translation with HTML tags * it can also append space if needed * * Examples: *_g("How are you?") * will just echo translation * * _g('Download Mageia %d!', array(5), 'a href="" style="color: blue;"') * OR for only one member of array: * _g('Download Mageia %s!', 5, 'a href="" style="color: blue;"') * will both echo blue link * * _g("Hey there.", null, ' '); _g("How are you?") * will just echo translation: Hey there. How are you? * * Return boolean. * Do not exit the process. * * @param string $string_for_translation which we want to translate * @param array OR string $args for vsprintf/sprintf * @param string $tag_or_space HTML tag or space to append * * @return null */ function _g($string_for_translation, $args = null, $tag_or_space = '') { $translated_string = _r($string_for_translation); if(!is_null($args)) { if(is_array($args)) { $translated_string = vsprintf($translated_string, $args); } else { $translated_string = sprintf($translated_string, $args); } } if(!empty($tag_or_space) && $tag_or_space != ' ') { $tag_or_space_w_args = explode(' ', $tag_or_space); $close_tag = array_shift($tag_or_space_w_args); echo sprintf('<%s>%s</%s>', $tag_or_space, $translated_string, $close_tag); } else { echo $translated_string . $tag_or_space; } }