00001 <?php
00002 # This file is part of the Savane project
00003 # <http://gna.org/projects/savane/>
00004 #
00005 # $Id: i18n.php 4567 2005-06-30 17:19:37Z toddy $
00006 #
00007 # Copyright 2003-2004 (c) Stéphane Urbanovski <s.urbanovski@ac-nancy-metz.fr>
00008 # Mathieu Roy <yeupou--at--gnu.org>
00009 #
00010 # The Savane project is free software; you can redistribute it and/or
00011 # modify it under the terms of the GNU General Public License
00012 # as published by the Free Software Foundation; either version 2
00013 # of the License, or (at your option) any later version.
00014 #
00015 # The Savane project is distributed in the hope that it will be useful,
00016 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00018 # GNU General Public License for more details.
00019 #
00020 # You should have received a copy of the GNU General Public License
00021 # along with the Savane project; if not, write to the Free Software
00022 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00023
00024 # Description : This script is used to configure the locale using if possible
00025 # the user's navigator preferences. The locale is used by gettext and strftime
00026 # functions.
00027
00028 # Should we use _ENV["LANG"] also?
00029
00030
00031 # Get the user's prefered language from the navigator sended headers :
00032 $navigatorLanguages = explode(",",getenv("HTTP_ACCEPT_LANGUAGE"));
00033
00034 # Set the default language :
00035 $locale = $GLOBALS['sys_default_locale'];
00036
00037
00038 # Table of supported languages :
00039 # "lang" => "associated prefered sublanguage"
00040 $supportedLanguages = array(
00041 "de" => "DE.UTF-8",
00042 "de_DE" => "DE.UTF-8",
00043 "en" => "US.UTF-8",
00044 "fr" => "FR.UTF-8",
00045 "fr_FR" => "FR.UTF-8",
00046 "it" => "IT.UTF-8",
00047 "it_IT" => "IT.UTF-8",
00048 "ja" => "JP.UTF-8",
00049 "ja_JP" => "JP.UTF-8",
00050 "ko" => "KR.UTF-8",
00051 "ko_KR" => "KR.UTF-8",
00052 "pt" => "BR.UTF-8",
00053 "pt_BR" => "BR.UTF-8",
00054 "ru" => "RU.UTF-8",
00055 "ru_RU" => "RU.UTF-8"
00056 );
00057
00058 # Try to find the best supported language from user's navigator preferences :
00059 while (list(, $lng) = each ($navigatorLanguages)) {
00060
00061 $lng = trim($lng);
00062 $curlocale = strtolower(substr($lng,0,2));
00063 if (substr($lng,2,1) == "-") {
00064 $sublocale = $curlocale."_".strtoupper(substr($lng,3,2));
00065 if ( isset($supportedLanguages[$sublocale] )) {
00066 $locale = $curlocale."_".$supportedLanguages[$sublocale];
00067 define(SV_LANG, $curlocale."-".$supportedLanguages[$sublocale]);
00068 break;
00069 }
00070 }
00071 if ( isset($supportedLanguages[$curlocale] )) {
00072 $locale = $curlocale."_".$supportedLanguages[$curlocale];
00073 define(SV_LANG, $curlocale."-".$supportedLanguages[$curlocale]);
00074 break;
00075 }
00076
00077 }
00078
00079 # Set the locale used by gettext() and strftime() functions :
00080 setlocale(LC_ALL, $locale);
00081
00082 # Gettext (i18n) configs :
00083 textdomain('savane');
00084
00085
00086 #print "[".$locale.",".setlocale(LC_ALL,0)."]"; //debug
00087
00088 # this provides a custom ngettext() function for PHP versions < 4.2
00089 # it should have the same functionality, but note that there is the
00090 # encoding of the po-file hardcoded to speed things up
00091 if (!function_exists("ngettext")) {
00092 function ngettext($string1, $string2, $n)
00093 {
00094 $locale = setlocale(LC_ALL, 0);
00095 # strip possible charset extension from the locale (e.g. "de_DE.UTF-8")
00096 $locale = array_shift(explode(".", $locale));
00097
00098 # assume a sane default for the return value
00099 if ($n != 1)
00100 {
00101 $msgstr = $string2;
00102 }
00103 else
00104 {
00105 $msgstr = $string1;
00106 }
00107
00108 # FIXME: This should not be hardcoded, but taken from the configure
00109 # script input somehow.
00110 $mo_file = "/usr/share/locale/".$locale."/LC_MESSAGES/savane.mo";
00111 $alternative[] = "/usr/share/locale/".substr($locale, 0, 2)."/LC_MESSAGES/savane.mo";
00112 $alternative[] = "/usr/local/share/locale/".$locale."/LC_MESSAGES/savane.mo";
00113 $alternative[] = "/usr/local/share/locale/".substr($locale, 0, 2)."/LC_MESSAGES/savane.mo";
00114
00115 foreach ($alternative as $location)
00116 {
00117 if (is_readable($location))
00118 {
00119 $mo_file = $location;
00120 break;
00121 }
00122 }
00123
00124 # fallback, also used for English
00125 if (!is_readable($mo_file))
00126 {
00127 return $msgstr;
00128 }
00129
00130 # open mo file for binary reading
00131 $mo = fopen($mo_file, "rb");
00132
00133 # get the number of strings
00134 fseek($mo, 8);
00135 $str_count = array_pop(unpack("L", fread($mo, 4)));
00136
00137 # read in the start of the msgids and msgstrs
00138 fseek($mo, 12);
00139 $start = unpack("Loriginal/Ltranslation", fread($mo, 8));
00140
00141 # read in the table for the lengths and offsets for the msgids
00142 fseek($mo, $start['original']);
00143 $msgids = fread($mo, $str_count*8);
00144 for ($q = 0; $q < $str_count; $q++)
00145 {
00146 $original[$q] = unpack("Llength/Loffset", substr($msgids, $q*8, 8));
00147 }
00148
00149 # read the msgids in, until the specified msgid is found
00150 $found = false;
00151 for ($q = 0; $q < $str_count; $q++)
00152 {
00153 fseek($mo, $original[$q]['offset']);
00154 if ($original[$q]['length'] != 0)
00155 {
00156 $msgid = array_pop(unpack("a*", fread($mo, $original[$q]['length'])));
00157 if ($msgid == $string1."\0".$string2)
00158 {
00159 $msgid = $q;
00160 $found = true;
00161 break;
00162 }
00163 }
00164 }
00165
00166 if (!$found)
00167 {
00168 return $msgstr;
00169 }
00170
00171 # get the length and offset for the corresponding msgstr
00172 fseek($mo, $start['translation'] + 8*$msgid);
00173 $translation = unpack("Llength/Loffset", fread($mo, 8));
00174
00175 # read the msgstr
00176 fseek($mo, $translation['offset']);
00177 if ($translation['length'] != 0)
00178 {
00179 $msgstr = array_pop(unpack("a*", fread($mo, $translation['length'])));
00180 }
00181
00182 # the plural forms rule needs to be hardcoded, because
00183 # the PHP operator precedence differs a little bit from
00184 # the one C uses -> the plural rule provided in the po-file
00185 # does not work for complicated rules (e.g. Russian)
00186 #
00187 # for the canonical rules see
00188 # <http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150>
00189 $plural_rule["de_DE"] = ($n != 1);
00190 $plural_rule["fr_FR"] = ($n > 1);
00191 $plural_rule["it_IT"] = ($n != 1);
00192 $plural_rule["ja_JP"] = 0;
00193 $plural_rule["ko_KR"] = 0;
00194 $plural_rule["pt_BR"] = ($n > 1);
00195 $plural_rule["ru_RU"] = ($n%10 == 1 && $n%100 != 11 ? 0 : ($n%10 >= 2 && $n%10 <= 4 && ($n%100 < 10 || $n%100 >= 20) ? 1 : 2));
00196
00197 # if there's no plural rule defined, use a generic one
00198 if (!isset($plural_rule[$locale]))
00199 {
00200 $plural_rule[$locale] = 0;
00201 }
00202
00203 # split the msgstr into the different plural forms
00204 $plural = preg_split("/\\x00/", $msgstr);
00205
00206 # finally, find the msgstr that's wanted ...
00207 $msgstr = $plural[$plural_rule[$locale]];
00208
00209 fclose($mo);
00210
00211 return $msgstr;
00212 }
00213 }
00214 ?>