Merge 'remotes/trunk'
[0ad.git] / source / tools / i18n / generateDebugTranslation.py
blobc30e6c47a11f5c06294468862abe3a82546adad2
1 #!/usr/bin/env python3
3 # Copyright (C) 2022 Wildfire Games.
4 # This file is part of 0 A.D.
6 # 0 A.D. is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 2 of the License, or
9 # (at your option) any later version.
11 # 0 A.D. is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
19 import argparse
20 import os
21 import sys
22 import multiprocessing
24 from i18n_helper import l10nFolderName, projectRootDirectory
25 from i18n_helper.catalog import Catalog
26 from i18n_helper.globber import getCatalogs
29 DEBUG_PREFIX = 'X_X '
32 def generate_long_strings(root_path, input_file_name, output_file_name, languages=None):
33 """
34 Generate the 'long strings' debug catalog.
35 This catalog contains the longest singular and plural string,
36 found amongst all translated languages or a filtered subset.
37 It can be used to check if GUI elements are large enough.
38 The catalog is long.*.po
39 """
40 print("Generating", output_file_name)
41 input_file_path = os.path.join(root_path, input_file_name)
42 output_file_path = os.path.join(root_path, output_file_name)
44 template_catalog = Catalog.readFrom(input_file_path)
45 # Pretend we write English to get plurals.
46 long_string_catalog = Catalog(locale="en")
48 # Fill catalog with English strings.
49 for message in template_catalog:
50 long_string_catalog.add(
51 id=message.id, string=message.id, context=message.context)
53 # Load existing translation catalogs.
54 existing_translation_catalogs = getCatalogs(input_file_path, languages)
56 # If any existing translation has more characters than the average expansion, use that instead.
57 for translation_catalog in existing_translation_catalogs:
58 for long_string_catalog_message in long_string_catalog:
59 translation_message = translation_catalog.get(
60 long_string_catalog_message.id, long_string_catalog_message.context)
61 if not translation_message or not translation_message.string:
62 continue
64 if not long_string_catalog_message.pluralizable or not translation_message.pluralizable:
65 if len(translation_message.string) > len(long_string_catalog_message.string):
66 long_string_catalog_message.string = translation_message.string
67 continue
69 longest_singular_string = translation_message.string[0]
70 longest_plural_string = translation_message.string[1 if len(
71 translation_message.string) > 1 else 0]
73 candidate_singular_string = long_string_catalog_message.string[0]
74 # There might be between 0 and infinite plural forms.
75 candidate_plural_string = ""
76 for candidate_string in long_string_catalog_message.string[1:]:
77 if len(candidate_string) > len(candidate_plural_string):
78 candidate_plural_string = candidate_string
80 changed = False
81 if len(candidate_singular_string) > len(longest_singular_string):
82 longest_singular_string = candidate_singular_string
83 changed = True
84 if len(candidate_plural_string) > len(longest_plural_string):
85 longest_plural_string = candidate_plural_string
86 changed = True
88 if changed:
89 long_string_catalog_message.string = [
90 longest_singular_string, longest_plural_string]
91 translation_message = long_string_catalog_message
92 long_string_catalog.writeTo(output_file_path)
95 def generate_debug(root_path, input_file_name, output_file_name):
96 """
97 Generate a debug catalog to identify untranslated strings.
98 This prefixes all strings with DEBUG_PREFIX, to easily identify
99 untranslated strings while still making the game navigable.
100 The catalog is debug.*.po
102 print("Generating", output_file_name)
103 input_file_path = os.path.join(root_path, input_file_name)
104 output_file_path = os.path.join(root_path, output_file_name)
106 template_catalog = Catalog.readFrom(input_file_path)
107 # Pretend we write English to get plurals.
108 out_catalog = Catalog(locale="en")
110 for message in template_catalog:
111 if message.pluralizable:
112 out_catalog.add(
113 id=message.id,
114 string=(DEBUG_PREFIX + message.id[0],),
115 context=message.context)
116 else:
117 out_catalog.add(
118 id=message.id,
119 string=DEBUG_PREFIX + message.id,
120 context=message.context)
122 out_catalog.writeTo(output_file_path)
125 def main():
126 parser = argparse.ArgumentParser()
127 parser.add_argument("--debug",
128 help="Generate debug localisation to identify non-translated strings.",
129 action="store_true")
130 parser.add_argument("--long",
131 help="Generate 'long strings' localisation to identify GUI elements too small.",
132 action="store_true")
133 parser.add_argument("--languages",
134 nargs="+",
135 help="For long strings, restrict to these languages")
136 args = parser.parse_args()
138 if not args.debug and not args.long:
139 parser.print_help()
140 sys.exit(0)
142 found_pot_files = 0
143 for root, _, filenames in os.walk(projectRootDirectory):
144 for filename in filenames:
145 if len(filename) > 4 and filename[-4:] == ".pot" and os.path.basename(root) == l10nFolderName:
146 found_pot_files += 1
147 if args.debug:
148 multiprocessing.Process(
149 target=generate_debug,
150 args=(root, filename, "debug." + filename[:-1])
151 ).start()
152 if args.long:
153 multiprocessing.Process(
154 target=generate_long_strings,
155 args=(root, filename, "long." +
156 filename[:-1], args.languages)
157 ).start()
159 if found_pot_files == 0:
160 print("This script did not work because no ‘.pot’ files were found. "
161 "Please, run ‘updateTemplates.py’ to generate the ‘.pot’ files, and run ‘pullTranslations.py’ to pull the latest translations from Transifex. "
162 "Then you can run this script to generate ‘.po’ files with obvious debug strings.")
165 if __name__ == "__main__":
166 main()