i18n: Make more `make_rst.py` strings translatable

For now we leave out the strings which could break rst table formatting.
This commit is contained in:
Rémi Verschelde 2021-12-22 16:35:08 +01:00
parent 0f6a6ca5be
commit fd1d0c28c2
No known key found for this signature in database
GPG Key ID: C3336907360768E1
2 changed files with 65 additions and 26 deletions

View File

@ -19,10 +19,11 @@ GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{" MARKUP_ALLOWED_PRECEDENT = " -:/'\"<([{"
MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>" MARKUP_ALLOWED_SUBSEQUENT = " -.,:;!?\\/'\")]}>"
# Used to translate the section headings when required with --lang argument. # Used to translate section headings and other hardcoded strings when required with
# The HEADINGS list should be synced with what we actually write with `make_heading`, # the --lang argument. The BASE_STRINGS list should be synced with what we actually
# and also hardcoded in `doc/translations/extract.py`. # write in this script (check `translate()` uses), and also hardcoded in
HEADINGS = [ # `doc/translations/extract.py` to include them in the source POT file.
BASE_STRINGS = [
"Description", "Description",
"Tutorials", "Tutorials",
"Properties", "Properties",
@ -38,8 +39,21 @@ HEADINGS = [
"Method Descriptions", "Method Descriptions",
"Operator Descriptions", "Operator Descriptions",
"Theme Property Descriptions", "Theme Property Descriptions",
"Inherits:",
"Inherited By:",
"(overrides %s)",
"Default",
"Setter",
"value",
"Getter",
"This method should typically be overridden by the user to have any effect.",
"This method has no side effects. It doesn't modify any of the instance's member variables.",
"This method accepts any number of arguments after the ones described here.",
"This method is used to construct a type.",
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
"This method describes a valid operator to use with this type as left-hand operand.",
] ]
headings_l10n = {} strings_l10n = {}
def print_error(error, state): # type: (str, State) -> None def print_error(error, state): # type: (str, State) -> None
@ -408,13 +422,13 @@ def main(): # type: () -> None
try: try:
import polib import polib
except ImportError: except ImportError:
print("Section heading localization requires `polib`.") print("Base template strings localization requires `polib`.")
exit(1) exit(1)
pofile = polib.pofile(lang_file) pofile = polib.pofile(lang_file)
for entry in pofile.translated_entries(): for entry in pofile.translated_entries():
if entry.msgid in HEADINGS: if entry.msgid in BASE_STRINGS:
headings_l10n[entry.msgid] = entry.msgstr strings_l10n[entry.msgid] = entry.msgstr
else: else:
print("No PO file at '{}' for language '{}'.".format(lang_file, args.lang)) print("No PO file at '{}' for language '{}'.".format(lang_file, args.lang))
@ -494,6 +508,14 @@ def main(): # type: () -> None
exit(1) exit(1)
def translate(string): # type: (str) -> str
"""Translate a string based on translations sourced from `doc/translations/*.po`
for a language if defined via the --lang command line argument.
Returns the original string if no translation exists.
"""
return strings_l10n.get(string, string)
def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, State, bool, str) -> None
class_name = class_def.name class_name = class_def.name
@ -515,7 +537,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
# Ascendants # Ascendants
if class_def.inherits: if class_def.inherits:
inh = class_def.inherits.strip() inh = class_def.inherits.strip()
f.write("**Inherits:** ") f.write("**" + translate("Inherits:") + "** ")
first = True first = True
while inh in state.classes: while inh in state.classes:
if not first: if not first:
@ -538,7 +560,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
inherited.append(c.name) inherited.append(c.name)
if len(inherited): if len(inherited):
f.write("**Inherited By:** ") f.write("**" + translate("Inherited By:") + "** ")
for i, child in enumerate(inherited): for i, child in enumerate(inherited):
if i > 0: if i > 0:
f.write(", ") f.write(", ")
@ -569,7 +591,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
default = property_def.default_value default = property_def.default_value
if default is not None and property_def.overrides: if default is not None and property_def.overrides:
ref = ":ref:`{1}<class_{1}_property_{0}>`".format(property_def.name, property_def.overrides) ref = ":ref:`{1}<class_{1}_property_{0}>`".format(property_def.name, property_def.overrides)
ml.append((type_rst, property_def.name, default + " (overrides " + ref + ")")) # Not using translate() for now as it breaks table formatting.
ml.append((type_rst, property_def.name, default + " " + "(overrides %s)" % ref))
else: else:
ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name) ref = ":ref:`{0}<class_{1}_property_{0}>`".format(property_def.name, class_name)
ml.append((type_rst, ref, default)) ml.append((type_rst, ref, default))
@ -687,12 +710,13 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name)) f.write("- {} **{}**\n\n".format(property_def.type_name.to_rst(state), property_def.name))
info = [] info = []
# Not using translate() for now as it breaks table formatting.
if property_def.default_value is not None: if property_def.default_value is not None:
info.append(("*Default*", property_def.default_value)) info.append(("*" + "Default" + "*", property_def.default_value))
if property_def.setter is not None and not property_def.setter.startswith("_"): if property_def.setter is not None and not property_def.setter.startswith("_"):
info.append(("*Setter*", property_def.setter + "(value)")) info.append(("*" + "Setter" + "*", property_def.setter + "(" + "value" + ")"))
if property_def.getter is not None and not property_def.getter.startswith("_"): if property_def.getter is not None and not property_def.getter.startswith("_"):
info.append(("*Getter*", property_def.getter + "()")) info.append(("*" + "Getter" + "*", property_def.getter + "()"))
if len(info) > 0: if len(info) > 0:
format_table(f, info) format_table(f, info)
@ -781,7 +805,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
info = [] info = []
if theme_item_def.default_value is not None: if theme_item_def.default_value is not None:
info.append(("*Default*", theme_item_def.default_value)) # Not using translate() for now as it breaks table formatting.
info.append(("*" + "Default" + "*", theme_item_def.default_value))
if len(info) > 0: if len(info) > 0:
format_table(f, info) format_table(f, info)
@ -1305,8 +1330,9 @@ def make_method_signature(
def make_heading(title, underline, l10n=True): # type: (str, str, bool) -> str def make_heading(title, underline, l10n=True): # type: (str, str, bool) -> str
if l10n: if l10n:
if title in headings_l10n: new_title = translate(title)
title = headings_l10n.get(title) if new_title != title:
title = new_title
underline *= 2 # Double length to handle wide chars. underline *= 2 # Double length to handle wide chars.
return title + "\n" + (underline * len(title)) + "\n\n" return title + "\n" + (underline * len(title)) + "\n\n"
@ -1316,12 +1342,12 @@ def make_footer(): # type: () -> str
# This way, we avoid bloating the generated rST with duplicate abbreviations. # This way, we avoid bloating the generated rST with duplicate abbreviations.
# fmt: off # fmt: off
return ( return (
".. |virtual| replace:: :abbr:`virtual (This method should typically be overridden by the user to have any effect.)`\n" ".. |virtual| replace:: :abbr:`virtual (" + translate("This method should typically be overridden by the user to have any effect.") + ")`\n"
".. |const| replace:: :abbr:`const (This method has no side effects. It doesn't modify any of the instance's member variables.)`\n" ".. |const| replace:: :abbr:`const (" + translate("This method has no side effects. It doesn't modify any of the instance's member variables.") + ")`\n"
".. |vararg| replace:: :abbr:`vararg (This method accepts any number of arguments after the ones described here.)`\n" ".. |vararg| replace:: :abbr:`vararg (" + translate("This method accepts any number of arguments after the ones described here.") + ")`\n"
".. |constructor| replace:: :abbr:`constructor (This method is used to construct a type.)`\n" ".. |constructor| replace:: :abbr:`constructor (" + translate("This method is used to construct a type.") + ")`\n"
".. |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" ".. |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"
".. |operator| replace:: :abbr:`operator (This method describes a valid operator to use with this type as left-hand operand.)`\n" ".. |operator| replace:: :abbr:`operator (" + translate("This method describes a valid operator to use with this type as left-hand operand.") + ")`\n"
) )
# fmt: on # fmt: on

View File

@ -26,7 +26,7 @@ msgstr ""
""" """
# Some strings used by make_rst.py are normally part of the editor translations, # Some strings used by make_rst.py are normally part of the editor translations,
# so we need to include them manually here for the online docs. # so we need to include them manually here for the online docs.
HEADINGS = [ BASE_STRINGS = [
"Description", "Description",
"Tutorials", "Tutorials",
"Properties", "Properties",
@ -42,6 +42,19 @@ HEADINGS = [
"Method Descriptions", "Method Descriptions",
"Operator Descriptions", "Operator Descriptions",
"Theme Property Descriptions", "Theme Property Descriptions",
"Inherits:",
"Inherited By:",
"(overrides %s)",
"Default",
"Setter",
"value",
"Getter",
"This method should typically be overridden by the user to have any effect.",
"This method has no side effects. It doesn't modify any of the instance's member variables.",
"This method accepts any number of arguments after the ones described here.",
"This method is used to construct a type.",
"This method doesn't need an instance to be called, so it can be called directly using the class name.",
"This method describes a valid operator to use with this type as left-hand operand.",
] ]
## <xml-line-number-hack from="https://stackoverflow.com/a/36430270/10846399"> ## <xml-line-number-hack from="https://stackoverflow.com/a/36430270/10846399">
@ -229,12 +242,12 @@ def _make_translation_catalog(classes):
def _generate_translation_catalog_file(unique_msgs, output, location_line=False): def _generate_translation_catalog_file(unique_msgs, output, location_line=False):
with open(output, "w", encoding="utf8") as f: with open(output, "w", encoding="utf8") as f:
f.write(HEADER) f.write(HEADER)
for msg in HEADINGS: for msg in BASE_STRINGS:
f.write("#: doc/tools/make_rst.py\n") f.write("#: doc/tools/make_rst.py\n")
f.write('msgid "{}"\n'.format(msg)) f.write('msgid "{}"\n'.format(msg))
f.write('msgstr ""\n\n') f.write('msgstr ""\n\n')
for msg in unique_msgs: for msg in unique_msgs:
if len(msg) == 0 or msg in HEADINGS: if len(msg) == 0 or msg in BASE_STRINGS:
continue continue
f.write("#:") f.write("#:")