Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(537)

Unified Diff: remoting/tools/localize.py

Issue 18323017: Localized Chromoting Host on Windows. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: remoting/tools/localize.py
diff --git a/remoting/tools/localize.py b/remoting/tools/localize.py
new file mode 100755
index 0000000000000000000000000000000000000000..5b8c4d0e1139c1e26b4c8210c776b10a47b4d115
--- /dev/null
+++ b/remoting/tools/localize.py
@@ -0,0 +1,375 @@
+#!/usr/bin/env python
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+localize.py -- Generates an output file from the given template replacing
+variables and localizing strings.
+
+The script uses Jinja2 template processing library (src/third_party/jinja2).
+Variables available to the templates:
+ - |languages| - the list of languages passed on the command line. ('-l').
+ - Each KEY=VALUE define ('-d') can be accesses as |KEY|.
+ - |official_build| is set to '1' when CHROME_BUILD_TYPE environment variable
+ is set to "_official".
+
+Filters:
+ - GetCodepage - returns the code page for the given language.
+ - GetCodepageDecimal same as GetCodepage, but returns a decimal value.
+ - GetLangId - returns Win32 LANGID.
+ - GetPrimaryLanguage - returns a named Win32 constant specifing the primary
+ language ID.
+ - GetSublanguage - returns a named Win32 constant specifing the sublanguage
+ ID.
+
+Globals:
+ - SelectLanguage(language) - allows to select the language to the used by
+ {% trans %}{% endtrans %} statements.
+
+"""
+
+import io
+import json
+from optparse import OptionParser
+import os
+import sys
+from string import Template
+
+'''
+See https://code.google.com/p/grit-i18n/source/browse/trunk/grit/format/rc.py
+(revision r79)
+
+This dictionary defines the language lookup table, which is used for replacing
+the GRIT expand variables for language info in Product Version resource. The key
+is the language ISO country code, and the value specifies the corresponding
+locale identifier, code page, primary language and sublanguage.
+
+LCID resource: http://msdn.microsoft.com/en-us/library/ms776294.aspx
+Codepage resource: http://www.science.co.il/language/locale-codes.asp
+Language ID resource: http://msdn.microsoft.com/en-us/library/ms776294.aspx
+
+There is no appropriate sublang for Spanish (Latin America) [es-419], so we
+use Mexico. SUBLANG_DEFAULT would incorrectly map to Spain. Unlike other
+Latin American countries, Mexican Spanish is supported by VERSIONINFO:
+http://msdn.microsoft.com/en-us/library/aa381058.aspx
+
+'''
+
+_LANGUAGE_LANGID = {
+ # Language neutral LCID, unicode(1200) code page.
+ 'neutral' : [ '0000', '04b0', 'LANG_NEUTRAL', 'SUBLANG_NEUTRAL' ],
+ # LANG_USER_DEFAULT LCID, unicode(1200) code page.
+ 'userdefault' : [ '0400', '04b0', 'LANG_NEUTRAL', 'SUBLANG_DEFAULT' ],
+ 'ar' : [ '0401', '04e8', 'LANG_ARABIC', 'SUBLANG_DEFAULT' ],
garykac 2013/07/09 00:34:12 Is there an order to this list? I expected it to
alexeypa (please no reviews) 2013/07/09 01:05:23 Done.
+ 'fi' : [ '040b', '04e4', 'LANG_FINNISH', 'SUBLANG_DEFAULT' ],
+ 'ko' : [ '0412', '03b5', 'LANG_KOREAN', 'SUBLANG_KOREAN' ],
+ 'es' : [ '040a', '04e4', 'LANG_SPANISH', 'SUBLANG_SPANISH_MODERN' ],
+ 'bg' : [ '0402', '04e3', 'LANG_BULGARIAN', 'SUBLANG_DEFAULT' ],
+ # No codepage for filipino, use unicode(1200).
+ 'fil' : [ '0464', '04e4', '100', 'SUBLANG_DEFAULT' ],
+ 'fr' : [ '040c', '04e4', 'LANG_FRENCH', 'SUBLANG_FRENCH' ],
+ 'lv' : [ '0426', '04e9', 'LANG_LATVIAN', 'SUBLANG_DEFAULT' ],
+ 'sv' : [ '041d', '04e4', 'LANG_SWEDISH', 'SUBLANG_SWEDISH' ],
+ 'ca' : [ '0403', '04e4', 'LANG_CATALAN', 'SUBLANG_DEFAULT' ],
+ 'de' : [ '0407', '04e4', 'LANG_GERMAN', 'SUBLANG_GERMAN' ],
+ 'lt' : [ '0427', '04e9', 'LANG_LITHUANIAN', 'SUBLANG_LITHUANIAN' ],
+ 'zh-CN' : [ '0804', '03a8', 'LANG_CHINESE', 'SUBLANG_CHINESE_SIMPLIFIED' ],
+ 'zh-TW' : [ '0404', '03b6', 'LANG_CHINESE', 'SUBLANG_CHINESE_TRADITIONAL' ],
+ 'zh-HK' : [ '0c04', '03b6', 'LANG_CHINESE', 'SUBLANG_CHINESE_HONGKONG' ],
+ 'el' : [ '0408', '04e5', 'LANG_GREEK', 'SUBLANG_DEFAULT' ],
+ 'nb' : [ '0414', '04e4', 'LANG_NORWEGIAN', 'SUBLANG_DEFAULT' ],
+ 'no' : [ '0414', '04e4', 'LANG_NORWEGIAN', 'SUBLANG_DEFAULT' ],
+ 'th' : [ '041e', '036a', 'LANG_THAI', 'SUBLANG_DEFAULT' ],
+ 'he' : [ '040d', '04e7', 'LANG_HEBREW', 'SUBLANG_DEFAULT' ],
+ 'iw' : [ '040d', '04e7', 'LANG_HEBREW', 'SUBLANG_DEFAULT' ],
+ 'pl' : [ '0415', '04e2', 'LANG_POLISH', 'SUBLANG_DEFAULT' ],
+ 'tr' : [ '041f', '04e6', 'LANG_TURKISH', 'SUBLANG_DEFAULT' ],
+ 'hr' : [ '041a', '04e4', 'LANG_CROATIAN', 'SUBLANG_DEFAULT' ],
+ # No codepage for Hindi, use unicode(1200).
+ 'hi' : [ '0439', '04b0', 'LANG_HINDI', 'SUBLANG_DEFAULT' ],
+ 'pt-PT' : [ '0816', '04e4', 'LANG_PORTUGUESE', 'SUBLANG_PORTUGUESE' ],
+ 'pt-BR' : [ '0416', '04e4', 'LANG_PORTUGUESE', 'SUBLANG_DEFAULT' ],
+ 'uk' : [ '0422', '04e3', 'LANG_UKRAINIAN', 'SUBLANG_DEFAULT' ],
+ 'cs' : [ '0405', '04e2', 'LANG_CZECH', 'SUBLANG_DEFAULT' ],
+ 'hu' : [ '040e', '04e2', 'LANG_HUNGARIAN', 'SUBLANG_DEFAULT' ],
+ 'ro' : [ '0418', '04e2', 'LANG_ROMANIAN', 'SUBLANG_DEFAULT' ],
+ # No codepage for Urdu, use unicode(1200).
+ 'ur' : [ '0420', '04b0', 'LANG_URDU', 'SUBLANG_DEFAULT' ],
+ 'da' : [ '0406', '04e4', 'LANG_DANISH', 'SUBLANG_DEFAULT' ],
+ 'is' : [ '040f', '04e4', 'LANG_ICELANDIC', 'SUBLANG_DEFAULT' ],
+ 'ru' : [ '0419', '04e3', 'LANG_RUSSIAN', 'SUBLANG_DEFAULT' ],
+ 'vi' : [ '042a', '04ea', 'LANG_VIETNAMESE', 'SUBLANG_DEFAULT' ],
+ 'nl' : [ '0413', '04e4', 'LANG_DUTCH', 'SUBLANG_DEFAULT' ],
+ 'id' : [ '0421', '04e4', 'LANG_INDONESIAN', 'SUBLANG_DEFAULT' ],
+ 'sr' : [ '081a', '04e2', 'LANG_SERBIAN', 'SUBLANG_SERBIAN_CYRILLIC' ],
+ 'en-GB' : [ '0809', '040e', 'LANG_ENGLISH', 'SUBLANG_ENGLISH_UK' ],
+ 'it' : [ '0410', '04e4', 'LANG_ITALIAN', 'SUBLANG_DEFAULT' ],
+ 'sk' : [ '041b', '04e2', 'LANG_SLOVAK', 'SUBLANG_DEFAULT' ],
+ 'et' : [ '0425', '04e9', 'LANG_ESTONIAN', 'SUBLANG_DEFAULT' ],
+ 'ja' : [ '0411', '03a4', 'LANG_JAPANESE', 'SUBLANG_DEFAULT' ],
+ 'sl' : [ '0424', '04e2', 'LANG_SLOVENIAN', 'SUBLANG_DEFAULT' ],
+ 'en' : [ '0409', '04b0', 'LANG_ENGLISH', 'SUBLANG_ENGLISH_US' ],
+ # LCID for Mexico; Windows does not support L.A. LCID.
+ 'es-419' : [ '080a', '04e4', 'LANG_SPANISH', 'SUBLANG_SPANISH_MEXICAN' ],
+ # No codepage for Bengali, use unicode(1200).
+ 'bn' : [ '0445', '04b0', 'LANG_BENGALI', 'SUBLANG_DEFAULT' ],
+ 'fa' : [ '0429', '04e8', 'LANG_PERSIAN', 'SUBLANG_DEFAULT' ],
+ # No codepage for Gujarati, use unicode(1200).
+ 'gu' : [ '0447', '04b0', 'LANG_GUJARATI', 'SUBLANG_DEFAULT' ],
+ # No codepage for Kannada, use unicode(1200).
+ 'kn' : [ '044b', '04b0', 'LANG_KANNADA', 'SUBLANG_DEFAULT' ],
+ # Malay (Malaysia) [ms-MY]
+ 'ms' : [ '043e', '04e4', 'LANG_MALAY', 'SUBLANG_DEFAULT' ],
+ # No codepage for Malayalam, use unicode(1200).
+ 'ml' : [ '044c', '04b0', 'LANG_MALAYALAM', 'SUBLANG_DEFAULT' ],
+ # No codepage for Marathi, use unicode(1200).
+ 'mr' : [ '044e', '04b0', 'LANG_MARATHI', 'SUBLANG_DEFAULT' ],
+ # No codepage for Oriya , use unicode(1200).
+ 'or' : [ '0448', '04b0', 'LANG_ORIYA', 'SUBLANG_DEFAULT' ],
+ # No codepage for Tamil, use unicode(1200).
+ 'ta' : [ '0449', '04b0', 'LANG_TAMIL', 'SUBLANG_DEFAULT' ],
+ # No codepage for Telugu, use unicode(1200).
+ 'te' : [ '044a', '04b0', 'LANG_TELUGU', 'SUBLANG_DEFAULT' ],
+ # No codepage for Amharic, use unicode(1200). >= Vista.
+ 'am' : [ '045e', '04b0', 'LANG_AMHARIC', 'SUBLANG_DEFAULT' ],
+ 'sw' : [ '0441', '04e4', 'LANG_SWAHILI', 'SUBLANG_DEFAULT' ],
+ 'af' : [ '0436', '04e4', 'LANG_AFRIKAANS', 'SUBLANG_DEFAULT' ],
+ 'eu' : [ '042d', '04e4', 'LANG_BASQUE', 'SUBLANG_DEFAULT' ],
+ 'fr-CA' : [ '0c0c', '04e4', 'LANG_FRENCH', 'SUBLANG_FRENCH_CANADIAN' ],
+ 'gl' : [ '0456', '04e4', 'LANG_GALICIAN', 'SUBLANG_DEFAULT' ],
+ # No codepage for Zulu, use unicode(1200).
+ 'zu' : [ '0435', '04b0', 'LANG_ZULU', 'SUBLANG_DEFAULT' ],
+ 'pa' : [ '0446', '04b0', 'LANG_PUNJABI', 'SUBLANG_PUNJABI_INDIA' ],
+ 'sa' : [ '044f', '04b0', 'LANG_SANSKRIT', 'SUBLANG_SANSKRIT_INDIA' ],
+ 'si' : [ '045b', '04b0', 'LANG_SINHALESE', 'SUBLANG_SINHALESE_SRI_LANKA' ],
+ 'ne' : [ '0461', '04b0', 'LANG_NEPALI', 'SUBLANG_NEPALI_NEPAL' ],
+ 'ti' : [ '0873', '04b0', 'LANG_TIGRIGNA', 'SUBLANG_TIGRIGNA_ERITREA' ],
+ 'fake-bidi' : [ '040d', '04e7', 'LANG_HEBREW', 'SUBLANG_DEFAULT' ],
+}
+
+# Right-To-Left languages
+_RTL_LANGUAGES = (
+ 'ar', # Arabic
+ 'fa', # Farsi
+ 'iw', # Hebrew
+ 'ks', # Kashmiri
+ 'ku', # Kurdish
+ 'ps', # Pashto
+ 'ur', # Urdu
+ 'yi', # Yiddish
+)
+
+
+def GetCodepage(language):
+ """ Returns the codepage for the given |language|. """
+ langid = _LANGUAGE_LANGID[language]
+ return langid[1]
+
+
+def GetCodepageDecimal(language):
+ """ Returns the codepage for the given |language| as a decimal value. """
+ langid = _LANGUAGE_LANGID[language]
+ return str(int(langid[1], 16))
+
+
+def GetLangId(language):
+ """ Returns the language id for the given |language|. """
+ langid = _LANGUAGE_LANGID[language]
+ return langid[0]
+
+
+def GetPrimaryLanguage(language):
+ """ Returns the primary language ID for the given |language|. """
+ langid = _LANGUAGE_LANGID[language]
+ return langid[2]
+
+
+def GetSublanguage(language):
+ """ Returns the sublanguage ID for the given |language|. """
+ langid = _LANGUAGE_LANGID[language]
+ return langid[3]
+
+
+def IsRtlLanguage(language):
+ return language in _RTL_LANGUAGES;
+
+
+def NormalizeLanguageCode(language):
+ return language.replace('_', '-', 1)
+
+
+def ReadValuesFromFile(values_dict, file_name):
+ """
+ Reads KEYWORD=VALUE settings from the specified file.
+
+ Everything to the left of the first '=' is the keyword,
+ everything to the right is the value. No stripping of
+ white space, so beware.
+
+ The file must exist, otherwise you get the Python exception from open().
+ """
+ for line in open(file_name, 'r').readlines():
+ key, val = line.rstrip('\r\n').split('=', 1)
+ values_dict[key] = val
+
+
+def ReadMessagesFromFile(file_name):
+ """
+ Reads messages from a 'chrome_messages_json' file.
+
+ The file must exist, otherwise you get the Python exception from open().
+ """
+ messages_file = io.open(file_name, encoding='utf-8-sig')
+ messages = json.load(messages_file)
+ messages_file.close()
+
+ values = {}
+ for key in messages.keys():
+ values[key] = unicode(messages[key]['message']);
+ return values
+
+
+def WriteIfChanged(file_name, contents, encoding='utf-16'):
+ """
+ Writes the specified contents to the specified file_name
+ iff the contents are different than the current contents.
+ """
+ try:
+ target = io.open(file_name, 'r')
+ old_contents = target.read()
+ except EnvironmentError:
+ pass
+ except UnicodeDecodeError:
+ target.close()
+ os.unlink(file_name)
+ else:
+ if contents == old_contents:
+ return
+ target.close()
+ os.unlink(file_name)
+ io.open(file_name, 'w', encoding=encoding).write(contents)
+
+
+class MessageMap:
+ """ Provides a dictionary of localized messages for each language."""
+ def __init__(self, languages, messages_path):
+ self.language = None
+ self.message_map = {}
+
+ # Populate the message map
+ if messages_path:
+ for language in languages:
+ file_name = os.path.join(messages_path,
+ language.replace('-', '_', 1),
+ 'messages.json')
+ self.message_map[language] = ReadMessagesFromFile(file_name)
+
+ def GetText(self, message):
+ """ Returns a localized message for the current language. """
+ return self.message_map[self.language][message]
+
+ def SelectLanguage(self, language):
+ """ Selects the language to be used when retrieving localized messages. """
+ self.language = language
+
+ def MakeSelectLanguage(self):
+ """ Returns a function that can be used to select the current language. """
+ return lambda language: self.SelectLanguage(language)
+
+ def MakeGetText(self):
+ """ Returns a function that can be used to retrieve a localized message. """
+ return lambda message: self.GetText(message)
+
+
+def Localize(source, target, options):
+ # Load jinja2 library.
+ if options.jinja2:
+ jinja2_path = os.path.normpath(options.jinja2)
+ else:
+ jinja2_path = os.path.normpath(os.path.join(os.path.abspath(__file__),
+ '../../../third_party/jinja2'))
+ sys.path.append(os.path.split(jinja2_path)[0])
+ from jinja2 import Environment, FileSystemLoader
+
+ # Create jinja2 environment.
+ (template_path, template_name) = os.path.split(source)
+ env = Environment(loader=FileSystemLoader(template_path),
+ extensions=['jinja2.ext.do', 'jinja2.ext.i18n'])
+
+ # Register custom filters.
+ env.filters['GetCodepage'] = GetCodepage
+ env.filters['GetCodepageDecimal'] = GetCodepageDecimal
+ env.filters['GetLangId'] = GetLangId
+ env.filters['GetPrimaryLanguage'] = GetPrimaryLanguage
+ env.filters['GetSublanguage'] = GetSublanguage
+
+ # Set the list of languages to use
+ languages = map(NormalizeLanguageCode, options.languages)
+ context = { 'languages' : languages }
+ env.globals['IsRtlLanguage'] = IsRtlLanguage
+
+ # Load the localized messages and register the message map with jinja2.i18n
+ # extension.
+ message_map = MessageMap(languages, options.messages_path)
+ env.globals['SelectLanguage'] = message_map.MakeSelectLanguage()
+ env.install_gettext_callables(message_map.MakeGetText(),
+ message_map.MakeGetText());
+
+ # Add OFFICIAL_BUILD variable the same way chrome/tools/build/version.py
+ # does.
+ if os.environ.get('CHROME_BUILD_TYPE') == '_official':
+ context['official_build'] = '1'
+ else:
+ context['official_build'] = '0'
+
+ # Add all variables defined in the command line.
+ if options.define:
+ for define in options.define:
+ context.update(dict([define.split('=', 1)]));
+
+ # Read KEYWORD=VALUE variables from file.
+ if options.input:
+ for file_name in options.input:
+ ReadValuesFromFile(context, file_name)
+
+ template = env.get_template(template_name)
+ WriteIfChanged(target, template.render(context), options.encoding);
+ return 0;
+
+
+def main():
+ usage = "Usage: localize [options] <input> <output>"
+ parser = OptionParser(usage=usage)
+ parser.add_option(
+ '-d', '--define', dest='define', action='append', type='string',
+ help='define a variable (VAR=VALUE).')
+ parser.add_option(
+ '-i', '--input', dest='input', action='append', type='string',
+ help='read variables from INPUT.')
+ parser.add_option(
+ '-l', '--language', dest='languages', action='append', type='string',
+ help='add LANGUAGE to the list of languages to use.')
+ parser.add_option(
+ '--encoding', dest='encoding', type='string', default='utf-16',
+ help="set the encoding of <output>. 'utf-16' is the default.")
+ parser.add_option(
+ '--jinja2', dest='jinja2', type='string',
+ help="specifies path to the jinja2 library.")
+ parser.add_option(
+ '--messages_path', dest='messages_path', type='string',
+ help="set path to localized messages.")
+
+ options, args = parser.parse_args()
+ if len(args) != 2:
+ parser.error('Two positional arguments (<input> and <output>) are expected')
+ if not options.languages:
+ parser.error('At least one language must be specified')
+ if not options.messages_path:
+ parser.error('--messages_path is required')
+
+ return Localize(args[0], args[1], options)
+
+if __name__ == '__main__':
+ sys.exit(main())
+

Powered by Google App Engine
This is Rietveld 408576698