|
|
@ -22,10 +22,10 @@
|
|
|
|
class L10n {
|
|
|
|
class L10n {
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* These are tranlations we currently support.
|
|
|
|
* These are tranlations we currently support.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* If another translation is added, it doesn't suffice to have gettext set
|
|
|
|
* If another translation is added, it doesn't suffice to have gettext set
|
|
|
|
* up, you also need to add it here, because it acts as a white list.
|
|
|
|
* up, you also need to add it here, because it acts as a white list.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @var array("ISO-language code" => "native name of the language")
|
|
|
|
* @var array("ISO-language code" => "native name of the language")
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static $translations = array(
|
|
|
|
public static $translations = array(
|
|
|
@ -53,15 +53,15 @@ class L10n {
|
|
|
|
"zh-cn" => "中文(简体)",
|
|
|
|
"zh-cn" => "中文(简体)",
|
|
|
|
"zh-tw" => "中文(臺灣)",
|
|
|
|
"zh-tw" => "中文(臺灣)",
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* setlocale needs a language + region code for whatever reason so here's
|
|
|
|
* setlocale needs a language + region code for whatever reason so here's
|
|
|
|
* the mapping from a translation code to locales with the region that
|
|
|
|
* the mapping from a translation code to locales with the region that
|
|
|
|
* seemed the most common for this language
|
|
|
|
* seemed the most common for this language
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* You probably never need this. Use {@link set_translation()} to change the
|
|
|
|
* You probably never need this. Use {@link set_translation()} to change the
|
|
|
|
* language instead of manually calling setlocale().
|
|
|
|
* language instead of manually calling setlocale().
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @var array(string => string)
|
|
|
|
* @var array(string => string)
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
private static $locales = array(
|
|
|
|
private static $locales = array(
|
|
|
@ -101,11 +101,11 @@ class L10n {
|
|
|
|
"zh-cn" => "zh_CN",
|
|
|
|
"zh-cn" => "zh_CN",
|
|
|
|
"zh-tw" => "zh_TW",
|
|
|
|
"zh-tw" => "zh_TW",
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Auto-detects the language that should be used and sets it. Only works for
|
|
|
|
* Auto-detects the language that should be used and sets it. Only works for
|
|
|
|
* HTTP, not in a command line script.
|
|
|
|
* HTTP, not in a command line script.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Priority:
|
|
|
|
* Priority:
|
|
|
|
* <ol>
|
|
|
|
* <ol>
|
|
|
|
* <li>explicit parameter "lang" passed in HTTP (e.g. via GET)</li>
|
|
|
|
* <li>explicit parameter "lang" passed in HTTP (e.g. via GET)</li>
|
|
|
@ -128,10 +128,10 @@ class L10n {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$languages = array();
|
|
|
|
$languages = array();
|
|
|
|
|
|
|
|
|
|
|
|
// parse Accept-Language header
|
|
|
|
// parse Accept-Language header
|
|
|
|
if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
|
|
|
|
if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
|
|
|
|
$bits = explode(",", strtolower(
|
|
|
|
$bits = explode(",", strtolower(
|
|
|
@ -144,29 +144,29 @@ class L10n {
|
|
|
|
$c = floatval(substr($b[1], 2));
|
|
|
|
$c = floatval(substr($b[1], 2));
|
|
|
|
else
|
|
|
|
else
|
|
|
|
$c = 1;
|
|
|
|
$c = 1;
|
|
|
|
|
|
|
|
|
|
|
|
if ($c != 0)
|
|
|
|
if ($c != 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
$languages[trim($b[0])] = $c;
|
|
|
|
$languages[trim($b[0])] = $c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check if there is an explicit language given as parameter
|
|
|
|
// check if there is an explicit language given as parameter
|
|
|
|
if(array_key_exists("lang",$_REQUEST) && trim($_REQUEST["lang"]) != "")
|
|
|
|
if(array_key_exists("lang",$_REQUEST) && trim($_REQUEST["lang"]) != "")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// higher priority than those values in the header
|
|
|
|
// higher priority than those values in the header
|
|
|
|
$languages[strtolower(trim($_REQUEST["lang"]))] = 2.0;
|
|
|
|
$languages[strtolower(trim($_REQUEST["lang"]))] = 2.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
arsort($languages, SORT_NUMERIC);
|
|
|
|
arsort($languages, SORT_NUMERIC);
|
|
|
|
|
|
|
|
|
|
|
|
// this is used to be compatible with browsers like internet
|
|
|
|
// this is used to be compatible with browsers like internet
|
|
|
|
// explorer which only provide the language code including the
|
|
|
|
// explorer which only provide the language code including the
|
|
|
|
// region not without. Also handles the fallback to English (qvalues
|
|
|
|
// region not without. Also handles the fallback to English (qvalues
|
|
|
|
// may only have three digits after the .)
|
|
|
|
// may only have three digits after the .)
|
|
|
|
$fallbacks = array("en" => 0.0005);
|
|
|
|
$fallbacks = array("en" => 0.0005);
|
|
|
|
|
|
|
|
|
|
|
|
foreach($languages as $lang => $qvalue)
|
|
|
|
foreach($languages as $lang => $qvalue)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// ignore any non-conforming values (that's why we don't need to
|
|
|
|
// ignore any non-conforming values (that's why we don't need to
|
|
|
@ -179,7 +179,7 @@ class L10n {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$lang_prefix = $matches[1]; // usually two-letter language code
|
|
|
|
$lang_prefix = $matches[1]; // usually two-letter language code
|
|
|
|
$fallbacks[$lang_prefix] = $qvalue;
|
|
|
|
$fallbacks[$lang_prefix] = $qvalue;
|
|
|
|
|
|
|
|
|
|
|
|
$chosen_translation = "";
|
|
|
|
$chosen_translation = "";
|
|
|
|
if ($lang === '*') {
|
|
|
|
if ($lang === '*') {
|
|
|
|
// According to the standard '*' matches anything but any
|
|
|
|
// According to the standard '*' matches anything but any
|
|
|
@ -202,7 +202,7 @@ class L10n {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($chosen_translation !== "")
|
|
|
|
if ($chosen_translation !== "")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (self::set_translation($chosen_translation)) {
|
|
|
|
if (self::set_translation($chosen_translation)) {
|
|
|
@ -210,7 +210,7 @@ class L10n {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// No translation found yet => try the prefixes
|
|
|
|
// No translation found yet => try the prefixes
|
|
|
|
arsort($fallbacks, SORT_NUMERIC);
|
|
|
|
arsort($fallbacks, SORT_NUMERIC);
|
|
|
|
foreach ($fallbacks as $lang => $qvalue) {
|
|
|
|
foreach ($fallbacks as $lang => $qvalue) {
|
|
|
@ -218,16 +218,47 @@ class L10n {
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// should not get here, as the fallback of "en" is provided and that
|
|
|
|
// should not get here, as the fallback of "en" is provided and that
|
|
|
|
// should always work => log an error
|
|
|
|
// should always work => log an error
|
|
|
|
trigger_error("L10n::detect_language(): could not set language",
|
|
|
|
trigger_error("L10n::detect_language(): could not set language",
|
|
|
|
E_USER_WARNING);
|
|
|
|
E_USER_WARNING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* Normalise the translation code (e.g. from the old codes to the new)
|
|
|
|
|
|
|
|
*
|
|
|
|
|
|
|
|
* @return string
|
|
|
|
|
|
|
|
* a translation code or the empty string if it can't be normalised
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
public static function normalise_translation($translation_code) {
|
|
|
|
|
|
|
|
// check $translation_code against whitelist
|
|
|
|
|
|
|
|
if (array_key_exists($translation_code, self::$translations) ) {
|
|
|
|
|
|
|
|
return $translation_code;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// maybe it's a locale as previously used in the system? e.g. en_AU
|
|
|
|
|
|
|
|
if (preg_match('/^([a-z][a-z])_([A-Z][A-Z])$/', $translation_code, $matches) !== 1) {
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$lang_code = $matches[1];
|
|
|
|
|
|
|
|
$region_code = strtolower($matches[2]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (array_key_exists("${lang_code}-${region_code}", self::$translations)) {
|
|
|
|
|
|
|
|
return "${lang_code}-${region_code}";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (array_key_exists($lang_code, self::$translations)) {
|
|
|
|
|
|
|
|
return $lang_code;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return '';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Get the set translation
|
|
|
|
* Get the set translation
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
* @return string
|
|
|
|
* a translation code or the empty string if not set
|
|
|
|
* a translation code or the empty string if not set
|
|
|
|
*/
|
|
|
|
*/
|
|
|
@ -238,13 +269,13 @@ class L10n {
|
|
|
|
return "";
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Set the translation to use.
|
|
|
|
* Set the translation to use.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param string $translation_code
|
|
|
|
* @param string $translation_code
|
|
|
|
* the translation code as specified in the keys of {@link $translations}
|
|
|
|
* the translation code as specified in the keys of {@link $translations}
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
* @return bool
|
|
|
|
* <ul>
|
|
|
|
* <ul>
|
|
|
|
* <li>true if the translation has been set successfully</li>
|
|
|
|
* <li>true if the translation has been set successfully</li>
|
|
|
@ -255,27 +286,11 @@ class L10n {
|
|
|
|
* </ul>
|
|
|
|
* </ul>
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
public static function set_translation($translation_code) {
|
|
|
|
public static function set_translation($translation_code) {
|
|
|
|
// check $translation_code against whitelist
|
|
|
|
$translation_code = self::normalise_translation($translation_code);
|
|
|
|
if ( !array_key_exists($translation_code, self::$translations) ) {
|
|
|
|
if (empty($translation_code)) {
|
|
|
|
// maybe it's a locale as previously used in the system? e.g. en_AU
|
|
|
|
return false;
|
|
|
|
if ( preg_match('/^([a-z][a-z])_([A-Z][A-Z])$/', $translation_code,
|
|
|
|
|
|
|
|
$matches) !== 1 ) {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$lang_code = $matches[1];
|
|
|
|
|
|
|
|
$region_code = strtolower($matches[2]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ( array_key_exists("${lang_code}-${region_code}",
|
|
|
|
|
|
|
|
self::$translations) ) {
|
|
|
|
|
|
|
|
$translation_code = "${lang_code}-${region_code}";
|
|
|
|
|
|
|
|
} elseif ( array_key_exists($lang_code, self::$translations) ) {
|
|
|
|
|
|
|
|
$translation_code = $lang_code;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// map translation to locale
|
|
|
|
// map translation to locale
|
|
|
|
if ( !array_key_exists($translation_code, self::$locales) ) {
|
|
|
|
if ( !array_key_exists($translation_code, self::$locales) ) {
|
|
|
|
// weird. maybe you added a translation but haven't added a
|
|
|
|
// weird. maybe you added a translation but haven't added a
|
|
|
@ -285,7 +300,7 @@ class L10n {
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$locale = self::$locales[$translation_code];
|
|
|
|
$locale = self::$locales[$translation_code];
|
|
|
|
|
|
|
|
|
|
|
|
// set up locale
|
|
|
|
// set up locale
|
|
|
|
if ( !putenv("LANG=$locale") ) {
|
|
|
|
if ( !putenv("LANG=$locale") ) {
|
|
|
|
trigger_error("L10n::set_translation(): could not set the ".
|
|
|
|
trigger_error("L10n::set_translation(): could not set the ".
|
|
|
@ -297,42 +312,42 @@ class L10n {
|
|
|
|
"LC_ALL to $locale", E_USER_WARNING);
|
|
|
|
"LC_ALL to $locale", E_USER_WARNING);
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// only set if we're running in a server not in a script
|
|
|
|
// only set if we're running in a server not in a script
|
|
|
|
if (isset($_SESSION)) {
|
|
|
|
if (isset($_SESSION)) {
|
|
|
|
// save the setting
|
|
|
|
// save the setting
|
|
|
|
$_SESSION['_config']['language'] = $translation_code;
|
|
|
|
$_SESSION['_config']['language'] = $translation_code;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set up the recode settings needed e.g. in PDF creation
|
|
|
|
// Set up the recode settings needed e.g. in PDF creation
|
|
|
|
$_SESSION['_config']['recode'] = "html..latin-1";
|
|
|
|
$_SESSION['_config']['recode'] = "html..latin-1";
|
|
|
|
|
|
|
|
|
|
|
|
if($translation_code === "zh-cn" || $translation_code === "zh-tw")
|
|
|
|
if($translation_code === "zh-cn" || $translation_code === "zh-tw")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
$_SESSION['_config']['recode'] = "html..gb2312";
|
|
|
|
$_SESSION['_config']['recode'] = "html..gb2312";
|
|
|
|
|
|
|
|
|
|
|
|
} else if($translation_code === "pl" || $translation_code === "hu") {
|
|
|
|
} else if($translation_code === "pl" || $translation_code === "hu") {
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-2";
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-2";
|
|
|
|
|
|
|
|
|
|
|
|
} else if($translation_code === "ja") {
|
|
|
|
} else if($translation_code === "ja") {
|
|
|
|
$_SESSION['_config']['recode'] = "html..SHIFT-JIS";
|
|
|
|
$_SESSION['_config']['recode'] = "html..SHIFT-JIS";
|
|
|
|
|
|
|
|
|
|
|
|
} else if($translation_code === "ru") {
|
|
|
|
} else if($translation_code === "ru") {
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-5";
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-5";
|
|
|
|
|
|
|
|
|
|
|
|
} else if($translation_code == "lt") { // legacy, keep for reference
|
|
|
|
} else if($translation_code == "lt") { // legacy, keep for reference
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-13";
|
|
|
|
$_SESSION['_config']['recode'] = "html..ISO-8859-13";
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Sets up the text domain used by gettext
|
|
|
|
* Sets up the text domain used by gettext
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param string $domain
|
|
|
|
* @param string $domain
|
|
|
|
* the gettext domain that should be used, defaults to "messages"
|
|
|
|
* the gettext domain that should be used, defaults to "messages"
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|