123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234 |
- #!/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)
|