1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
|
#!/usr/bin/python
# Code shared by translation conversion scripts.
#
# Copyright 2013 Google Inc.
# https://developers.google.com/blockly/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import codecs
import json
import os
from datetime import datetime
class InputError(Exception):
"""Exception raised for errors in the input.
Attributes:
location -- where error occurred
msg -- explanation of the error
"""
def __init__(self, location, msg):
Exception.__init__(self, '{0}: {1}'.format(location, msg))
self.location = location
self.msg = msg
def read_json_file(filename):
"""Read a JSON file as UTF-8 into a dictionary, discarding @metadata.
Args:
filename: The filename, which must end ".json".
Returns:
The dictionary.
Raises:
InputError: The filename did not end with ".json" or an error occurred
while opening or reading the file.
"""
if not filename.endswith('.json'):
raise InputError(filename, 'filenames must end with ".json"')
try:
# Read in file.
with codecs.open(filename, 'r', 'utf-8') as infile:
defs = json.load(infile)
if '@metadata' in defs:
del defs['@metadata']
return defs
except ValueError, e:
print('Error reading ' + filename)
raise InputError(filename, str(e))
def _create_qqq_file(output_dir):
"""Creates a qqq.json file with message documentation for translatewiki.net.
The file consists of key-value pairs, where the keys are message ids and
the values are descriptions for the translators of the messages.
What documentation exists for the format can be found at:
http://translatewiki.net/wiki/Translating:Localisation_for_developers#Message_documentation
The file should be closed by _close_qqq_file().
Parameters:
output_dir: The output directory.
Returns:
A pointer to a file to which a left brace and newline have been written.
Raises:
IOError: An error occurred while opening or writing the file.
"""
qqq_file_name = os.path.join(os.curdir, output_dir, 'qqq.json')
qqq_file = codecs.open(qqq_file_name, 'w', 'utf-8')
print 'Created file: ' + qqq_file_name
qqq_file.write('{\n')
return qqq_file
def _close_qqq_file(qqq_file):
"""Closes a qqq.json file created and opened by _create_qqq_file().
This writes the final newlines and right brace.
Args:
qqq_file: A file created by _create_qqq_file().
Raises:
IOError: An error occurred while writing to or closing the file.
"""
qqq_file.write('\n}\n')
qqq_file.close()
def _create_lang_file(author, lang, output_dir):
"""Creates a <lang>.json file for translatewiki.net.
The file consists of metadata, followed by key-value pairs, where the keys
are message ids and the values are the messages in the language specified
by the corresponding command-line argument. The file should be closed by
_close_lang_file().
Args:
author: Name and email address of contact for translators.
lang: ISO 639-1 source language code.
output_dir: Relative directory for output files.
Returns:
A pointer to a file to which the metadata has been written.
Raises:
IOError: An error occurred while opening or writing the file.
"""
lang_file_name = os.path.join(os.curdir, output_dir, lang + '.json')
lang_file = codecs.open(lang_file_name, 'w', 'utf-8')
print 'Created file: ' + lang_file_name
# string.format doesn't like printing braces, so break up our writes.
lang_file.write('{\n\t"@metadata": {')
lang_file.write("""
\t\t"author": "{0}",
\t\t"lastupdated": "{1}",
\t\t"locale": "{2}",
\t\t"messagedocumentation" : "qqq"
""".format(author, str(datetime.now()), lang))
lang_file.write('\t},\n')
return lang_file
def _close_lang_file(lang_file):
"""Closes a <lang>.json file created with _create_lang_file().
This also writes the terminating left brace and newline.
Args:
lang_file: A file opened with _create_lang_file().
Raises:
IOError: An error occurred while writing to or closing the file.
"""
lang_file.write('\n}\n')
lang_file.close()
def _create_key_file(output_dir):
"""Creates a keys.json file mapping Closure keys to Blockly keys.
Args:
output_dir: Relative directory for output files.
Raises:
IOError: An error occurred while creating the file.
"""
key_file_name = os.path.join(os.curdir, output_dir, 'keys.json')
key_file = open(key_file_name, 'w')
key_file.write('{\n')
print 'Created file: ' + key_file_name
return key_file
def _close_key_file(key_file):
"""Closes a key file created and opened with _create_key_file().
Args:
key_file: A file created by _create_key_file().
Raises:
IOError: An error occurred while writing to or closing the file.
"""
key_file.write('\n}\n')
key_file.close()
def write_files(author, lang, output_dir, units, write_key_file):
"""Writes the output files for the given units.
There are three possible output files:
* lang_file: JSON file mapping meanings (e.g., Maze.turnLeft) to the
English text. The base name of the language file is specified by the
"lang" command-line argument.
* key_file: JSON file mapping meanings to Soy-generated keys (long hash
codes). This is only output if the parameter write_key_file is True.
* qqq_file: JSON file mapping meanings to descriptions.
Args:
author: Name and email address of contact for translators.
lang: ISO 639-1 source language code.
output_dir: Relative directory for output files.
units: A list of dictionaries with entries for 'meaning', 'source',
'description', and 'keys' (the last only if write_key_file is true),
in the order desired in the output files.
write_key_file: Whether to output a keys.json file.
Raises:
IOError: An error occurs opening, writing to, or closing a file.
KeyError: An expected key is missing from units.
"""
lang_file = _create_lang_file(author, lang, output_dir)
qqq_file = _create_qqq_file(output_dir)
if write_key_file:
key_file = _create_key_file(output_dir)
first_entry = True
for unit in units:
if not first_entry:
lang_file.write(',\n')
if write_key_file:
key_file.write(',\n')
qqq_file.write(',\n')
lang_file.write(u'\t"{0}": "{1}"'.format(
unit['meaning'],
unit['source'].replace('"', "'")))
if write_key_file:
key_file.write('"{0}": "{1}"'.format(unit['meaning'], unit['key']))
qqq_file.write(u'\t"{0}": "{1}"'.format(
unit['meaning'],
unit['description'].replace('"', "'").replace(
'{lb}', '{').replace('{rb}', '}')))
first_entry = False
_close_lang_file(lang_file)
if write_key_file:
_close_key_file(key_file)
_close_qqq_file(qqq_file)
|