summaryrefslogtreecommitdiff
path: root/blockly/i18n/common.py
diff options
context:
space:
mode:
Diffstat (limited to 'blockly/i18n/common.py')
-rw-r--r--blockly/i18n/common.py234
1 files changed, 234 insertions, 0 deletions
diff --git a/blockly/i18n/common.py b/blockly/i18n/common.py
new file mode 100644
index 0000000..90e584e
--- /dev/null
+++ b/blockly/i18n/common.py
@@ -0,0 +1,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)