diff options
author | mnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-10 07:20:24 +0000 |
---|---|---|
committer | mnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-10 07:20:24 +0000 |
commit | 8cefa2e4c4fc03a1c87bd0b242cf24488ae3a774 (patch) | |
tree | 88d6236235b2a7da31d8a6d17890ca85b984ac51 | |
parent | aea074778ad07955e0e61e968361c83d559d3d61 (diff) | |
download | chromium_src-8cefa2e4c4fc03a1c87bd0b242cf24488ae3a774.zip chromium_src-8cefa2e4c4fc03a1c87bd0b242cf24488ae3a774.tar.gz chromium_src-8cefa2e4c4fc03a1c87bd0b242cf24488ae3a774.tar.bz2 |
GRIT: add support for 'js_map_format' needed for DevTools l10n.
WebKit Inspector is localized using a JS file containing the following map:
localizedStrings[<english text>] = <translated text>;
Review URL: http://codereview.chromium.org/164066
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22900 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | tools/grit/grit/format/js_map_format.py | 66 | ||||
-rw-r--r-- | tools/grit/grit/format/js_map_format_unittest.py | 98 | ||||
-rw-r--r-- | tools/grit/grit/node/empty.py | 4 | ||||
-rw-r--r-- | tools/grit/grit/node/message.py | 3 | ||||
-rw-r--r-- | tools/grit/grit/node/misc.py | 5 | ||||
-rw-r--r-- | tools/grit/grit/test_suite_all.py | 3 | ||||
-rw-r--r-- | tools/grit/grit/tool/build.py | 2 |
7 files changed, 176 insertions, 5 deletions
diff --git a/tools/grit/grit/format/js_map_format.py b/tools/grit/grit/format/js_map_format.py new file mode 100644 index 0000000..94efb6b --- /dev/null +++ b/tools/grit/grit/format/js_map_format.py @@ -0,0 +1,66 @@ +#!/usr/bin/python2.4 +# +# Copyright (c) 2009 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. + +"""Formats as a .js file using a map: <english text> -> <localized text>. +""" + +import os +import re +import types + +from grit import util +from grit.format import interface +from grit.node import io + + +class TopLevel(interface.ItemFormatter): + """Writes out the required preamble for JS files.""" + + def Format(self, item, lang='en', begin_item=True, output_dir='.'): + """Format the JS file header.""" + assert isinstance(lang, types.StringTypes) + if not begin_item: + return '' + else: + return '''// Copyright %d Google Inc. All Rights Reserved. +// This file is automatically generated by GRIT. Do not edit. +''' % (util.GetCurrentYear()) + + +class StringTable(interface.ItemFormatter): + """Writes out the string table.""" + + def Format(self, item, lang='en', begin_item=True, output_dir='.'): + if begin_item: + return '' + else: + return '\n' + + +class Message(interface.ItemFormatter): + """Writes out a single message.""" + + def Format(self, item, lang='en', begin_item=True, output_dir='.'): + """Format a single message.""" + if not begin_item: + return '' + + from grit.node import message + + assert isinstance(lang, types.StringTypes) + assert isinstance(item, message.MessageNode) + + en_message = item.ws_at_start + item.Translate('en') + item.ws_at_end + # Remove position numbers from placeholders. + en_message = re.sub(r'%\d\$([a-z])', r'%\1', en_message) + # Escape double quotes. + en_message = re.sub(r'"', r'\"', en_message) + + loc_message = item.ws_at_start + item.Translate(lang) + item.ws_at_end + # Escape double quotes. + loc_message = re.sub(r'"', r'\"', loc_message) + + return '\nlocalizedStrings["%s"] = "%s";' % (en_message, loc_message) diff --git a/tools/grit/grit/format/js_map_format_unittest.py b/tools/grit/grit/format/js_map_format_unittest.py new file mode 100644 index 0000000..fcd812b --- /dev/null +++ b/tools/grit/grit/format/js_map_format_unittest.py @@ -0,0 +1,98 @@ +#!/usr/bin/python2.4 +# +# Copyright (c) 2009 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. + +"""Unittest for js_map_format.py. +""" + +import os +import re +import sys +if __name__ == '__main__': + sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '../..')) + +import unittest +import StringIO + +from grit import grd_reader +from grit import util +from grit.tool import build + + +class JsMapFormatUnittest(unittest.TestCase): + + def testMessages(self): + grd_text = u""" + <messages> + <message name="IDS_SIMPLE_MESSAGE"> + Simple message. + </message> + <message name="IDS_QUOTES"> + element\u2019s \u201c<ph name="NAME">%s<ex>name</ex></ph>\u201d attribute + </message> + <message name="IDS_PLACEHOLDERS"> + <ph name="ERROR_COUNT">%1$d<ex>1</ex></ph> error, <ph name="WARNING_COUNT">%2$d<ex>1</ex></ph> warning + </message> + <message name="IDS_STARTS_WITH_SPACE"> + ''' (<ph name="COUNT">%d<ex>2</ex></ph>) + </message> + <message name="IDS_DOUBLE_QUOTES"> + A "double quoted" message. + </message> + </messages> + """ + root = grd_reader.Parse(StringIO.StringIO(grd_text.encode('utf-8')), + flexible_root=True) + util.FixRootForUnittest(root) + + buf = StringIO.StringIO() + build.RcBuilder.ProcessNode(root, DummyOutput('js_map_format', 'en'), buf) + output = buf.getvalue() + test = u""" +localizedStrings["Simple message."] = "Simple message."; +localizedStrings["element\u2019s \u201c%s\u201d attribute"] = "element\u2019s \u201c%s\u201d attribute"; +localizedStrings["%d error, %d warning"] = "%1$d error, %2$d warning"; +localizedStrings[" (%d)"] = " (%d)"; +localizedStrings["A \\\"double quoted\\\" message."] = "A \\\"double quoted\\\" message."; +""" + self.failUnless(output.strip() == test.strip()) + + def testTranslations(self): + root = grd_reader.Parse(StringIO.StringIO(""" + <messages> + <message name="ID_HELLO">Hello!</message> + <message name="ID_HELLO_USER">Hello <ph name="USERNAME">%s<ex> + Joi</ex></ph></message> + </messages> + """), flexible_root=True) + util.FixRootForUnittest(root) + + buf = StringIO.StringIO() + build.RcBuilder.ProcessNode(root, DummyOutput('js_map_format', 'fr'), buf) + output = buf.getvalue() + test = u""" +localizedStrings["Hello!"] = "H\xe9P\xe9ll\xf4P\xf4!"; +localizedStrings["Hello %s"] = "H\xe9P\xe9ll\xf4P\xf4 %s"; +""" + self.failUnless(output.strip() == test.strip()) + + +class DummyOutput(object): + + def __init__(self, type, language): + self.type = type + self.language = language + + def GetType(self): + return self.type + + def GetLanguage(self): + return self.language + + def GetOutputFilename(self): + return 'hello.gif' + +if __name__ == '__main__': + unittest.main() diff --git a/tools/grit/grit/node/empty.py b/tools/grit/grit/node/empty.py index 516bdde..cfff7a4 100644 --- a/tools/grit/grit/node/empty.py +++ b/tools/grit/grit/node/empty.py @@ -42,6 +42,9 @@ class MessagesNode(GroupingNode): if t in ['rc_all', 'rc_translateable', 'rc_nontranslateable']: from grit.format import rc # avoid circular dep by importing here return rc.StringTable() + elif t == 'js_map_format': + from grit.format import js_map_format + return js_map_format.StringTable() class StructuresNode(GroupingNode): @@ -67,4 +70,3 @@ class IdentifiersNode(GroupingNode): def _IsValidChild(self, child): from grit.node import misc return isinstance(child, misc.IdentifierNode) - diff --git a/tools/grit/grit/node/message.py b/tools/grit/grit/node/message.py index a6346b1..4622af6c 100644 --- a/tools/grit/grit/node/message.py +++ b/tools/grit/grit/node/message.py @@ -104,6 +104,8 @@ class MessageNode(base.ContentNode): elif (t in ['rc_all', 'rc_translateable', 'rc_nontranslateable'] and self.SatisfiesOutputCondition()): return grit.format.rc.Message() + elif t == 'js_map_format' and self.SatisfiesOutputCondition(): + return grit.format.js_map_format.Message() else: return super(type(self), self).ItemFormatter(t) @@ -264,4 +266,3 @@ class PhNode(base.ContentNode): class ExNode(base.ContentNode): '''An <ex> element.''' pass - diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py index 1495615..61917e4 100644 --- a/tools/grit/grit/node/misc.py +++ b/tools/grit/grit/node/misc.py @@ -224,6 +224,9 @@ class GritNode(base.Node): elif t == 'resource_map_source': from grit.format import resource_map return resource_map.SourceTopLevel() + elif t == 'js_map_format': + from grit.format import js_map_format + return js_map_format.TopLevel() else: return super(type(self), self).ItemFormatter(t) @@ -268,5 +271,3 @@ class IdentifierNode(base.Node): node.EndParsing() return node Construct = staticmethod(Construct) - - diff --git a/tools/grit/grit/test_suite_all.py b/tools/grit/grit/test_suite_all.py index 83add26..cb2d087 100644 --- a/tools/grit/grit/test_suite_all.py +++ b/tools/grit/grit/test_suite_all.py @@ -45,6 +45,7 @@ class TestSuiteAll(unittest.TestSuite): from grit import shortcuts_unittests from grit.gather import muppet_strings_unittest from grit.node.custom import filename_unittest + import grit.format.js_map_format_unittest test_classes = [ base_unittest.NodeUnittest, @@ -73,6 +74,7 @@ class TestSuiteAll(unittest.TestSuite): shortcuts_unittests.ShortcutsUnittest, muppet_strings_unittest.MuppetStringsUnittest, filename_unittest.WindowsFilenameUnittest, + grit.format.js_map_format_unittest.JsMapFormatUnittest, # add test classes here... ] @@ -82,4 +84,3 @@ class TestSuiteAll(unittest.TestSuite): if __name__ == '__main__': unittest.TextTestRunner(verbosity=2).run(TestSuiteAll()) - diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index affe699..e750b9b 100644 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py @@ -172,6 +172,8 @@ are exported to translation interchange files (e.g. XMB files), etc. if output.GetType() in ('rc_header', 'resource_map_header', 'resource_map_source'): encoding = 'cp1252' + elif output.GetType() == 'js_map_format': + encoding = 'utf_8' else: encoding = 'utf_16' |