#! /usr/bin/env python3 # -*- coding: utf-8 -*- # fg-convert-translation-files --- Convert FlightGear's translation files # Copyright (C) 2017 Florent Rougon # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import argparse import collections import locale import os import sys try: import xml.etree.ElementTree as et except ImportError: import elementtree.ElementTree as et import flightgear.meta.logging import flightgear.meta.i18n as fg_i18n PROGNAME = os.path.basename(sys.argv[0]) # Only messages with severity >= info will be printed to the terminal (it's # possible to also log all messages to a file regardless of their level, see # the Logger class). Of course, there is also the standard logging module... logger = flightgear.meta.logging.Logger( progname=PROGNAME, logLevel=flightgear.meta.logging.LogLevel.info, defaultOutputStream=sys.stderr) debug = logger.debug info = logger.info notice = logger.notice warning = logger.warning error = logger.error critical = logger.critical # We could use Translation.__str__(): not as readable (for now) but more # accurate on metadata def printPlainText(l10nResPoolMgr, translations): """Print output suitable for a quick review (by the programmer).""" firstLang = True for langCode, (transl, nbWhitespacePbs) in translations.items(): # 'transl' is a Translation instance if firstLang: firstLang = False else: print() print("-" * 78 + "\n" + langCode + "\n" + "-" * 78) print("\nNumber of leading and/or trailing whitespace problems: {}" .format(nbWhitespacePbs)) for cat in transl: print("\nCategory: {cat}\n{underline}".format( cat=cat, underline="~"*(len("Category: ") + len(cat)))) t = transl[cat] for tid, translUnit in sorted(t.items()): # - Using '{master!r}' and '{transl!r}' prints stuff such as # \xa0 for nobreak spaces, which can lead to the erroneous # conclusion that there was an encoding problem. # - Only printing the first target text here (no plural forms) print("\n{id}\n '{sourceText}'\n '{targetText}'" .format(id=tid.id(), sourceText=translUnit.sourceText, targetText=translUnit.targetTexts[0])) def writeXliff(l10nResPoolMgr, translations): formatHandler = fg_i18n.XliffFormatHandler() for langCode, translData in translations.items(): translation = translData.transl # Translation instance if params.output_dir is None: # Use default locations for the written xliff files l10nResPoolMgr.writeTranslation(formatHandler, translation) else: basename = "{}-{}.{}".format( formatHandler.defaultFileStem(langCode), langCode, formatHandler.standardExtension) filePath = os.path.join(params.output_dir, basename) formatHandler.writeTranslation(translation, filePath) def processCommandLine(): params = argparse.Namespace() parser = argparse.ArgumentParser( usage="""\ %(prog)s [OPTION ...] LANGUAGE_CODE... Convert FlightGear's old XML translation files into other formats.""", description="""\ Most notably, XLIFF format can be chosen for output. The script performs a few automated checks on the input files too.""", formatter_class=argparse.RawDescriptionHelpFormatter, # I want --help but not -h (it might be useful for something else) add_help=False) parser.add_argument("-t", "--transl-dir", help="""\ directory containing all translation subdirs (such as {default!r}, 'en_GB', 'fr_FR', 'de', 'it'...). This "option" MUST be specified.""".format( default=fg_i18n.DEFAULT_LANG_DIR)) parser.add_argument("lang_code", metavar="LANGUAGE_CODE", nargs="+", help="""\ codes of languages to read translations for (don't specify {default!r} this way, it is special and not a language code)""" .format(default=fg_i18n.DEFAULT_LANG_DIR)) parser.add_argument("-o", "--output-dir", help="""\ output directory for written XLIFF files (default: for each output file, use a suitable location under TRANSL_DIR)""") parser.add_argument("-f", "--output-format", default="xliff", choices=("xliff", "text"), help="""\ format to use for the output files""") parser.add_argument("--help", action="help", help="display this message and exit") params = parser.parse_args(namespace=params) if params.transl_dir is None: error("--transl-dir must be given, aborting") sys.exit(1) return params def main(): global params locale.setlocale(locale.LC_ALL, '') params = processCommandLine() l10nResPoolMgr = fg_i18n.L10NResourcePoolManager(params.transl_dir, logger) # English version of all translatable strings masterTransl, nbWhitespaceProblemsInMaster = \ l10nResPoolMgr.readFgMasterTranslation() translations = collections.OrderedDict() # Sort elements of 'translations' according to language code (= the keys) for langCode in sorted(params.lang_code): translationData = l10nResPoolMgr.readFgTranslation(masterTransl, langCode) translations[translationData.transl.targetLanguage] = translationData if params.output_format == "xliff": writeFunc = writeXliff # write to files elif params.output_format == "text": writeFunc = printPlainText # print to stdout else: assert False, \ "Unexpected output format: '{}'".format(params.output_format) writeFunc(l10nResPoolMgr, translations) nbWhitespaceProblemsInTransl = sum( (translData.nbWhitespacePbs for translData in translations.values() )) info("total number of leading and/or trailing whitespace problems: {}" .format(nbWhitespaceProblemsInMaster + nbWhitespaceProblemsInTransl)) sys.exit(0) if __name__ == "__main__": main()