summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-10 07:20:24 +0000
committermnaganov@chromium.org <mnaganov@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-08-10 07:20:24 +0000
commit8cefa2e4c4fc03a1c87bd0b242cf24488ae3a774 (patch)
tree88d6236235b2a7da31d8a6d17890ca85b984ac51
parentaea074778ad07955e0e61e968361c83d559d3d61 (diff)
downloadchromium_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.py66
-rw-r--r--tools/grit/grit/format/js_map_format_unittest.py98
-rw-r--r--tools/grit/grit/node/empty.py4
-rw-r--r--tools/grit/grit/node/message.py3
-rw-r--r--tools/grit/grit/node/misc.py5
-rw-r--r--tools/grit/grit/test_suite_all.py3
-rw-r--r--tools/grit/grit/tool/build.py2
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'