9 ion_special_characters = {
10 u'Σ':
"Ion::Charset::CapitalSigma",
11 u'λ':
"Ion::Charset::SmallLambda",
12 u'μ':
"Ion::Charset::SmallMu",
13 u'σ':
"Ion::Charset::SmallSigma",
14 u'≤':
"Ion::Charset::LessEqual",
15 u'≈':
"Ion::Charset::AlmostEqual" 19 if i18n_letter ==
'\'':
21 if ord(i18n_letter) < 128:
22 return "'" + i18n_letter +
"'" 23 if i18n_letter
in ion_special_characters:
24 return ion_special_characters[i18n_letter]
25 normalized = unicodedata.normalize(
"NFD", i18n_letter).encode(
'ascii',
'ignore')
27 return "'" + normalized.decode() +
"'" 32 while i < len(i18n_string):
33 if i18n_string[i] ==
'\\':
35 newChar =
"'\\"+i18n_string[i]+
"'" 36 ion_characters.append(newChar)
38 ion_characters.append(
ion_char(i18n_string[i]))
40 ion_characters.append(
"0")
41 return "{" +
", ".join(ion_characters) +
"}" 44 match = re.match(
r"^(\w+)\s*=\s*\"(.*)\"$", line)
46 sys.stderr.write(
"Error: Invalid line \"" + line +
"\"\n")
51 return re.match(
r".*\.([a-z]+)\.i18n", filename).group(1)
56 universal_messages = set()
59 if locale
not in data:
61 with io.open(path,
"r", encoding='utf-8') as file: 64 if locale ==
"universal":
66 sys.stderr.write(
"Error: Redefinition of message \"" + name +
"\" as universal\n")
68 if name
in universal_messages:
69 sys.stderr.write(
"Error: Redefinition of universal message \"" + name +
"\"\n")
71 universal_messages.add(name)
74 data[locale][name] = definition
75 return {
"messages": sorted(messages),
"universal_messages": sorted(universal_messages),
"data": data}
79 f.write(
"#ifndef APPS_I18N_H\n")
80 f.write(
"#define APPS_I18N_H\n")
82 f.write(
"// This file is auto-generated by i18n.py\n")
84 f.write(
"#include <escher.h>\n")
86 f.write(
"namespace I18n {\n")
88 f.write(
"constexpr static int NumberOfLanguages = %d;\n" % len(locales))
90 f.write(
"enum class Message : uint16_t {\n")
91 for message
in data[
"messages"]:
92 f.write(
" " + message +
",\n")
94 f.write(
" UniversalMessageMarker,\n")
96 for message
in data[
"universal_messages"]:
97 f.write(
" " + message +
",\n")
100 f.write(
"enum class Language : uint16_t {\n")
101 f.write(
" Default = 0,\n")
102 for locale
in locales:
103 f.write(
" " + locale.upper() +
",\n")
106 f.write(
"constexpr const Message LanguageNames[NumberOfLanguages] = {\n");
107 for locale
in locales:
108 f.write(
" Message::Language" + locale.upper() +
",\n")
118 f.write(
"#include \"i18n.h\"\n")
119 f.write(
"#include \"global_preferences.h\"\n")
120 f.write(
"#include <assert.h>\n");
122 f.write(
"namespace I18n {\n")
124 for message
in data[
"messages"]:
125 for locale
in locales:
126 if not locale
in data[
"data"]:
127 sys.stderr.write(
"Error: Undefined locale \"" + locale +
"\"\n")
129 if not message
in data[
"data"][locale]:
130 sys.stderr.write(
"Error: Undefined key \"" + message +
"\" for locale \"" + locale +
"\"\n")
132 f.write(
"constexpr static char " + locale + message +
"[] = " + data[
"data"][locale][message] +
";\n")
134 f.write(
"constexpr static const char * messages[%d][%d] = {\n" % (len(data[
"messages"]), len(locales)))
135 for message
in data[
"messages"]:
137 for locale
in locales:
138 f.write(locale + message +
", ")
142 for message
in data[
"universal_messages"]:
143 f.write(
"constexpr static char universal" + message +
"[] = " + data[
"data"][
"universal"][message] +
";\n")
145 f.write(
"constexpr static const char * universalMessages[%d] = {\n" % len(data[
"universal_messages"]))
146 for message
in data[
"universal_messages"]:
147 f.write(
" universal" + message +
",\n")
150 f.write(
"const char * translate(Message m, Language l) {\n")
151 f.write(
" assert(m != Message::UniversalMessageMarker);\n")
152 f.write(
" int universalMessageOffset = (int)Message::UniversalMessageMarker+1;\n")
153 f.write(
" if ((int)m >= universalMessageOffset) {\n")
154 f.write(
" assert(universalMessages[(int)m - universalMessageOffset] != nullptr);\n")
155 f.write(
" return universalMessages[(int)m - universalMessageOffset];\n")
157 f.write(
" int languageIndex = (int)l;\n")
158 f.write(
" if (l == Language::Default) {\n")
159 f.write(
" languageIndex = (int) GlobalPreferences::sharedGlobalPreferences()->language();\n")
161 f.write(
" assert(languageIndex > 0);\n")
162 f.write(
" assert(((int)m*NumberOfLanguages+languageIndex-1)*sizeof(char *) < sizeof(messages));\n")
163 f.write(
" return messages[(int)m][languageIndex-1];\n")
169 parser = argparse.ArgumentParser(description=
"Process some i18n files.")
170 parser.add_argument(
'--header', help=
'the .h file to generate')
171 parser.add_argument(
'--implementation', help=
'the .cpp file to generate')
172 parser.add_argument(
'--locales', nargs=
'+', help=
'locale to actually generate')
173 parser.add_argument(
'--files', nargs=
'+', help=
'an i18n file')
175 args = parser.parse_args()
179 if args.implementation:
def print_header(data, path, locales)
def source_definition(i18n_string)
def print_implementation(data, path, locales)
def locale_from_filename(filename)
def ion_char(i18n_letter)