Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/build_config/i18n.py
193968 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2011-2026 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file i18n.py
15
# @author Michael Behrisch
16
# @date 2022-10-08
17
18
"""
19
Prepare gettext pot and po files for all languages.
20
"""
21
from __future__ import absolute_import
22
from __future__ import print_function
23
import os
24
import io
25
import subprocess
26
import difflib
27
from glob import glob
28
from argparse import ArgumentParser
29
30
31
SUMO_HOME = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
32
SUMO_LIBRARIES = os.environ.get("SUMO_LIBRARIES", os.path.join(os.path.dirname(SUMO_HOME), "SUMOLibraries"))
33
34
35
def get_args(args=None):
36
arg_parser = ArgumentParser()
37
arg_parser.add_argument("-l", "--lang", nargs='*', help="languages to process")
38
arg_parser.add_argument("-m", "--mo-only", action="store_true", default=False,
39
help="only generate mo files, do not update po and pot")
40
arg_parser.add_argument("-f", "--fuzzy", action="store_true", default=False,
41
help="use fuzzy matching to prefill new message ids")
42
arg_parser.add_argument("--sumo-home", default=SUMO_HOME, help="SUMO root directory to use")
43
arg_parser.add_argument("-o", "--out-dir", help="output directory to use")
44
return arg_parser.parse_args(args)
45
46
47
def generate_po(sumo_home, path, languages, pot_file, gui_pot_file, py_pot_file, fuzzy):
48
pots = {pot_file: open(pot_file + ".txt", "w"),
49
gui_pot_file: open(gui_pot_file + ".txt", "w"),
50
py_pot_file: open(py_pot_file + ".txt", "w")}
51
for f in sorted(glob(sumo_home + "/src/*.cpp") +
52
glob(sumo_home + "/src/*/*.cpp") +
53
glob(sumo_home + "/src/*/*/*.cpp") +
54
glob(sumo_home + "/src/*/*/*/*.cpp") +
55
glob(sumo_home + "/src/*.h") +
56
glob(sumo_home + "/src/*/*.h") +
57
glob(sumo_home + "/src/*/*/*.h") +
58
glob(sumo_home + "/src/*/*/*/*.h") +
59
glob(sumo_home + "/tools/game/*.py")):
60
if f[-3:] == ".py":
61
print(f, file=pots[py_pot_file])
62
elif "gui" in f[len(sumo_home):] or "netedit" in f[len(sumo_home):]:
63
print(f, file=pots[gui_pot_file])
64
else:
65
print(f, file=pots[pot_file])
66
for pot, sources in pots.items():
67
sources.close()
68
arguments = [path + "xgettext", "--files-from=" + sources.name, "--from-code=UTF-8",
69
"--keyword=TL", "--keyword=TLC:1c,2", "--keyword=TLF", "--output=" + pot + ".new",
70
"--package-name=sumo", "[email protected]"]
71
if pot == py_pot_file:
72
arguments.append("--language=Python")
73
subprocess.check_call(arguments)
74
os.remove(sources.name)
75
with io.open(pot + ".new", encoding="utf-8") as new, io.open(pot + ".fixed", "w", encoding="utf-8") as fixed:
76
for s in new.readlines():
77
if s.startswith("#") and sumo_home in s:
78
fixed.write(s.replace(sumo_home, "").replace("\\", "/").replace("#: /", "#: "))
79
elif s.strip() == r'"Content-Type: text/plain; charset=CHARSET\n"':
80
fixed.write(s.replace("CHARSET", "UTF-8"))
81
else:
82
fixed.write(s)
83
os.remove(new.name)
84
has_diff = True
85
if os.path.exists(pot):
86
with io.open(pot, encoding="utf-8") as old, io.open(pot + ".fixed", encoding="utf-8") as fixed:
87
a = [s for s in old.readlines() if not s.startswith(("#", '"POT-Creation-Date:'))]
88
b = [s for s in fixed.readlines() if not s.startswith(("#", '"POT-Creation-Date:'))]
89
has_diff = list(difflib.unified_diff(a, b))
90
if has_diff:
91
os.remove(pot)
92
if has_diff:
93
os.rename(fixed.name, pot)
94
else:
95
os.remove(fixed.name)
96
for lang in languages:
97
po_file = "%s/data/po/%s_%s" % (sumo_home, lang, os.path.basename(pot)[:-1])
98
if os.path.exists(po_file):
99
subprocess.check_call([path + "msgmerge", po_file, pot,
100
"--output-file=" + po_file] + ([] if fuzzy else ["--no-fuzzy-matching"]))
101
else:
102
subprocess.check_call([path + "msginit", "--input=" + pot, "--output=" + po_file,
103
"--no-translator", "--locale=" + lang])
104
105
106
def main(args=None):
107
path = ""
108
if os.name == "nt":
109
paths = glob(os.path.join(SUMO_LIBRARIES, "gettext-*", "tools", "gettext", "bin"))
110
if paths:
111
path = paths[0] + os.path.sep
112
options = get_args(args)
113
if options.lang is None:
114
options.lang = [os.path.basename(p)[:-8] for p in glob(options.sumo_home + "/data/po/*_sumo.po")]
115
if options.out_dir is None:
116
options.out_dir = options.sumo_home + "/data"
117
pot_file = options.sumo_home + "/data/po/sumo.pot"
118
gui_pot_file = options.sumo_home + "/data/po/gui.pot"
119
py_pot_file = options.sumo_home + "/data/po/py.pot"
120
if not options.mo_only:
121
generate_po(options.sumo_home, path, options.lang, pot_file, gui_pot_file, py_pot_file, options.fuzzy)
122
for lang in options.lang:
123
po_files = ["%s/data/po/%s_%s" % (options.sumo_home, lang, os.path.basename(pot)[:-1])
124
for pot in (pot_file, gui_pot_file, py_pot_file)]
125
if not os.path.exists("%s/po" % options.out_dir):
126
os.makedirs("%s/po" % options.out_dir)
127
merged_po_file = "%s/po/%s.po" % (options.out_dir, lang)
128
subprocess.check_call([path + "msgcat"] + po_files + ["--output-file=" + merged_po_file])
129
d = "%s/locale/%s/LC_MESSAGES" % (options.out_dir, lang)
130
try:
131
os.makedirs(d)
132
except OSError:
133
pass
134
subprocess.check_call([path + "msgfmt", merged_po_file, "--output-file=%s/sumo.mo" % d])
135
os.remove(merged_po_file)
136
137
138
if __name__ == "__main__":
139
main()
140
141