#!/usr/bin/env python from __future__ import print_function import json import os import io import sys TRANSLATION_CPP = "Translation.cpp" try : to_unicode = unicode except NameError: to_unicode = str # Loading a single JSON file def loadJson(fileName, skipFirstLine): with io.open(fileName, mode="r", encoding="utf-8") as f: if skipFirstLine: f.readline() obj = json.loads(f.read()) return obj # Reading all language translations into a dictionary by langCode def readTranslations(jsonDir): langDict = {} # Read all translation files from the input dir for fileName in os.listdir(jsonDir): fileWithPath = os.path.join(jsonDir, fileName) lf = fileName.lower() # Read only translation_XX.json if lf.startswith("translation_") and lf.endswith(".json"): try: lang = loadJson(fileWithPath, False) except json.decoder.JSONDecodeError as e: print("Failed to decode " + lf) print(str(e)) sys.exit(2) # Extract lang code from file name langCode = fileName[12:-5].upper() # ...and the one specified in the JSON file... try: langCodeFromJson = lang['languageCode'] except KeyError: langCodeFromJson = "(missing)" # ...cause they should be the same! if langCode != langCodeFromJson: raise ValueError("Invalid languageCode " + langCodeFromJson + " in file " + fileName) langDict[langCode] = lang return langDict def writeStart(f): f.write(to_unicode("""// WARNING: THIS FILE WAS AUTO GENERATED BY make_translation.py. PLEASE DO NOT EDIT. #include "Translation.h" #ifndef LANG #define LANG_EN #endif """)) def escapeC(s): return s.replace("\"", "\\\"") def writeLanguage(languageCode, defs, f): print("Generating block for " + languageCode) lang = langDict[languageCode] f.write(to_unicode("\n#ifdef LANG_" + languageCode + "\n")) try: langName = lang['languageLocalName'] except KeyError: langName = languageCode f.write(to_unicode("// ---- " + langName + " ----\n\n")) # ----- Writing SettingsDescriptions obj = lang['menuOptions'] f.write(to_unicode("const char* SettingsDescriptions[] = {\n")) maxLen = 25 for mod in defs['menuOptions']: eid = mod['id'] if 'feature' in mod: f.write(to_unicode("#ifdef " + mod['feature'] + "\n")) f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ ")) f.write(to_unicode("\"" + escapeC(obj[eid]['desc']) + "\",\n")) if 'feature' in mod: f.write(to_unicode("#endif\n")) f.write(to_unicode("};\n\n")) # ----- Writing Message strings obj = lang['messages'] for mod in defs['messages']: eid = mod['id'] f.write(to_unicode("const char* " + eid + " = \"" + escapeC(obj[eid]) + "\";\n")) f.write(to_unicode("\n")) # ----- Writing Characters obj = lang['characters'] for mod in defs['characters']: eid = mod['id'] f.write(to_unicode("const char " + eid + " = '" + obj[eid] + "';\n")) f.write(to_unicode("\n")) # ----- Menu Options # Menu type f.write(to_unicode("const enum ShortNameType SettingsShortNameType = SHORT_NAME_" + ("DOUBLE" if lang['menuDouble'] else "SINGLE") + "_LINE;\n")) # ----- Writing SettingsDescriptions obj = lang['menuOptions'] f.write(to_unicode("const char* SettingsShortNames[][2] = {\n")) maxLen = 25 for mod in defs['menuOptions']: eid = mod['id'] if 'feature' in mod: f.write(to_unicode("#ifdef " + mod['feature'] + "\n")) f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ ")) if lang['menuDouble']: f.write(to_unicode("{ \"" + escapeC(obj[eid]['text2'][0]) + "\", \"" + escapeC(obj[eid]['text2'][1]) + "\" },\n")) else: f.write(to_unicode("{ \"" + escapeC(obj[eid]['text']) + "\" },\n")) if 'feature' in mod: f.write(to_unicode("#endif\n")) f.write(to_unicode("};\n\n")) # ----- Writing Menu Groups obj = lang['menuGroups'] f.write(to_unicode("const char* SettingsMenuEntries[" + str(len(obj)) + "] = {\n")) maxLen = 25 for mod in defs['menuGroups']: eid = mod['id'] f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ ")) f.write(to_unicode("\"" + escapeC(obj[eid]['text2'][0] + "\\n" + obj[eid]['text2'][1]) + "\",\n")) f.write(to_unicode("};\n\n")) # ----- Writing Menu Groups Descriptions obj = lang['menuGroups'] f.write(to_unicode("const char* SettingsMenuEntriesDescriptions[" + str(len(obj)) + "] = {\n")) maxLen = 25 for mod in defs['menuGroups']: eid = mod['id'] f.write(to_unicode(" /* " + eid.ljust(maxLen)[:maxLen] + " */ ")) f.write(to_unicode("\"" + escapeC(obj[eid]['desc']) + "\",\n")) f.write(to_unicode("};\n\n")) # ----- Block end f.write(to_unicode("#endif\n")) def read_opts(): """ Reading input parameters First parameter = json directory Second parameter = target directory """ if len(sys.argv) > 1: jsonDir = sys.argv[1] else: jsonDir = "." if len(sys.argv) > 2: outFile = sys.argv[2] else: outDir = os.path.relpath(jsonDir + "/../workspace/TS100/src/") outFile = os.path.join(outDir, TRANSLATION_CPP) if len(sys.argv) > 3: raise Exception("Too many parameters!") return jsonDir, outFile def orderOutput(langDict): # These languages go first mandatoryOrder = ['EN'] # Then add all others in alphabetical order sortedKeys = sorted(langDict.keys()) # Add the rest as they come for key in sortedKeys: if key not in mandatoryOrder: mandatoryOrder.append(key) return mandatoryOrder def writeTarget(outFile, defs, langCodes): # Start writing the file with io.open(outFile, 'w', encoding='utf-8', newline="\n") as f: writeStart(f) for langCode in langCodes: writeLanguage(langCode, defs, f) if __name__ == "__main__": try: jsonDir, outFile = read_opts() except: print("usage: make_translation.py {json dir} {cpp dir}") sys.exit(1) print("Making " + outFile + " from " + jsonDir) langDict = readTranslations(jsonDir) defs = loadJson(os.path.join(jsonDir, "translations_def.js"), True) langCodes = orderOutput(langDict) writeTarget(outFile, defs, langCodes) print("Done")