Skip to content

Commit 0905f81

Browse files
authored
Merge pull request godotengine#56162 from akien-mga/i18n-make_rst-more-translatable
i18n: Make more `make_rst.py` strings translatable
2 parents 897afb6 + fd1d0c2 commit 0905f81

File tree

2 files changed

+65
-26
lines changed

2 files changed

+65
-26
lines changed

doc/tools/make_rst.py

+49-23
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{"
2020
MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>"
2121

22-
# Used to translate the section headings when required with --lang argument.
23-
# The HEADINGS list should be synced with what we actually write with `make_heading`,
24-
# and also hardcoded in `doc/translations/extract.py`.
25-
HEADINGS = [
22+
# Used to translate section headings and other hardcoded strings when required with
23+
# the --lang argument. The BASE_STRINGS list should be synced with what we actually
24+
# write in this script (check `translate()` uses), and also hardcoded in
25+
# `doc/translations/extract.py` to include them in the source POT file.
26+
BASE_STRINGS = [
2627
"Description",
2728
"Tutorials",
2829
"Properties",
@@ -38,8 +39,21 @@
3839
"Method Descriptions",
3940
"Operator Descriptions",
4041
"Theme Property Descriptions",
42+
"Inherits:",
43+
"Inherited By:",
44+
"(overrides %s)",
45+
"Default",
46+
"Setter",
47+
"value",
48+
"Getter",
49+
"This method should typically be overridden by the user to have any effect.",
50+
"This method has no side effects. It doesn't modify any of the instance's member variables.",
51+
"This method accepts any number of arguments after the ones described here.",
52+
"This method is used to construct a type.",
53+
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
54+
"This method describes a valid operator to use with this type as left-hand operand.",
4155
]
42-
headings_l10n = {}
56+
strings_l10n = {}
4357

4458

4559
def print_error(error, state): # type: (str, State) -> None
@@ -408,13 +422,13 @@ def main(): # type: () -> None
408422
try:
409423
import polib
410424
except ImportError:
411-
print("Section heading localization requires `polib`.")
425+
print("Base template strings localization requires `polib`.")
412426
exit(1)
413427

414428
pofile = polib.pofile(lang_file)
415429
for entry in pofile.translated_entries():
416-
if entry.msgid in HEADINGS:
417-
headings_l10n[entry.msgid] = entry.msgstr
430+
if entry.msgid in BASE_STRINGS:
431+
strings_l10n[entry.msgid] = entry.msgstr
418432
else:
419433
print("No PO file at '{}' for language '{}'.".format(lang_file, args.lang))
420434

@@ -494,6 +508,14 @@ def main(): # type: () -> None
494508
exit(1)
495509

496510

511+
def translate(string): # type: (str) -> str
512+
"""Translate a string based on translations sourced from `doc/translations/*.po`
513+
for a language if defined via the --lang command line argument.
514+
Returns the original string if no translation exists.
515+
"""
516+
return strings_l10n.get(string, string)
517+
518+
497519
def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None
498520
class_name = class_def.name
499521

@@ -515,7 +537,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
515537
# Ascendants
516538
if class_def.inherits:
517539
inh = class_def.inherits.strip()
518-
f.write("**Inherits:** ")
540+
f.write("**" + translate("Inherits:") + "** ")
519541
first = True
520542
while inh in state.classes:
521543
if not first:
@@ -538,7 +560,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
538560
inherited.append(c.name)
539561

540562
if len(inherited):
541-
f.write("**Inherited By:** ")
563+
f.write("**" + translate("Inherited By:") + "** ")
542564
for i, child in enumerate(inherited):
543565
if i > 0:
544566
f.write(", ")
@@ -569,7 +591,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
569591
default = property_def.default_value
570592
if default is not None and property_def.overrides:
571593
ref = ":ref:`{1}<class_{1}_property_{0}>`".format(property_def.name, property_def.overrides)
572-
ml.append((type_rst, property_def.name, default + " (overrides " + ref + ")"))
594+
# Not using translate() for now as it breaks table formatting.
595+
ml.append((type_rst, property_def.name, default + " " + "(overrides %s)" % ref))
573596
else:
574597
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
575598
ml.append((type_rst, ref, default))
@@ -687,12 +710,13 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
687710
f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name))
688711

