2 # Copyright (c) 2012 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 # This script can be used to convert messages.json to grd translations.
14 import xml
.dom
.minidom
as dom
17 sys
.path
.append('../../tools/grit')
18 sys
.path
.append('../../tools/grit/grit')
21 def camelCase2ALL_CAPS(s
):
22 for c
in string
.ascii_uppercase
:
23 s
= s
.replace(c
, '_' + c
)
26 def load_messages(filename
):
28 def create_ordered_dict(list):
29 return collections
.OrderedDict(list)
30 messages
= json
.load(file(filename
), object_pairs_hook
=create_ordered_dict
)
35 text
= messages
[id]['message']
37 if messages
[id].has_key('placeholders'):
38 for name
, p
in messages
[id]['placeholders'].items():
40 caps_name
= camelCase2ALL_CAPS(name
)
41 placeholders
.append(tclib
.Placeholder(caps_name
, index
, p
['example']))
42 text
= text
.replace('$' + name
+ '$', caps_name
)
44 msg
= tclib
.Message(text
, placeholders
,
45 messages
[id]['description'])
50 def json_to_grd(input_dir
, output_dir
):
51 # load list of string IDs and placeholder names from the untranslated file
52 # because order of messages and placeholder names are not persisted in
54 message_ids
, messages
= load_messages(
55 os
.path
.join(input_dir
, '_locales/en', 'messages.json'))
57 grd_name
= os
.path
.join(output_dir
,
58 'string_resources.grd')
59 grd_xml
= dom
.parse(grd_name
)
60 grd_translations
= grd_xml
.getElementsByTagName('translations')[0]
61 grd_outputs
= grd_xml
.getElementsByTagName('outputs')[0]
62 grd_messages
= grd_xml
.getElementsByTagName('messages')[0]
64 for id in message_ids
:
66 message
= grd_xml
.createElement('message')
67 grd_messages
.appendChild(grd_xml
.createTextNode(' '))
68 grd_messages
.appendChild(message
)
69 grd_messages
.appendChild(grd_xml
.createTextNode('\n '))
70 message
.setAttribute('name', grit_id
)
71 message
.setAttribute('desc', messages
[id].description
)
72 message
.appendChild(grd_xml
.createTextNode('\n '))
73 for part
in messages
[id].parts
:
74 if isinstance(part
, tclib
.Placeholder
):
75 ph
= grd_xml
.createElement('ph')
76 message
.appendChild(ph
)
77 ph
.setAttribute('name', part
.presentation
)
78 ph
.appendChild(grd_xml
.createTextNode(part
.original
))
79 ex
= grd_xml
.createElement('ex')
81 ex
.appendChild(grd_xml
.createTextNode(part
.example
))
83 message
.appendChild(grd_xml
.createTextNode(part
))
84 message
.appendChild(grd_xml
.createTextNode('\n '))
86 translations_dir
= os
.path
.join(input_dir
, '_locales.official')
87 lang_list
= os
.listdir(translations_dir
)
89 for lang
in lang_list
:
90 # Convert locale name representation to the Grit format.
91 grit_lang
= lang
.replace('_', '-') if lang
!= 'en' else 'en_US'
94 translations_file
= file(
95 os
.path
.join(translations_dir
, lang
, 'messages.json'))
96 translations
= json
.load(translations_file
)
97 translations_file
.close()
99 # Uppercase all string name.
100 translations
= dict(zip(map(lambda x
: x
.upper(), translations
.iterkeys()),
101 translations
.values()))
105 bundle
= doc
.createElement('translationbundle')
106 doc
.appendChild(bundle
)
107 bundle
.setAttribute('lang', grit_lang
)
108 written_translations
= {}
109 for id in message_ids
:
110 bundle
.appendChild(doc
.createTextNode('\n'))
112 if not translations
.has_key(id):
113 # Skip not translated messages.
115 grit_id
= 'IDR_' + id
117 placeholders
= messages
[id].placeholders
118 text
= translations
[id]['message']
119 for p
in placeholders
:
120 text
= text
.replace(p
.original
, p
.presentation
)
122 msg_id
= messages
[id].GetId()
123 if written_translations
.has_key(msg_id
):
124 # We've already written translation for this message.
126 parsed_translation
= tclib
.Translation(text
, msg_id
, placeholders
)
127 written_translations
[msg_id
] = 1
129 translation
= doc
.createElement('translation')
130 bundle
.appendChild(translation
)
131 translation
.setAttribute('id', parsed_translation
.GetId())
132 for part
in parsed_translation
.parts
:
133 if isinstance(part
, tclib
.Placeholder
):
134 ph
= doc
.createElement('ph')
135 translation
.appendChild(ph
)
136 ph
.setAttribute('name', part
.presentation
)
138 translation
.appendChild(doc
.createTextNode(part
))
139 bundle
.appendChild(doc
.createTextNode('\n'))
141 out_name
= os
.path
.join(output_dir
,
142 'string_resources_' + grit_lang
+ '.xtb')
143 out
= codecs
.open(out_name
, mode
='w', encoding
= 'UTF-8')
144 out
.write('<?xml version="1.0" ?>\n'
145 '<!DOCTYPE translationbundle>\n')
149 if grit_lang
== 'en_US':
152 t
= grd_xml
.createElement('file')
153 grd_translations
.appendChild(grd_xml
.createTextNode(' '))
154 grd_translations
.appendChild(t
)
155 grd_translations
.appendChild(grd_xml
.createTextNode('\n '))
156 t
.setAttribute('path', 'string_resources_' + grit_lang
+ '.xtb')
157 t
.setAttribute('lang', grit_lang
)
159 t
= grd_xml
.createElement('output')
160 grd_outputs
.appendChild(grd_xml
.createTextNode(' '))
161 grd_outputs
.appendChild(t
)
162 grd_outputs
.appendChild(grd_xml
.createTextNode('\n '))
163 t
.setAttribute('filename', 'remoting/resources/' + grit_lang
+ '.pak')
164 t
.setAttribute('type', 'data_package')
165 t
.setAttribute('lang', grit_lang
)
167 t
= grd_xml
.createElement('output')
168 grd_outputs
.appendChild(grd_xml
.createTextNode(' '))
169 grd_outputs
.appendChild(t
)
170 grd_outputs
.appendChild(grd_xml
.createTextNode('\n '))
171 t
.setAttribute('filename',
172 'remoting/webapp/_locales/' + lang
+ '/messages.json')
173 t
.setAttribute('type', 'chrome_messages_json')
174 t
.setAttribute('lang', grit_lang
)
176 grd_out
= codecs
.open(grd_name
+ '_new', mode
='w', encoding
= 'UTF-8')
177 grd_xml
.writexml(grd_out
, encoding
= 'UTF-8')
181 usage
= 'Usage: json_to_grd <input_dir> <output_dir>'
182 parser
= optparse
.OptionParser(usage
=usage
)
183 options
, args
= parser
.parse_args()
185 parser
.error('two positional arguments expected')
187 return json_to_grd(args
[0], args
[1])
189 if __name__
== '__main__':