Quick attempt at correcting the English in the plural forms section
[squirrelmail.git] / doc / i18n.txt
1
2     *************************************
3     * SquirrelMail internationalization *
4     *************************************
5
6 $Date$
7 $Revision$
8
9 This document should explain how SquirrelMail internationalization works and
10 provide information about some aspects of implementation.
11
12 1. Supported languages
13 2. $languages array
14 3. XTRA_CODE functions
15 4. Display of different charsets
16 5. IMAP folder names
17 6. Plural forms
18 7. Language setup
19 8. Time zones
20
21 -------------------------------
22 1. Supported languages
23 -------------------------------
24 Valid language codes are:
25 * ar    - Arabic, windows-1256 charset
26 * bg_BG - Bulgarian, windows-1251 charset
27 * bn_IN - Bengali, utf-8 charset
28 * ca_ES - Catalan, iso-8859-1 charset
29 * cs_CZ - Czech, iso-8859-2 charset
30 * cy_GB - Welsh, iso-8859-1 charset
31 * da_DK - Danish, iso-8859-1 charset
32 * de_DE - German, iso-8859-1 charset
33 * el_GR - Greek, iso-8859-7 charset
34 * en_GB - British, iso-8859-15 charset
35 * en_US - English, charset depends on $default_charset
36 * es_ES - Spanish, iso-8859-1 charset
37 * et_EE - Estonian, iso-8859-15 charset
38 * eu_ES - Basque, iso-8859-1 charset
39 * fa_IR - Farsi, utf-8 charset
40 * fi_FI - Finnish, iso-8859-1 charset
41 * fo_FO - Faroese, iso-8859-1 charset
42 * fr_FR - French, iso-8859-1 charset
43 * he_IL - Hebrew, windows-1255 charset
44 * hr_HR - Croatian, iso-8859-2 charset
45 * hu_HU - Hungarian, iso-8859-2 charset
46 * id_ID - Indonesian, iso-8859-1 charset
47 * is_IS - Icelandic, iso-8859-1 charset
48 * it_IT - Italian, iso-8859-1 charset
49 * ja_JP - Japanese, euc-jp charset (emails are created in iso-2022-jp)
50 * ko_KR - Korean, euc-kr charset
51 * lt_LT - Lithuanian, utf-8 charset
52 * ms_MY - Malay, iso-8859-1 charset
53 * nb_NO - Norwegian (Bokmal), iso-8859-1 charset
54 * nl_NL - Dutch, iso-8859-1 charset
55 * nn_NO - Norwegian (Nynorsk), iso-8859-1 charset
56 * pl_PL - Polish, iso-8859-2 charset
57 * pt_BR - Portuguese (Brazil), iso-8859-1 charset
58 * pt_PT - Portuguese (Portugal), iso-8859-1 charset
59 * ro_RO - Romanian, iso-8859-2 charset
60 * ru_UA - Ukrainian Russian, koi8-r charset
61 * ru_RU - Russian, utf-8 charset
62 * sk_SK - Slovak, iso-8859-2 charset
63 * sl_SI - Slovenian, iso-8859-2 charset
64 * sr_YU - Serbian, iso-8859-2 charset
65 * sv_SE - Swedish, iso-8859-1 charset
66 * ug    - Uighur, utf-8 charset (some systems don't support Uighur system locale)
67 * th_TH - Thai, tis-620 charset
68 * tl_PH - Tagalog, iso-8859-1 charset (main translation is missing, only some plugins are translated)
69 * tr_TR - Turkish, iso-8859-9 charset
70 * uk_UA - Ukrainian, koi8-u charset
71 * zh_CN - Chinese Simplified, gb2312 charset
72 * zh_TW - Chinese Traditional, big5 charset
73
74 Charset totals:
75 * iso-8859-1   = 21
76 * iso-8859-2   = 8
77 * utf-8        = 5 
78 * iso-8859-15  = 2
79 * iso-8859-7   = 1
80 * iso-8859-9   = 1
81 * koi8-r       = 1
82 * koi8-u       = 1
83 * windows-1251 = 1
84 * windows-1255 = 1
85 * windows-1256 = 1
86 * tis-620      = 1
87 * gb2312       = 1
88 * big5         = 1
89 * euc-jp       = 1
90 * euc-kr       = 1
91
92 -------------------
93 2. $languages array
94 -------------------
95 $languages array is stored in functions/i18n.php (v. 1.5.0 or older) or 
96 locale/*/setup.php files and defines enabled SquirrelMail translations.
97
98 Format of array:
99     $languages['language_code']['key'] = 'value'
100
101 Possible array key names:
102 * NAME      - Translation name in English. Any 8bit symbols must be html encoded.
103 * CHARSET   - Charset used by translation
104 * ALIAS     - 'language_code' should contain short language name
105               (iso-639). 'value' should contain name of other 'language_code'
106               that defines translation with NAME and CHARSET keys.
107               Entry links short language form with long form (language+country).
108               See: http://www.loc.gov/standards/iso639-2/langhome.html and
109               http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
110 * ALTNAME   - Native translation name. Any 8bit symbols must be html encoded.
111               Name is visible when $show_alternative_names is enabled.
112 * LOCALE    - Full locale name (in xx_XX.charset format or other format required
113               by php gettext functions). From 1.4.4/1.5.1 'value' can contain
114               array. If php version is older than 4.3.0, system uses only first
115               locale name listed in array. First locale name must be compatible 
116               with FreeBSD system locale names.
117 * DIR       - Text direction. Used to define Right-to-Left languages. Possible 
118               values 'rtl' or 'ltr'. If undefined - defaults to 'ltr'.
119 * XTRA_CODE - translation uses special functions. (see chapter 3. XTRA_CODE functions)
120
121 Each 'language_code' definition requires NAME+CHARSET or ALIAS keys. Other keys are
122 optional.
123
124 ----------------------
125 3. XTRA_CODE functions
126 ----------------------
127 XTRA_CODE functions provide way to change interface behavior, when translation
128 requires special handling of some SquirrelMail functions. Functions are enabled
129 by setting XTRA_CODE option in $languages array and including appropriate
130 functions in locale/language_code/setup.php. First part of function name is word 
131 listed in $languages['language_code']['XTRA_CODE'] value. Second part is one of special
132 keywords. Possible keywords:
133 * _decode
134 Used in src/compose.php, src/i18n.php, src/view_text.php, functions/mime.php
135 Requires mbstring support
136
137 * _encode
138 Used in src/compose.php, src/read_body.php
139
140 * _encodeheader
141 Used in functions/mime.php
142 Returning function
143
144 * _decodeheader
145 Used in functions/mime.php
146 Returning function
147
148 * _downloadfilename
149 Used in functions/mime.php
150
151 * _utf7_imap_encode
152 Used in functions/imap_utf7_local.php
153 Returning function
154
155 * _utf7_imap_decode
156 Used in functions/imap_utf7_local.php
157 Returning function
158
159 * _strimwidth
160 Used in functions/mailbox_display.php
161 Returning function
162
163 * _wordwrap
164 Used in functions/strings.php (sqWordWrap)
165
166 --------------------------------
167 4. Display of different charsets
168 --------------------------------
169 When SquirrelMail generates html pages, it uses charset defined in translation
170 selected by end user. Interface can display emails encoded in different
171 charsets. In order to display characters that might be unsupported by user's
172 charset, SquirrelMail uses decoding functions that convert non us-ascii symbols
173 into html entities. All decoding functions are stored in functions/decode/
174 directory.
175
176 By default SquirrelMail includes decoding functions that support iso-8859-x,
177 windows-125x, utf-8, us-ascii, koi8-r, koi8-u, tis-620, ns-4551_1, iso-ir-111,
178 cp855 and cp866 charsets. Other decoding functions are distributed in separate
179 packages. Separate packaging of decoding functions is supported from
180 SquirrelMail 1.4.4 and 1.5.0. us-ascii decoding replaces all 8bit symbols with
181 question marks. utf-8 decoding function does not enable decoding of five and six
182 byte utf-8 symbols by default (code is commented) and replaces all incorrectly
183 formated 8bit symbols with question marks.
184
185 Some decoding functions might require php recode extension or php 4.3+ mbstring
186 extension. If your php installation does not support them, you might be using 
187 slower and cpu/memory intensive functions.
188
189 --------------------
190 5. IMAP folder names
191 --------------------
192 IMAP folder names use UTF7-IMAP charset. Folder names that are stored in
193 conf.pl must be encoded in UTF7-IMAP charset. SquirrelMail uses internal
194 functions that convert folder names from/to utf7-imap charset. By default those
195 functions work with iso-8859-1 charset. Other charsets are supported only 
196 when php mbstring extension supports them.
197
198 TODO: write independent implementation of charset to utf7-imap conversion.
199
200 ---------------
201 6. Plural forms
202 ---------------
203 From v.1.5.1 SquirrelMail includes support for plural forms. It allows the use
204 of correct translation forms with numbers. For example. "We have %s squirrel
205 on the roof." and "We have %s squirrels on the roof." can be written in one 
206 function call without checking actual number of squirrels. The gettext
207 functions also deal with non English languages that might use different word
208 forms for two, five, ten or more units.
209
210 Plural forms support is provided by ngettext functions that exist in the php
211 gettext extension as of php 4.2.0 and by ngettext function replacements from
212 the php-gettext classes (http://savannah.nongnu.org/projects/php-gettext).
213 In order to provide identical functionality when the php gettext extension does
214 not have ngettext support, SquirrelMail uses bindtextdomain and textdomain
215 wrappers that load the missing functions.
216
217 If plugin authors want to use ngettext functions without increasing php
218 requirements to 4.2.0 with gettext support, they should require at least
219 SquirrelMail 1.5.1, and use the sq_change_text_domain function instead of
220 separate calls to bindtextdomain and textdomain. If sq_change_text_domain
221 cannot be used, the sq_bindtextdomain function should be used instead of
222 bindtextdomain and the sq_textdomain function should be used instead of the
223 textdomain function. If these latter two SquirrelMail wrapper functions are
224 used (but again, please use sq_change_text_domain), there is no need to issue
225 a call to sq_bindtextdomain when a plugin reverts to the SquirrelMail domain.
226
227 More information about ngettext and plural forms can be found at:
228 http://www.gnu.org/software/gettext/manual/html_chapter/gettext_10.html#SEC150
229
230 -----------------
231 7. Language setup
232 -----------------
233 SquirrelMail uses set_up_language() function to setup language environment.
234 Environment is setup automatically when include/validate.php is loaded.
235
236 SquirrelMail gets interface language from three places:
237  a) user preference. It is set in Options -> Display Preferences -> Language.
238     preference uses language key. If user's preferences are not available (user
239     is not logged in), system tries to extract language value from 
240     'squirrelmail_language' cookie.
241  b) default squirrelmail language that is set in configuration 
242     ($squirrelmail_default_language variable).
243  c) preferred language setting provided by browser. It is used only when default 
244     squirrelmail language is set to empty string
245
246 If language information is not available, SquirrelMail falls back to US English
247 translation.
248
249 -------------
250 8. Time zones
251 -------------
252 If php install allows modifying environment variable TZ, SquirrelMail allows
253 end users to select different time zone in their preferences. It can be set in
254 Options -> Personal Information -> Your current timezone. Time zone is
255 setup automatically when include/validate.php is loaded.
256
257 If TZ variable can't be modified (php is running is safe mode and variable 
258 is not listed in php safe_mode_allowed_env_vars), user's time zone options are
259 not visible and interface uses default webserver's time zone.
260
261 SquirrelMail 1.5.0 and older store list of available time zones in 
262 locale/timezones.cfg. Since 1.5.1 standard times zones are moved to 
263 include/timezones/standard.php and time zone handling differs from older
264 SquirrelMail versions. Time zone configuration is controlled in SquirrelMail
265 configuration utility (conf.pl), 4. General Options -> 15. Time zone
266 configuration menu option. Administrator can select standard, strict, custom 
267 and custom strict time zone handling.
268
269 Standard handling does not differ from previous SquirrelMail versions and
270 SquirrelMail uses GNU C geographical location based time zone names. Strict
271 handling uses time zone codes with offset from GMT. Strict time zones should
272 work on systems that don't support GNU C time zone naming. Custom and custom
273 strict handling uses config/timezones.php file instead of
274 include/timezones/standard.php.
275
276 config/timezones.php file should store $aTimeZones array with different set of
277 time zones. See default time zone set in include/timezones/standard.php.For
278 example:
279
280 <?php
281 // World outside US border is a mirage
282
283 $aTimeZones=array();
284 $aTimeZones['America/New_York']['NAME']='US Eastern standard time';
285 $aTimeZones['America/New_York']['TZ']='EST5EDT';
286
287 $aTimeZones['America/Chicago']['NAME']='US Central standard time';
288 $aTimeZones['America/Chicago']['TZ']='CST6CDT';
289
290 // Oliver County, ND
291 $aTimeZones['America/North_Dakota/Center']['NAME']='US, Oliver County [ND]';
292 $aTimeZones['America/North_Dakota/Center']['TZ']='CST6CDT'; // CST since 1992
293
294 $aTimeZones['America/Denver']['NAME']='US Mountain standard time';
295 $aTimeZones['America/Denver']['TZ']='MST7MDT';
296
297 $aTimeZones['America/Los_Angeles']['NAME']='US Pacific standard time';
298 $aTimeZones['America/Los_Angeles']['TZ']='PST8PDT';
299
300 // Aliaska
301 $aTimeZones['America/Juneau']['NAME']='Aliaska, Juneau';
302 $aTimeZones['America/Juneau']['TZ']='NAST9NADT';
303 $aTimeZones['America/Yakutat']['NAME']='Aliaska, Yakutat';
304 $aTimeZones['America/Yakutat']['TZ']='NAST9NADT';
305 $aTimeZones['America/Anchorage']['NAME']='Aliaska, Anchorage';
306 $aTimeZones['America/Anchorage']['TZ']='NAST9NADT';
307 $aTimeZones['America/Nome']['NAME']='Aliaska, Nome';
308 $aTimeZones['America/Nome']['TZ']='NAST9NADT';
309 $aTimeZones['America/Adak']['NAME']='US, Aleutian Islands';
310 $aTimeZones['America/Adak']['TZ']='AST10ADT';
311
312 $aTimeZones['Pacific/Honolulu']['NAME']='US, Hawaii';
313 $aTimeZones['Pacific/Honolulu']['TZ']='UCT10';
314 $aTimeZones['America/Phoenix']['NAME']='US, Arizona';
315 $aTimeZones['America/Phoenix']['TZ']='MST7'; // gmt-7
316 $aTimeZones['America/Shiprock']['LINK']='America/Denver';
317
318 $aTimeZones['America/Boise']['NAME']='US, South Idaho';
319 $aTimeZones['America/Boise']['TZ']='MST7MDT';
320 $aTimeZones['America/Indianapolis']['NAME']='US, Indiana';
321 $aTimeZones['America/Indianapolis']['TZ']='EST5';
322 $aTimeZones['America/Indiana/Indianapolis']['LINK']='America/Indianapolis';
323 // Crawford County, Indiana
324 $aTimeZones['America/Indiana/Marengo']['NAME']='US, Crawford County [IN]';
325 $aTimeZones['America/Indiana/Marengo']['TZ']='EST5';
326 // Starke County, Indiana
327 $aTimeZones['America/Indiana/Knox']['NAME']='US, Starke County [IN]';
328 $aTimeZones['America/Indiana/Knox']['TZ']='EST5';
329 // Switzerland County, Indiana
330 $aTimeZones['America/Indiana/Vevay']['NAME']='US, Switzerland County [IN]';
331 $aTimeZones['America/Indiana/Vevay']['TZ']='EST5';
332 $aTimeZones['America/Louisville']['NAME']='US, Louisville [KY]';
333 $aTimeZones['America/Louisville']['TZ']='EST5EDT';
334 $aTimeZones['America/Kentucky/Louisville']['LINK']='America/Louisville';
335 // Wayne, Clinton, and Russell Counties, Kentucky
336 $aTimeZones['America/Kentucky/Monticello']['NAME']='US, Wayne, Clinton, and Russell Counties [KY]';
337 $aTimeZones['America/Kentucky/Monticello']['TZ']='EST5EDT';
338 // Michigan
339 $aTimeZones['America/Detroit']['NAME']='US, Michigan';
340 $aTimeZones['America/Detroit']['TZ']='EST5EDT';
341 // The Michigan border with Wisconsin switched from EST to CST/CDT in 1973.
342 $aTimeZones['America/Menominee']['NAME']='US, Menominee [MI]';
343 $aTimeZones['America/Menominee']['TZ']='CST6CDT';
344 ?>
345
346 GNU C time zone naming should be supported by many Unix OSes. It is recommended
347 way of setting time zone, because it handles historical changes and daylight
348 savings specific to selected geographical location. Strict time zones might
349 provide inaccurate or outdated time zone settings.
350
351 If modifications in TZ environment are visible in your webserver's logs (time
352 offset is changed), make sure that you can reproduce such behavior in latest php
353 version and report bug to php developers. Issue can be fixed by blocking use of
354 time zone (php safe mode and TZ is not listed in safe_mode_allowed_env_vars
355 setting or forced_prefs plugin) or by attaching special php script with 
356 putenv('TZ=some time zone') call in php auto_append_file setting (suggestion is
357 not tested and you might have to fix all SquirrelMail exit calls).
358
359 Please note, that use of auto_append_file provides only temporally workaround
360 and does not fix your php setup. Script that runs as unprivileged user, should
361 be unable to affect webserver's logging system.
362