Roll src/third_party/WebKit 3529d49:06e8485 (svn 202554:202555)
[chromium-blink-merge.git] / remoting / tools / build / remoting_localize.py
blobf1f437bd5c3550af1e63629d9e02063fd846fb5a
1 #!/usr/bin/env python
2 # Copyright 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """
7 localize.py -- Generates an output file from the given template replacing
8 variables and localizing strings.
10 The script uses Jinja2 template processing library (src/third_party/jinja2).
11 Variables available to the templates:
12 - |languages| - the list of languages passed on the command line. ('-l').
13 - Each NAME=VALUE define ('-d') can be accesses as {{ NAME }}.
14 - |official_build| is set to '1' when CHROME_BUILD_TYPE environment variable
15 is set to "_official".
17 Filters:
18 - GetCodepage - returns the code page for the given language.
19 - GetCodepageDecimal same as GetCodepage, but returns a decimal value.
20 - GetLangId - returns Win32 LANGID.
21 - GetPrimaryLanguage - returns a named Win32 constant specifing the primary
22 language ID.
23 - GetSublanguage - returns a named Win32 constant specifing the sublanguage
24 ID.
26 Globals:
27 - IsRtlLanguage(language) - returns True if the language is right-to-left.
28 - SelectLanguage(language) - allows to select the language to the used by
29 {% trans %}{% endtrans %} statements.
31 """
33 import io
34 import json
35 from optparse import OptionParser
36 import os
37 import sys
38 from string import Template
41 # Win32 primary languages IDs.
42 _LANGUAGE_PRIMARY = {
43 'LANG_NEUTRAL' : 0x00,
44 'LANG_INVARIANT' : 0x7f,
45 'LANG_AFRIKAANS' : 0x36,
46 'LANG_ALBANIAN' : 0x1c,
47 'LANG_ALSATIAN' : 0x84,
48 'LANG_AMHARIC' : 0x5e,
49 'LANG_ARABIC' : 0x01,
50 'LANG_ARMENIAN' : 0x2b,
51 'LANG_ASSAMESE' : 0x4d,
52 'LANG_AZERI' : 0x2c,
53 'LANG_BASHKIR' : 0x6d,
54 'LANG_BASQUE' : 0x2d,
55 'LANG_BELARUSIAN' : 0x23,
56 'LANG_BENGALI' : 0x45,
57 'LANG_BRETON' : 0x7e,
58 'LANG_BOSNIAN' : 0x1a,
59 'LANG_BULGARIAN' : 0x02,
60 'LANG_CATALAN' : 0x03,
61 'LANG_CHINESE' : 0x04,
62 'LANG_CORSICAN' : 0x83,
63 'LANG_CROATIAN' : 0x1a,
64 'LANG_CZECH' : 0x05,
65 'LANG_DANISH' : 0x06,
66 'LANG_DARI' : 0x8c,
67 'LANG_DIVEHI' : 0x65,
68 'LANG_DUTCH' : 0x13,
69 'LANG_ENGLISH' : 0x09,
70 'LANG_ESTONIAN' : 0x25,
71 'LANG_FAEROESE' : 0x38,
72 'LANG_FILIPINO' : 0x64,
73 'LANG_FINNISH' : 0x0b,
74 'LANG_FRENCH' : 0x0c,
75 'LANG_FRISIAN' : 0x62,
76 'LANG_GALICIAN' : 0x56,
77 'LANG_GEORGIAN' : 0x37,
78 'LANG_GERMAN' : 0x07,
79 'LANG_GREEK' : 0x08,
80 'LANG_GREENLANDIC' : 0x6f,
81 'LANG_GUJARATI' : 0x47,
82 'LANG_HAUSA' : 0x68,
83 'LANG_HEBREW' : 0x0d,
84 'LANG_HINDI' : 0x39,
85 'LANG_HUNGARIAN' : 0x0e,
86 'LANG_ICELANDIC' : 0x0f,
87 'LANG_IGBO' : 0x70,
88 'LANG_INDONESIAN' : 0x21,
89 'LANG_INUKTITUT' : 0x5d,
90 'LANG_IRISH' : 0x3c,
91 'LANG_ITALIAN' : 0x10,
92 'LANG_JAPANESE' : 0x11,
93 'LANG_KANNADA' : 0x4b,
94 'LANG_KASHMIRI' : 0x60,
95 'LANG_KAZAK' : 0x3f,
96 'LANG_KHMER' : 0x53,
97 'LANG_KICHE' : 0x86,
98 'LANG_KINYARWANDA' : 0x87,
99 'LANG_KONKANI' : 0x57,
100 'LANG_KOREAN' : 0x12,
101 'LANG_KYRGYZ' : 0x40,
102 'LANG_LAO' : 0x54,
103 'LANG_LATVIAN' : 0x26,
104 'LANG_LITHUANIAN' : 0x27,
105 'LANG_LOWER_SORBIAN' : 0x2e,
106 'LANG_LUXEMBOURGISH' : 0x6e,
107 'LANG_MACEDONIAN' : 0x2f,
108 'LANG_MALAY' : 0x3e,
109 'LANG_MALAYALAM' : 0x4c,
110 'LANG_MALTESE' : 0x3a,
111 'LANG_MANIPURI' : 0x58,
112 'LANG_MAORI' : 0x81,
113 'LANG_MAPUDUNGUN' : 0x7a,
114 'LANG_MARATHI' : 0x4e,
115 'LANG_MOHAWK' : 0x7c,
116 'LANG_MONGOLIAN' : 0x50,
117 'LANG_NEPALI' : 0x61,
118 'LANG_NORWEGIAN' : 0x14,
119 'LANG_OCCITAN' : 0x82,
120 'LANG_ORIYA' : 0x48,
121 'LANG_PASHTO' : 0x63,
122 'LANG_PERSIAN' : 0x29,
123 'LANG_POLISH' : 0x15,
124 'LANG_PORTUGUESE' : 0x16,
125 'LANG_PUNJABI' : 0x46,
126 'LANG_QUECHUA' : 0x6b,
127 'LANG_ROMANIAN' : 0x18,
128 'LANG_ROMANSH' : 0x17,
129 'LANG_RUSSIAN' : 0x19,
130 'LANG_SAMI' : 0x3b,
131 'LANG_SANSKRIT' : 0x4f,
132 'LANG_SCOTTISH_GAELIC' : 0x91,
133 'LANG_SERBIAN' : 0x1a,
134 'LANG_SINDHI' : 0x59,
135 'LANG_SINHALESE' : 0x5b,
136 'LANG_SLOVAK' : 0x1b,
137 'LANG_SLOVENIAN' : 0x24,
138 'LANG_SOTHO' : 0x6c,
139 'LANG_SPANISH' : 0x0a,
140 'LANG_SWAHILI' : 0x41,
141 'LANG_SWEDISH' : 0x1d,
142 'LANG_SYRIAC' : 0x5a,
143 'LANG_TAJIK' : 0x28,
144 'LANG_TAMAZIGHT' : 0x5f,
145 'LANG_TAMIL' : 0x49,
146 'LANG_TATAR' : 0x44,
147 'LANG_TELUGU' : 0x4a,
148 'LANG_THAI' : 0x1e,
149 'LANG_TIBETAN' : 0x51,
150 'LANG_TIGRIGNA' : 0x73,
151 'LANG_TSWANA' : 0x32,
152 'LANG_TURKISH' : 0x1f,
153 'LANG_TURKMEN' : 0x42,
154 'LANG_UIGHUR' : 0x80,
155 'LANG_UKRAINIAN' : 0x22,
156 'LANG_UPPER_SORBIAN' : 0x2e,
157 'LANG_URDU' : 0x20,
158 'LANG_UZBEK' : 0x43,
159 'LANG_VIETNAMESE' : 0x2a,
160 'LANG_WELSH' : 0x52,
161 'LANG_WOLOF' : 0x88,
162 'LANG_XHOSA' : 0x34,
163 'LANG_YAKUT' : 0x85,
164 'LANG_YI' : 0x78,
165 'LANG_YORUBA' : 0x6a,
166 'LANG_ZULU' : 0x35,
170 # Win32 sublanguage IDs.
171 _LANGUAGE_SUB = {
172 'SUBLANG_NEUTRAL' : 0x00,
173 'SUBLANG_DEFAULT' : 0x01,
174 'SUBLANG_SYS_DEFAULT' : 0x02,
175 'SUBLANG_CUSTOM_DEFAULT' : 0x03,
176 'SUBLANG_CUSTOM_UNSPECIFIED' : 0x04,
177 'SUBLANG_UI_CUSTOM_DEFAULT' : 0x05,
178 'SUBLANG_AFRIKAANS_SOUTH_AFRICA' : 0x01,
179 'SUBLANG_ALBANIAN_ALBANIA' : 0x01,
180 'SUBLANG_ALSATIAN_FRANCE' : 0x01,
181 'SUBLANG_AMHARIC_ETHIOPIA' : 0x01,
182 'SUBLANG_ARABIC_SAUDI_ARABIA' : 0x01,
183 'SUBLANG_ARABIC_IRAQ' : 0x02,
184 'SUBLANG_ARABIC_EGYPT' : 0x03,
185 'SUBLANG_ARABIC_LIBYA' : 0x04,
186 'SUBLANG_ARABIC_ALGERIA' : 0x05,
187 'SUBLANG_ARABIC_MOROCCO' : 0x06,
188 'SUBLANG_ARABIC_TUNISIA' : 0x07,
189 'SUBLANG_ARABIC_OMAN' : 0x08,
190 'SUBLANG_ARABIC_YEMEN' : 0x09,
191 'SUBLANG_ARABIC_SYRIA' : 0x0a,
192 'SUBLANG_ARABIC_JORDAN' : 0x0b,
193 'SUBLANG_ARABIC_LEBANON' : 0x0c,
194 'SUBLANG_ARABIC_KUWAIT' : 0x0d,
195 'SUBLANG_ARABIC_UAE' : 0x0e,
196 'SUBLANG_ARABIC_BAHRAIN' : 0x0f,
197 'SUBLANG_ARABIC_QATAR' : 0x10,
198 'SUBLANG_ARMENIAN_ARMENIA' : 0x01,
199 'SUBLANG_ASSAMESE_INDIA' : 0x01,
200 'SUBLANG_AZERI_LATIN' : 0x01,
201 'SUBLANG_AZERI_CYRILLIC' : 0x02,
202 'SUBLANG_BASHKIR_RUSSIA' : 0x01,
203 'SUBLANG_BASQUE_BASQUE' : 0x01,
204 'SUBLANG_BELARUSIAN_BELARUS' : 0x01,
205 'SUBLANG_BENGALI_INDIA' : 0x01,
206 'SUBLANG_BENGALI_BANGLADESH' : 0x02,
207 'SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_LATIN' : 0x05,
208 'SUBLANG_BOSNIAN_BOSNIA_HERZEGOVINA_CYRILLIC' : 0x08,
209 'SUBLANG_BRETON_FRANCE' : 0x01,
210 'SUBLANG_BULGARIAN_BULGARIA' : 0x01,
211 'SUBLANG_CATALAN_CATALAN' : 0x01,
212 'SUBLANG_CHINESE_TRADITIONAL' : 0x01,
213 'SUBLANG_CHINESE_SIMPLIFIED' : 0x02,
214 'SUBLANG_CHINESE_HONGKONG' : 0x03,
215 'SUBLANG_CHINESE_SINGAPORE' : 0x04,
216 'SUBLANG_CHINESE_MACAU' : 0x05,
217 'SUBLANG_CORSICAN_FRANCE' : 0x01,
218 'SUBLANG_CZECH_CZECH_REPUBLIC' : 0x01,
219 'SUBLANG_CROATIAN_CROATIA' : 0x01,
220 'SUBLANG_CROATIAN_BOSNIA_HERZEGOVINA_LATIN' : 0x04,
221 'SUBLANG_DANISH_DENMARK' : 0x01,
222 'SUBLANG_DARI_AFGHANISTAN' : 0x01,
223 'SUBLANG_DIVEHI_MALDIVES' : 0x01,
224 'SUBLANG_DUTCH' : 0x01,
225 'SUBLANG_DUTCH_BELGIAN' : 0x02,
226 'SUBLANG_ENGLISH_US' : 0x01,
227 'SUBLANG_ENGLISH_UK' : 0x02,
228 'SUBLANG_ENGLISH_AUS' : 0x03,
229 'SUBLANG_ENGLISH_CAN' : 0x04,
230 'SUBLANG_ENGLISH_NZ' : 0x05,
231 'SUBLANG_ENGLISH_EIRE' : 0x06,
232 'SUBLANG_ENGLISH_SOUTH_AFRICA' : 0x07,
233 'SUBLANG_ENGLISH_JAMAICA' : 0x08,
234 'SUBLANG_ENGLISH_CARIBBEAN' : 0x09,
235 'SUBLANG_ENGLISH_BELIZE' : 0x0a,
236 'SUBLANG_ENGLISH_TRINIDAD' : 0x0b,
237 'SUBLANG_ENGLISH_ZIMBABWE' : 0x0c,
238 'SUBLANG_ENGLISH_PHILIPPINES' : 0x0d,
239 'SUBLANG_ENGLISH_INDIA' : 0x10,
240 'SUBLANG_ENGLISH_MALAYSIA' : 0x11,
241 'SUBLANG_ENGLISH_SINGAPORE' : 0x12,
242 'SUBLANG_ESTONIAN_ESTONIA' : 0x01,
243 'SUBLANG_FAEROESE_FAROE_ISLANDS' : 0x01,
244 'SUBLANG_FILIPINO_PHILIPPINES' : 0x01,
245 'SUBLANG_FINNISH_FINLAND' : 0x01,
246 'SUBLANG_FRENCH' : 0x01,
247 'SUBLANG_FRENCH_BELGIAN' : 0x02,
248 'SUBLANG_FRENCH_CANADIAN' : 0x03,
249 'SUBLANG_FRENCH_SWISS' : 0x04,
250 'SUBLANG_FRENCH_LUXEMBOURG' : 0x05,
251 'SUBLANG_FRENCH_MONACO' : 0x06,
252 'SUBLANG_FRISIAN_NETHERLANDS' : 0x01,
253 'SUBLANG_GALICIAN_GALICIAN' : 0x01,
254 'SUBLANG_GEORGIAN_GEORGIA' : 0x01,
255 'SUBLANG_GERMAN' : 0x01,
256 'SUBLANG_GERMAN_SWISS' : 0x02,
257 'SUBLANG_GERMAN_AUSTRIAN' : 0x03,
258 'SUBLANG_GERMAN_LUXEMBOURG' : 0x04,
259 'SUBLANG_GERMAN_LIECHTENSTEIN' : 0x05,
260 'SUBLANG_GREEK_GREECE' : 0x01,
261 'SUBLANG_GREENLANDIC_GREENLAND' : 0x01,
262 'SUBLANG_GUJARATI_INDIA' : 0x01,
263 'SUBLANG_HAUSA_NIGERIA_LATIN' : 0x01,
264 'SUBLANG_HEBREW_ISRAEL' : 0x01,
265 'SUBLANG_HINDI_INDIA' : 0x01,
266 'SUBLANG_HUNGARIAN_HUNGARY' : 0x01,
267 'SUBLANG_ICELANDIC_ICELAND' : 0x01,
268 'SUBLANG_IGBO_NIGERIA' : 0x01,
269 'SUBLANG_INDONESIAN_INDONESIA' : 0x01,
270 'SUBLANG_INUKTITUT_CANADA' : 0x01,
271 'SUBLANG_INUKTITUT_CANADA_LATIN' : 0x02,
272 'SUBLANG_IRISH_IRELAND' : 0x02,
273 'SUBLANG_ITALIAN' : 0x01,
274 'SUBLANG_ITALIAN_SWISS' : 0x02,
275 'SUBLANG_JAPANESE_JAPAN' : 0x01,
276 'SUBLANG_KANNADA_INDIA' : 0x01,
277 'SUBLANG_KASHMIRI_SASIA' : 0x02,
278 'SUBLANG_KASHMIRI_INDIA' : 0x02,
279 'SUBLANG_KAZAK_KAZAKHSTAN' : 0x01,
280 'SUBLANG_KHMER_CAMBODIA' : 0x01,
281 'SUBLANG_KICHE_GUATEMALA' : 0x01,
282 'SUBLANG_KINYARWANDA_RWANDA' : 0x01,
283 'SUBLANG_KONKANI_INDIA' : 0x01,
284 'SUBLANG_KOREAN' : 0x01,
285 'SUBLANG_KYRGYZ_KYRGYZSTAN' : 0x01,
286 'SUBLANG_LAO_LAO' : 0x01,
287 'SUBLANG_LATVIAN_LATVIA' : 0x01,
288 'SUBLANG_LITHUANIAN' : 0x01,
289 'SUBLANG_LOWER_SORBIAN_GERMANY' : 0x02,
290 'SUBLANG_LUXEMBOURGISH_LUXEMBOURG' : 0x01,
291 'SUBLANG_MACEDONIAN_MACEDONIA' : 0x01,
292 'SUBLANG_MALAY_MALAYSIA' : 0x01,
293 'SUBLANG_MALAY_BRUNEI_DARUSSALAM' : 0x02,
294 'SUBLANG_MALAYALAM_INDIA' : 0x01,
295 'SUBLANG_MALTESE_MALTA' : 0x01,
296 'SUBLANG_MAORI_NEW_ZEALAND' : 0x01,
297 'SUBLANG_MAPUDUNGUN_CHILE' : 0x01,
298 'SUBLANG_MARATHI_INDIA' : 0x01,
299 'SUBLANG_MOHAWK_MOHAWK' : 0x01,
300 'SUBLANG_MONGOLIAN_CYRILLIC_MONGOLIA' : 0x01,
301 'SUBLANG_MONGOLIAN_PRC' : 0x02,
302 'SUBLANG_NEPALI_INDIA' : 0x02,
303 'SUBLANG_NEPALI_NEPAL' : 0x01,
304 'SUBLANG_NORWEGIAN_BOKMAL' : 0x01,
305 'SUBLANG_NORWEGIAN_NYNORSK' : 0x02,
306 'SUBLANG_OCCITAN_FRANCE' : 0x01,
307 'SUBLANG_ORIYA_INDIA' : 0x01,
308 'SUBLANG_PASHTO_AFGHANISTAN' : 0x01,
309 'SUBLANG_PERSIAN_IRAN' : 0x01,
310 'SUBLANG_POLISH_POLAND' : 0x01,
311 'SUBLANG_PORTUGUESE' : 0x02,
312 'SUBLANG_PORTUGUESE_BRAZILIAN' : 0x01,
313 'SUBLANG_PUNJABI_INDIA' : 0x01,
314 'SUBLANG_QUECHUA_BOLIVIA' : 0x01,
315 'SUBLANG_QUECHUA_ECUADOR' : 0x02,
316 'SUBLANG_QUECHUA_PERU' : 0x03,
317 'SUBLANG_ROMANIAN_ROMANIA' : 0x01,
318 'SUBLANG_ROMANSH_SWITZERLAND' : 0x01,
319 'SUBLANG_RUSSIAN_RUSSIA' : 0x01,
320 'SUBLANG_SAMI_NORTHERN_NORWAY' : 0x01,
321 'SUBLANG_SAMI_NORTHERN_SWEDEN' : 0x02,
322 'SUBLANG_SAMI_NORTHERN_FINLAND' : 0x03,
323 'SUBLANG_SAMI_LULE_NORWAY' : 0x04,
324 'SUBLANG_SAMI_LULE_SWEDEN' : 0x05,
325 'SUBLANG_SAMI_SOUTHERN_NORWAY' : 0x06,
326 'SUBLANG_SAMI_SOUTHERN_SWEDEN' : 0x07,
327 'SUBLANG_SAMI_SKOLT_FINLAND' : 0x08,
328 'SUBLANG_SAMI_INARI_FINLAND' : 0x09,
329 'SUBLANG_SANSKRIT_INDIA' : 0x01,
330 'SUBLANG_SCOTTISH_GAELIC' : 0x01,
331 'SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_LATIN' : 0x06,
332 'SUBLANG_SERBIAN_BOSNIA_HERZEGOVINA_CYRILLIC' : 0x07,
333 'SUBLANG_SERBIAN_MONTENEGRO_LATIN' : 0x0b,
334 'SUBLANG_SERBIAN_MONTENEGRO_CYRILLIC' : 0x0c,
335 'SUBLANG_SERBIAN_SERBIA_LATIN' : 0x09,
336 'SUBLANG_SERBIAN_SERBIA_CYRILLIC' : 0x0a,
337 'SUBLANG_SERBIAN_CROATIA' : 0x01,
338 'SUBLANG_SERBIAN_LATIN' : 0x02,
339 'SUBLANG_SERBIAN_CYRILLIC' : 0x03,
340 'SUBLANG_SINDHI_INDIA' : 0x01,
341 'SUBLANG_SINDHI_PAKISTAN' : 0x02,
342 'SUBLANG_SINDHI_AFGHANISTAN' : 0x02,
343 'SUBLANG_SINHALESE_SRI_LANKA' : 0x01,
344 'SUBLANG_SOTHO_NORTHERN_SOUTH_AFRICA' : 0x01,
345 'SUBLANG_SLOVAK_SLOVAKIA' : 0x01,
346 'SUBLANG_SLOVENIAN_SLOVENIA' : 0x01,
347 'SUBLANG_SPANISH' : 0x01,
348 'SUBLANG_SPANISH_MEXICAN' : 0x02,
349 'SUBLANG_SPANISH_MODERN' : 0x03,
350 'SUBLANG_SPANISH_GUATEMALA' : 0x04,
351 'SUBLANG_SPANISH_COSTA_RICA' : 0x05,
352 'SUBLANG_SPANISH_PANAMA' : 0x06,
353 'SUBLANG_SPANISH_DOMINICAN_REPUBLIC' : 0x07,
354 'SUBLANG_SPANISH_VENEZUELA' : 0x08,
355 'SUBLANG_SPANISH_COLOMBIA' : 0x09,
356 'SUBLANG_SPANISH_PERU' : 0x0a,
357 'SUBLANG_SPANISH_ARGENTINA' : 0x0b,
358 'SUBLANG_SPANISH_ECUADOR' : 0x0c,
359 'SUBLANG_SPANISH_CHILE' : 0x0d,
360 'SUBLANG_SPANISH_URUGUAY' : 0x0e,
361 'SUBLANG_SPANISH_PARAGUAY' : 0x0f,
362 'SUBLANG_SPANISH_BOLIVIA' : 0x10,
363 'SUBLANG_SPANISH_EL_SALVADOR' : 0x11,
364 'SUBLANG_SPANISH_HONDURAS' : 0x12,
365 'SUBLANG_SPANISH_NICARAGUA' : 0x13,
366 'SUBLANG_SPANISH_PUERTO_RICO' : 0x14,
367 'SUBLANG_SPANISH_US' : 0x15,
368 'SUBLANG_SWAHILI_KENYA' : 0x01,
369 'SUBLANG_SWEDISH' : 0x01,
370 'SUBLANG_SWEDISH_FINLAND' : 0x02,
371 'SUBLANG_SYRIAC_SYRIA' : 0x01,
372 'SUBLANG_TAJIK_TAJIKISTAN' : 0x01,
373 'SUBLANG_TAMAZIGHT_ALGERIA_LATIN' : 0x02,
374 'SUBLANG_TAMIL_INDIA' : 0x01,
375 'SUBLANG_TATAR_RUSSIA' : 0x01,
376 'SUBLANG_TELUGU_INDIA' : 0x01,
377 'SUBLANG_THAI_THAILAND' : 0x01,
378 'SUBLANG_TIBETAN_PRC' : 0x01,
379 'SUBLANG_TIGRIGNA_ERITREA' : 0x02,
380 'SUBLANG_TSWANA_SOUTH_AFRICA' : 0x01,
381 'SUBLANG_TURKISH_TURKEY' : 0x01,
382 'SUBLANG_TURKMEN_TURKMENISTAN' : 0x01,
383 'SUBLANG_UIGHUR_PRC' : 0x01,
384 'SUBLANG_UKRAINIAN_UKRAINE' : 0x01,
385 'SUBLANG_UPPER_SORBIAN_GERMANY' : 0x01,
386 'SUBLANG_URDU_PAKISTAN' : 0x01,
387 'SUBLANG_URDU_INDIA' : 0x02,
388 'SUBLANG_UZBEK_LATIN' : 0x01,
389 'SUBLANG_UZBEK_CYRILLIC' : 0x02,
390 'SUBLANG_VIETNAMESE_VIETNAM' : 0x01,
391 'SUBLANG_WELSH_UNITED_KINGDOM' : 0x01,
392 'SUBLANG_WOLOF_SENEGAL' : 0x01,
393 'SUBLANG_XHOSA_SOUTH_AFRICA' : 0x01,
394 'SUBLANG_YAKUT_RUSSIA' : 0x01,
395 'SUBLANG_YI_PRC' : 0x01,
396 'SUBLANG_YORUBA_NIGERIA' : 0x01,
397 'SUBLANG_ZULU_SOUTH_AFRICA' : 0x01,
402 This dictionary defines the language lookup table. The key is the language ISO
403 country code, and the value specifies the corresponding code page, primary
404 language and sublanguage.
406 LCID resource: http://msdn.microsoft.com/en-us/library/ms776294.aspx
407 Codepage resource: http://www.science.co.il/language/locale-codes.asp
408 Language ID resource: http://msdn.microsoft.com/en-us/library/ms776294.aspx
410 There is no appropriate sublang for Spanish (Latin America) [es-419], so we
411 use Mexico. SUBLANG_DEFAULT would incorrectly map to Spain. Unlike other
412 Latin American countries, Mexican Spanish is supported by VERSIONINFO:
413 http://msdn.microsoft.com/en-us/library/aa381058.aspx
416 _LANGUAGE_MAP = {
417 # Language neutral LCID, unicode(1200) code page.
418 'neutral' : [ 1200, 'LANG_NEUTRAL', 'SUBLANG_NEUTRAL' ],
419 # LANG_USER_DEFAULT LCID, unicode(1200) code page.
420 'userdefault' : [ 1200, 'LANG_NEUTRAL', 'SUBLANG_DEFAULT' ],
421 'fake-bidi' : [ 1255, 'LANG_HEBREW', 'SUBLANG_NEUTRAL' ],
422 'af' : [ 1252, 'LANG_AFRIKAANS', 'SUBLANG_DEFAULT' ],
423 'am' : [ 1200, 'LANG_AMHARIC', 'SUBLANG_DEFAULT' ],
424 'ar' : [ 1256, 'LANG_ARABIC', 'SUBLANG_DEFAULT' ],
425 'bg' : [ 1251, 'LANG_BULGARIAN', 'SUBLANG_DEFAULT' ],
426 'bn' : [ 1200, 'LANG_BENGALI', 'SUBLANG_DEFAULT' ],
427 'ca' : [ 1252, 'LANG_CATALAN', 'SUBLANG_DEFAULT' ],
428 'cs' : [ 1250, 'LANG_CZECH', 'SUBLANG_DEFAULT' ],
429 'da' : [ 1252, 'LANG_DANISH', 'SUBLANG_DEFAULT' ],
430 'de' : [ 1252, 'LANG_GERMAN', 'SUBLANG_GERMAN' ],
431 'el' : [ 1253, 'LANG_GREEK', 'SUBLANG_DEFAULT' ],
432 'en' : [ 1200, 'LANG_ENGLISH', 'SUBLANG_ENGLISH_US' ],
433 'en-GB' : [ 1038, 'LANG_ENGLISH', 'SUBLANG_ENGLISH_UK' ],
434 'es' : [ 1252, 'LANG_SPANISH', 'SUBLANG_SPANISH_MODERN' ],
435 # LCID for Mexico; Windows does not support L.A. LCID.
436 'es-419' : [ 1252, 'LANG_SPANISH', 'SUBLANG_SPANISH_MEXICAN' ],
437 'et' : [ 1257, 'LANG_ESTONIAN', 'SUBLANG_DEFAULT' ],
438 'eu' : [ 1252, 'LANG_BASQUE', 'SUBLANG_DEFAULT' ],
439 'fa' : [ 1256, 'LANG_PERSIAN', 'SUBLANG_DEFAULT' ],
440 'fi' : [ 1252, 'LANG_FINNISH', 'SUBLANG_DEFAULT' ],
441 'fil' : [ 1252, 'LANG_FILIPINO', 'SUBLANG_DEFAULT' ],
442 'fr' : [ 1252, 'LANG_FRENCH', 'SUBLANG_FRENCH' ],
443 'fr-CA' : [ 1252, 'LANG_FRENCH', 'SUBLANG_FRENCH_CANADIAN' ],
444 'gl' : [ 1252, 'LANG_GALICIAN', 'SUBLANG_DEFAULT' ],
445 'gu' : [ 1200, 'LANG_GUJARATI', 'SUBLANG_DEFAULT' ],
446 'he' : [ 1255, 'LANG_HEBREW', 'SUBLANG_DEFAULT' ],
447 'hi' : [ 1200, 'LANG_HINDI', 'SUBLANG_DEFAULT' ],
448 'hr' : [ 1252, 'LANG_CROATIAN', 'SUBLANG_DEFAULT' ],
449 'hu' : [ 1250, 'LANG_HUNGARIAN', 'SUBLANG_DEFAULT' ],
450 'id' : [ 1252, 'LANG_INDONESIAN', 'SUBLANG_DEFAULT' ],
451 'is' : [ 1252, 'LANG_ICELANDIC', 'SUBLANG_DEFAULT' ],
452 'it' : [ 1252, 'LANG_ITALIAN', 'SUBLANG_DEFAULT' ],
453 'iw' : [ 1255, 'LANG_HEBREW', 'SUBLANG_DEFAULT' ],
454 'ja' : [ 932, 'LANG_JAPANESE', 'SUBLANG_DEFAULT' ],
455 'kn' : [ 1200, 'LANG_KANNADA', 'SUBLANG_DEFAULT' ],
456 'ko' : [ 949, 'LANG_KOREAN', 'SUBLANG_KOREAN' ],
457 'lt' : [ 1257, 'LANG_LITHUANIAN', 'SUBLANG_LITHUANIAN' ],
458 'lv' : [ 1257, 'LANG_LATVIAN', 'SUBLANG_DEFAULT' ],
459 'ml' : [ 1200, 'LANG_MALAYALAM', 'SUBLANG_DEFAULT' ],
460 'mr' : [ 1200, 'LANG_MARATHI', 'SUBLANG_DEFAULT' ],
461 # Malay (Malaysia) [ms-MY]
462 'ms' : [ 1252, 'LANG_MALAY', 'SUBLANG_DEFAULT' ],
463 'nb' : [ 1252, 'LANG_NORWEGIAN', 'SUBLANG_NORWEGIAN_BOKMAL' ],
464 'ne' : [ 1200, 'LANG_NEPALI', 'SUBLANG_NEPALI_NEPAL' ],
465 'nl' : [ 1252, 'LANG_DUTCH', 'SUBLANG_DEFAULT' ],
466 'nn' : [ 1252, 'LANG_NORWEGIAN', 'SUBLANG_NORWEGIAN_NYNORSK' ],
467 'no' : [ 1252, 'LANG_NORWEGIAN', 'SUBLANG_DEFAULT' ],
468 'or' : [ 1200, 'LANG_ORIYA', 'SUBLANG_DEFAULT' ],
469 'pa' : [ 1200, 'LANG_PUNJABI', 'SUBLANG_PUNJABI_INDIA' ],
470 'pl' : [ 1250, 'LANG_POLISH', 'SUBLANG_DEFAULT' ],
471 'pt-BR' : [ 1252, 'LANG_PORTUGUESE', 'SUBLANG_DEFAULT' ],
472 'pt-PT' : [ 1252, 'LANG_PORTUGUESE', 'SUBLANG_PORTUGUESE' ],
473 'ro' : [ 1250, 'LANG_ROMANIAN', 'SUBLANG_DEFAULT' ],
474 'ru' : [ 1251, 'LANG_RUSSIAN', 'SUBLANG_DEFAULT' ],
475 'sa' : [ 1200, 'LANG_SANSKRIT', 'SUBLANG_SANSKRIT_INDIA' ],
476 'si' : [ 1200, 'LANG_SINHALESE', 'SUBLANG_SINHALESE_SRI_LANKA' ],
477 'sk' : [ 1250, 'LANG_SLOVAK', 'SUBLANG_DEFAULT' ],
478 'sl' : [ 1250, 'LANG_SLOVENIAN', 'SUBLANG_DEFAULT' ],
479 'sr' : [ 1250, 'LANG_SERBIAN', 'SUBLANG_SERBIAN_LATIN' ],
480 'sv' : [ 1252, 'LANG_SWEDISH', 'SUBLANG_SWEDISH' ],
481 'sw' : [ 1252, 'LANG_SWAHILI', 'SUBLANG_DEFAULT' ],
482 'ta' : [ 1200, 'LANG_TAMIL', 'SUBLANG_DEFAULT' ],
483 'te' : [ 1200, 'LANG_TELUGU', 'SUBLANG_DEFAULT' ],
484 'th' : [ 874, 'LANG_THAI', 'SUBLANG_DEFAULT' ],
485 'ti' : [ 1200, 'LANG_TIGRIGNA', 'SUBLANG_TIGRIGNA_ERITREA' ],
486 'tr' : [ 1254, 'LANG_TURKISH', 'SUBLANG_DEFAULT' ],
487 'uk' : [ 1251, 'LANG_UKRAINIAN', 'SUBLANG_DEFAULT' ],
488 'ur' : [ 1200, 'LANG_URDU', 'SUBLANG_DEFAULT' ],
489 'vi' : [ 1258, 'LANG_VIETNAMESE', 'SUBLANG_DEFAULT' ],
490 'zh-CN' : [ 936, 'LANG_CHINESE', 'SUBLANG_CHINESE_SIMPLIFIED' ],
491 'zh-HK' : [ 950, 'LANG_CHINESE', 'SUBLANG_CHINESE_HONGKONG' ],
492 'zh-TW' : [ 950, 'LANG_CHINESE', 'SUBLANG_CHINESE_TRADITIONAL' ],
493 'zu' : [ 1200, 'LANG_ZULU', 'SUBLANG_DEFAULT' ],
497 # Right-To-Left languages
498 _RTL_LANGUAGES = (
499 'ar', # Arabic
500 'fa', # Farsi
501 'iw', # Hebrew
502 'ks', # Kashmiri
503 'ku', # Kurdish
504 'ps', # Pashto
505 'ur', # Urdu
506 'yi', # Yiddish
510 def GetCodepage(language):
511 """ Returns the codepage for the given |language|. """
512 lang = _LANGUAGE_MAP[language]
513 return "%04x" % lang[0]
516 def GetCodepageDecimal(language):
517 """ Returns the codepage for the given |language| as a decimal value. """
518 lang = _LANGUAGE_MAP[language]
519 return "%d" % lang[0]
522 def GetLangId(language):
523 """ Returns the language id for the given |language|. """
524 lang = _LANGUAGE_MAP[language]
525 return "%04x" % (_LANGUAGE_PRIMARY[lang[1]] | (_LANGUAGE_SUB[lang[2]] << 10))
528 def GetPrimaryLanguage(language):
529 """ Returns the primary language ID for the given |language|. """
530 lang = _LANGUAGE_MAP[language]
531 return _LANGUAGE_PRIMARY[lang[1]]
534 def GetSublanguage(language):
535 """ Returns the sublanguage ID for the given |language|. """
536 lang = _LANGUAGE_MAP[language]
537 return _LANGUAGE_SUB[lang[2]]
540 def IsRtlLanguage(language):
541 return language in _RTL_LANGUAGES;
544 def NormalizeLanguageCode(language):
545 lang = language.replace('_', '-', 1)
546 if lang == 'en-US':
547 lang = 'en'
548 return lang
551 def GetDataPackageSuffix(language):
552 lang = NormalizeLanguageCode(language)
553 if lang == 'en':
554 lang = 'en-US'
555 return lang
558 def GetJsonSuffix(language):
559 return language.replace('-', '_', 1)
562 def ReadValuesFromFile(values_dict, file_name):
564 Reads NAME=VALUE settings from the specified file.
566 Everything to the left of the first '=' is the keyword,
567 everything to the right is the value. No stripping of
568 white space, so beware.
570 The file must exist, otherwise you get the Python exception from open().
572 for line in open(file_name, 'r').readlines():
573 key, val = line.rstrip('\r\n').split('=', 1)
574 values_dict[key] = val
577 def ReadMessagesFromFile(file_name):
579 Reads messages from a 'chrome_messages_json' file.
581 The file must exist, otherwise you get the Python exception from open().
583 messages_file = io.open(file_name, encoding='utf-8-sig')
584 messages = json.load(messages_file)
585 messages_file.close()
587 values = {}
588 for key in messages.keys():
589 values[key] = unicode(messages[key]['message']);
590 return values
593 def WriteIfChanged(file_name, contents, encoding):
595 Writes the specified contents to the specified file_name
596 iff the contents are different than the current contents.
598 try:
599 target = io.open(file_name, 'r')
600 old_contents = target.read()
601 except EnvironmentError:
602 pass
603 except UnicodeDecodeError:
604 target.close()
605 os.unlink(file_name)
606 else:
607 if contents == old_contents:
608 return
609 target.close()
610 os.unlink(file_name)
611 io.open(file_name, 'w', encoding=encoding).write(contents)
614 class MessageMap:
615 """ Provides a dictionary of localized messages for each language."""
616 def __init__(self, languages, locale_dir):
617 self.language = None
618 self.message_map = {}
620 # Populate the message map
621 if locale_dir:
622 for language in languages:
623 file_name = os.path.join(locale_dir,
624 GetJsonSuffix(language),
625 'messages.json')
626 self.message_map[language] = ReadMessagesFromFile(file_name)
628 def GetText(self, message):
629 """ Returns a localized message for the current language. """
630 return self.message_map[self.language][message]
632 def SelectLanguage(self, language):
633 """ Selects the language to be used when retrieving localized messages. """
634 self.language = language
636 def MakeSelectLanguage(self):
637 """ Returns a function that can be used to select the current language. """
638 return lambda language: self.SelectLanguage(language)
640 def MakeGetText(self):
641 """ Returns a function that can be used to retrieve a localized message. """
642 return lambda message: self.GetText(message)
645 # Use '@' as a delimiter for string templates instead of '$' to avoid unintended
646 # expansion when passing the string from GYP.
647 class GypTemplate(Template):
648 delimiter = '@'
651 def Localize(source, locales, options):
652 # Set the list of languages to use.
653 languages = map(NormalizeLanguageCode, locales)
654 # Remove duplicates.
655 languages = sorted(set(languages))
656 context = { 'languages' : languages }
658 # Load the localized messages.
659 message_map = MessageMap(languages, options.locale_dir)
661 # Add OFFICIAL_BUILD variable the same way build/util/version.py
662 # does.
663 if os.environ.get('CHROME_BUILD_TYPE') == '_official':
664 context['official_build'] = '1'
665 else:
666 context['official_build'] = '0'
668 # Add all variables defined in the command line.
669 if options.define:
670 for define in options.define:
671 context.update(dict([define.split('=', 1)]));
673 # Read NAME=VALUE variables from file.
674 if options.variables:
675 for file_name in options.variables:
676 ReadValuesFromFile(context, file_name)
678 env = None
679 template = None
681 if source:
682 # Load jinja2 library.
683 if options.jinja2:
684 jinja2_path = os.path.normpath(options.jinja2)
685 else:
686 jinja2_path = os.path.normpath(
687 os.path.join(os.path.abspath(__file__),
688 '../../../../third_party/jinja2'))
689 sys.path.append(os.path.split(jinja2_path)[0])
690 from jinja2 import Environment, FileSystemLoader
692 # Create jinja2 environment.
693 (template_path, template_name) = os.path.split(source)
694 env = Environment(loader=FileSystemLoader(template_path),
695 extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
697 # Register custom filters.
698 env.filters['GetCodepage'] = GetCodepage
699 env.filters['GetCodepageDecimal'] = GetCodepageDecimal
700 env.filters['GetLangId'] = GetLangId
701 env.filters['GetPrimaryLanguage'] = GetPrimaryLanguage
702 env.filters['GetSublanguage'] = GetSublanguage
704 # Register the message map with jinja2.i18n extension.
705 env.globals['IsRtlLanguage'] = IsRtlLanguage
706 env.globals['SelectLanguage'] = message_map.MakeSelectLanguage()
707 env.install_gettext_callables(message_map.MakeGetText(),
708 message_map.MakeGetText());
710 template = env.get_template(template_name)
712 # Generate a separate file per each locale if requested.
713 outputs = []
714 if options.locale_output:
715 target = GypTemplate(options.locale_output)
716 for lang in languages:
717 context['languages'] = [ lang ]
718 context['language'] = lang
719 context['pak_suffix'] = GetDataPackageSuffix(lang)
720 context['json_suffix'] = GetJsonSuffix(lang)
721 message_map.SelectLanguage(lang)
723 template_file_name = target.safe_substitute(context)
724 outputs.append(template_file_name)
725 if not options.print_only and not options.locales_listfile:
726 WriteIfChanged(template_file_name, template.render(context),
727 options.encoding)
728 else:
729 outputs.append(options.output)
730 if not options.print_only:
731 WriteIfChanged(options.output, template.render(context), options.encoding)
733 if options.print_only:
734 # Quote each element so filename spaces don't mess up gyp's attempt to parse
735 # it into a list.
736 return " ".join(['"%s"' % x for x in outputs])
738 if options.locales_listfile:
739 # Strip off the quotes from each filename when writing into a listfile.
740 content = u'\n'.join([x.strip('"') for x in outputs])
741 WriteIfChanged(options.locales_listfile, content, options.encoding)
743 return
746 def DoMain(argv):
747 usage = "Usage: localize [options] locales"
748 parser = OptionParser(usage=usage)
749 parser.add_option(
750 '-d', '--define', dest='define', action='append', type='string',
751 help='define a variable (NAME=VALUE).')
752 parser.add_option(
753 '--encoding', dest='encoding', type='string', default='utf-8',
754 help="set the encoding of <output>. 'utf-8' is the default.")
755 parser.add_option(
756 '--jinja2', dest='jinja2', type='string',
757 help="specifies path to the jinja2 library.")
758 parser.add_option(
759 '--locale_dir', dest='locale_dir', type='string',
760 help="set path to localized message files.")
761 parser.add_option(
762 '--locale_output', dest='locale_output', type='string',
763 help='specify the per-locale output file name.')
764 parser.add_option(
765 '-o', '--output', dest='output', type='string',
766 help="specify the output file name.")
767 parser.add_option(
768 '--print_only', dest='print_only', action='store_true',
769 default=False, help='print the output file names only.')
770 parser.add_option(
771 '--locales_listfile', dest='locales_listfile', type='string',
772 help='print the output file names into the specified file.')
773 parser.add_option(
774 '-t', '--template', dest='template', type='string',
775 help="specify the template file name.")
776 parser.add_option(
777 '--variables', dest='variables', action='append', type='string',
778 help='read variables (NAME=VALUE) from file.')
780 options, locales = parser.parse_args(argv)
781 if not locales:
782 parser.error('At least one locale must be specified')
783 if bool(options.output) == bool(options.locale_output):
784 parser.error(
785 'Either --output or --locale_output must be specified but not both')
786 if (not options.template and
787 not options.print_only and not options.locales_listfile):
788 parser.error('The template name is required unless either --print_only '
789 'or --locales_listfile is used')
791 return Localize(options.template, locales, options)
793 if __name__ == '__main__':
794 sys.exit(DoMain(sys.argv[1:]))