689712
info = []
713+
# Not using translate() for now as it breaks table formatting.
690714
if property_def.default_value is not None:
691-
info.append(("*Default*", property_def.default_value))
715+
info.append(("*" + "Default" + "*", property_def.default_value))
692716
if property_def.setter is not None and not property_def.setter.startswith("_"):
693-
info.append(("*Setter*", property_def.setter + "(value)"))
717+
info.append(("*" + "Setter" + "*", property_def.setter + "(" + "value" + ")"))
694718
if property_def.getter is not None and not property_def.getter.startswith("_"):
695-
info.append(("*Getter*", property_def.getter + "()"))
719+
info.append(("*" + "Getter" + "*", property_def.getter + "()"))
696720

697721
if len(info) > 0:
698722
format_table(f, info)
@@ -781,7 +805,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
781805

782806
info = []
783807
if theme_item_def.default_value is not None:
784-
info.append(("*Default*", theme_item_def.default_value))
808+
# Not using translate() for now as it breaks table formatting.
809+
info.append(("*" + "Default" + "*", theme_item_def.default_value))
785810

786811
if len(info) > 0:
787812
format_table(f, info)
@@ -1306,8 +1331,9 @@ def make_method_signature(
13061331

13071332
def make_heading(title, underline, l10n=True): # type: (str, str, bool) -> str
13081333
if l10n:
1309-
if title in headings_l10n:
1310-
title = headings_l10n.get(title)
1334+
new_title = translate(title)
1335+
if new_title != title:
1336+
title = new_title
13111337
underline *= 2 # Double length to handle wide chars.
13121338
return title + "\n" + (underline * len(title)) + "\n\n"
13131339

@@ -1317,12 +1343,12 @@ def make_footer(): # type: () -> str
13171343
# This way, we avoid bloating the generated rST with duplicate abbreviations.
13181344
# fmt: off
13191345
return (
1320-
".. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`\n"
1321-
".. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`\n"
1322-
".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`\n"
1323-
".. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`\n"
1324-
".. |static| replace:: :abbr:`static (This method doesn't need an instance to be called, so it can be called directly using the class name.)`\n"
1325-
".. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`\n"
1346+
".. |virtual| replace:: :abbr:`virtual (" + translate("This method should typically be overridden by the user to have any effect.") + ")`\n"
1347+
".. |const| replace:: :abbr:`const (" + translate("This method has no side effects. It doesn't modify any of the instance's member variables.") + ")`\n"
1348+
".. |vararg| replace:: :abbr:`vararg (" + translate("This method accepts any number of arguments after the ones described here.") + ")`\n"
1349+
".. |constructor| replace:: :abbr:`constructor (" + translate("This method is used to construct a type.") + ")`\n"
1350+
".. |static| replace:: :abbr:`static (" + translate("This method doesn't need an instance to be called, so it can be called directly using the class name.") + ")`\n"
1351+
".. |operator| replace:: :abbr:`operator (" + translate("This method describes a valid operator to use with this type as left-hand operand.") + ")`\n"
13261352
)
13271353
# fmt: on
13281354

doc/translations/extract.py

+16-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"""
2727
# Some strings used by make_rst.py are normally part of the editor translations,
2828
# so we need to include them manually here for the online docs.
29-
HEADINGS = [
29+
BASE_STRINGS = [
3030
"Description",
3131
"Tutorials",
3232
"Properties",
@@ -42,6 +42,19 @@
4242
"Method Descriptions",
4343
"Operator Descriptions",
4444
"Theme Property Descriptions",
45+
"Inherits:",
46+
"Inherited By:",
47+
"(overrides %s)",
48+
"Default",
49+
"Setter",
50+
"value",
51+
"Getter",
52+
"This method should typically be overridden by the user to have any effect.",
53+
"This method has no side effects. It doesn't modify any of the instance's member variables.",
54+
"This method accepts any number of arguments after the ones described here.",
55+
"This method is used to construct a type.",
56+
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
57+
"This method describes a valid operator to use with this type as left-hand operand.",
4558
]
4659

4760
## <xml-line-number-hack from="https://stackoverflow.com/a/36430270/10846399">
@@ -229,12 +242,12 @@ def _make_translation_catalog(classes):
229242
def _generate_translation_catalog_file(unique_msgs, output, location_line=False):
230243
with open(output, "w", encoding="utf8") as f:
231244
f.write(HEADER)
232-
for msg in HEADINGS:
245+
for msg in BASE_STRINGS:
233246
f.write("#: doc/tools/make_rst.py\n")
234247
f.write('msgid "{}"\n'.format(msg))
235248
f.write('msgstr ""\n\n')
236249
for msg in unique_msgs:
237-
if len(msg) == 0 or msg in HEADINGS:
250+
if len(msg) == 0 or msg in BASE_STRINGS:
238251
continue
239252

240253
f.write("#:")

0 commit comments

Comments
 (0)