fix: wrap long language comment in gen_i18n.py output

This commit is contained in:
pablohc
2026-03-29 22:44:43 +02:00
parent 81d992d254
commit 4699ff0b88
2 changed files with 61 additions and 35 deletions
+2 -1
View File
@@ -408,7 +408,8 @@ inline const char* const* getStringArray(Language lang) {
constexpr uint8_t getLanguageCount() { return static_cast<uint8_t>(Language::_COUNT); } constexpr uint8_t getLanguageCount() { return static_cast<uint8_t>(Language::_COUNT); }
// Sorted language indices by code (auto-generated by gen_i18n.py) // Sorted language indices by code (auto-generated by gen_i18n.py)
// Order: English, Беларуская, Català, Čeština, Dansk, Deutsch, Español, Suomi, Français, Italiano, Қазақша, Nederlands, Polski, Português (Brasil), Română, Русский, Svenska, Türkçe, Українська // Order: English,
// Беларуская, Català, Čeština, Dansk, Deutsch, Español, Suomi, Français, Italiano, Қазақша, Nederlands, Polski, Português (Brasil), Română, Русский, Svenska, Türkçe, Українська
constexpr uint8_t SORTED_LANGUAGE_INDICES[] = {0, 11, 9, 4, 15, 3, 1, 14, 2, 12, 18, 16, 13, 5, 8, 6, 7, 17, 10}; constexpr uint8_t SORTED_LANGUAGE_INDICES[] = {0, 11, 9, 4, 15, 3, 1, 14, 2, 12, 18, 16, 13, 5, 8, 6, 7, 17, 10};
static_assert(sizeof(SORTED_LANGUAGE_INDICES) / sizeof(SORTED_LANGUAGE_INDICES[0]) == getLanguageCount(), static_assert(sizeof(SORTED_LANGUAGE_INDICES) / sizeof(SORTED_LANGUAGE_INDICES[0]) == getLanguageCount(),
+59 -34
View File
@@ -33,6 +33,7 @@ from typing import List, Dict, Tuple
# YAML file reading (simple key: "value" format, no PyYAML dependency) # YAML file reading (simple key: "value" format, no PyYAML dependency)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def _unescape_yaml_value(raw: str, filepath: str = "", line_num: int = 0) -> str: def _unescape_yaml_value(raw: str, filepath: str = "", line_num: int = 0) -> str:
""" """
Process escape sequences in a YAML value string. Process escape sequences in a YAML value string.
@@ -51,9 +52,7 @@ def _unescape_yaml_value(raw: str, filepath: str = "", line_num: int = 0) -> str
elif nxt == "n": elif nxt == "n":
result.append("\n") result.append("\n")
else: else:
raise ValueError( raise ValueError(f"{filepath}:{line_num}: unknown escape '\\{nxt}'")
f"{filepath}:{line_num}: unknown escape '\\{nxt}'"
)
i += 2 i += 2
else: else:
result.append(raw[i]) result.append(raw[i])
@@ -103,6 +102,7 @@ def parse_yaml_file(filepath: str) -> Dict[str, str]:
# Load all languages from a directory of YAML files # Load all languages from a directory of YAML files
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def load_translations( def load_translations(
translations_dir: str, translations_dir: str,
) -> Tuple[List[str], List[str], List[str], Dict[str, List[str]]]: ) -> Tuple[List[str], List[str], List[str], Dict[str, List[str]]]:
@@ -207,23 +207,37 @@ def load_translations(
LANG_ABBREVIATIONS = { LANG_ABBREVIATIONS = {
"english": "EN", "english": "EN",
"español": "ES", "espanol": "ES", "español": "ES",
"espanol": "ES",
"italiano": "IT", "italiano": "IT",
"svenska": "SV", "svenska": "SV",
"français": "FR", "francais": "FR", "français": "FR",
"deutsch": "DE", "german": "DE", "francais": "FR",
"deutsch": "DE",
"german": "DE",
"polski": "PL", "polski": "PL",
"português": "PT", "portugues": "PT", "português (brasil)": "PO", "português": "PT",
"中文": "ZH", "chinese": "ZH", "portugues": "PT",
"日本語": "JA", "japanese": "JA", "português (brasil)": "PO",
"한국어": "KO", "korean": "KO", "中文": "ZH",
"русский": "RU", "russian": "RU", "chinese": "ZH",
"العربية": "AR", "arabic": "AR", "日本語": "JA",
"עברית": "HE", "hebrew": "HE", "japanese": "JA",
"فارسی": "FA", "persian": "FA", "한국어": "KO",
"korean": "KO",
"русский": "RU",
"russian": "RU",
"العربية": "AR",
"arabic": "AR",
"עברית": "HE",
"hebrew": "HE",
"فارسی": "FA",
"persian": "FA",
"čeština": "CS", "čeština": "CS",
"türkçe": "TR", "turkish": "TR", "türkçe": "TR",
"Қазақша": "KK", "kazakh": "KK", "turkish": "TR",
"Қазақша": "KK",
"kazakh": "KK",
} }
@@ -267,12 +281,12 @@ def escape_cpp_string(s: str) -> List[str]:
if ch == "\\" and i + 1 < len(s): if ch == "\\" and i + 1 < len(s):
nxt = s[i + 1] nxt = s[i + 1]
if nxt in "ntr\"\\": if nxt in 'ntr"\\':
current.append(ch + nxt) current.append(ch + nxt)
i += 2 i += 2
elif nxt == "x" and i + 3 < len(s): elif nxt == "x" and i + 3 < len(s):
current.append(s[i : i + 4]) current.append(s[i : i + 4])
_flush() # segment break after hex _flush() # segment break after hex
i += 4 i += 4
else: else:
current.append("\\\\") current.append("\\\\")
@@ -286,7 +300,7 @@ def escape_cpp_string(s: str) -> List[str]:
else: else:
for byte in ch.encode("utf-8"): for byte in ch.encode("utf-8"):
current.append(f"\\x{byte:02X}") current.append(f"\\x{byte:02X}")
_flush() # segment break after hex _flush() # segment break after hex
i += 1 i += 1
# Flush remaining content # Flush remaining content
@@ -321,11 +335,11 @@ def format_cpp_string_literal(segments: List[str], indent: str = " ") -> List
last_space = -1 last_space = -1
idx = 0 idx = 0
while idx <= MAX_CONTENT_LEN and idx < len(current): while idx <= MAX_CONTENT_LEN and idx < len(current):
if current[idx] == ' ': if current[idx] == " ":
last_space = idx last_space = idx
# Handle escapes to step correctly # Handle escapes to step correctly
if current[idx] == '\\': if current[idx] == "\\":
idx += 2 idx += 2
else: else:
idx += 1 idx += 1
@@ -340,7 +354,7 @@ def format_cpp_string_literal(segments: List[str], indent: str = " ") -> List
# No space, forced break at MAX_CONTENT_LEN (or slightly less) # No space, forced break at MAX_CONTENT_LEN (or slightly less)
cut_at = MAX_CONTENT_LEN cut_at = MAX_CONTENT_LEN
# Don't cut in the middle of an escape sequence # Don't cut in the middle of an escape sequence
if current[cut_at - 1] == '\\': if current[cut_at - 1] == "\\":
cut_at -= 1 cut_at -= 1
lines.append(f'{indent}"{current[:cut_at]}"') lines.append(f'{indent}"{current[:cut_at]}"')
@@ -356,6 +370,7 @@ def format_cpp_string_literal(segments: List[str], indent: str = " ") -> List
# Character-set computation # Character-set computation
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def compute_character_set(translations: Dict[str, List[str]], lang_index: int) -> str: def compute_character_set(translations: Dict[str, List[str]], lang_index: int) -> str:
"""Return a sorted string of every unique character used in a language.""" """Return a sorted string of every unique character used in a language."""
chars = set() chars = set()
@@ -369,6 +384,7 @@ def compute_character_set(translations: Dict[str, List[str]], lang_index: int) -
# Code generators # Code generators
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def generate_keys_header( def generate_keys_header(
languages: List[str], languages: List[str],
language_names: List[str], language_names: List[str],
@@ -451,9 +467,15 @@ def generate_keys_header(
key=lambda i: languages[i], key=lambda i: languages[i],
) )
sorted_indices = [english_idx] + rest sorted_indices = [english_idx] + rest
comment_names = ", ".join(language_names[i] for i in sorted_indices) names = [language_names[i] for i in sorted_indices]
comment_names = ", ".join(names)
lines.append("// Sorted language indices by code (auto-generated by gen_i18n.py)") lines.append("// Sorted language indices by code (auto-generated by gen_i18n.py)")
lines.append(f"// Order: {comment_names}") if len(f"// Order: {comment_names}") <= 100:
lines.append(f"// Order: {comment_names}")
else:
lines.append("// Order: " + names[0] + ",")
rest_line = ", ".join(names[1:])
lines.append("// " + rest_line)
lines.append( lines.append(
"constexpr uint8_t SORTED_LANGUAGE_INDICES[] = {" "constexpr uint8_t SORTED_LANGUAGE_INDICES[] = {"
f"{', '.join(str(i) for i in sorted_indices)}" f"{', '.join(str(i) for i in sorted_indices)}"
@@ -463,9 +485,7 @@ def generate_keys_header(
lines.append( lines.append(
"static_assert(sizeof(SORTED_LANGUAGE_INDICES) / sizeof(SORTED_LANGUAGE_INDICES[0]) == getLanguageCount()," "static_assert(sizeof(SORTED_LANGUAGE_INDICES) / sizeof(SORTED_LANGUAGE_INDICES[0]) == getLanguageCount(),"
) )
lines.append( lines.append(' "SORTED_LANGUAGE_INDICES size mismatch");')
' "SORTED_LANGUAGE_INDICES size mismatch");'
)
_write_file(output_path, lines) _write_file(output_path, lines)
@@ -478,7 +498,7 @@ def generate_strings_header(
"""Generate I18nStrings.h.""" """Generate I18nStrings.h."""
lines: List[str] = [ lines: List[str] = [
"#pragma once", "#pragma once",
'#include <string>', "#include <string>",
"", "",
'#include "I18nKeys.h"', '#include "I18nKeys.h"',
"", "",
@@ -565,9 +585,8 @@ def generate_strings_cpp(
# Helpers # Helpers
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def _append_string_entry(
lines: List[str], text: str, comment: str = "" def _append_string_entry(lines: List[str], text: str, comment: str = "") -> None:
) -> None:
"""Escape *text*, format as indented C++ lines, append comma (and optional comment).""" """Escape *text*, format as indented C++ lines, append comma (and optional comment)."""
segments = escape_cpp_string(text) segments = escape_cpp_string(text)
formatted = format_cpp_string_literal(segments) formatted = format_cpp_string_literal(segments)
@@ -587,6 +606,7 @@ def _write_file(path: str, lines: List[str]) -> None:
# Main # Main
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def main(translations_dir=None, output_dir=None) -> None: def main(translations_dir=None, output_dir=None) -> None:
# Default paths (relative to project root) # Default paths (relative to project root)
default_translations_dir = "lib/I18n/translations" default_translations_dir = "lib/I18n/translations"
@@ -601,7 +621,6 @@ def main(translations_dir=None, output_dir=None) -> None:
translations_dir = default_translations_dir translations_dir = default_translations_dir
output_dir = default_output_dir output_dir = default_output_dir
if not os.path.isdir(translations_dir): if not os.path.isdir(translations_dir):
print(f"Error: Translations directory not found: {translations_dir}") print(f"Error: Translations directory not found: {translations_dir}")
sys.exit(1) sys.exit(1)
@@ -620,10 +639,16 @@ def main(translations_dir=None, output_dir=None) -> None:
) )
out = Path(output_dir) out = Path(output_dir)
generate_keys_header(languages, language_names, string_keys, str(out / "I18nKeys.h")) generate_keys_header(
languages, language_names, string_keys, str(out / "I18nKeys.h")
)
generate_strings_header(languages, language_names, str(out / "I18nStrings.h")) generate_strings_header(languages, language_names, str(out / "I18nStrings.h"))
generate_strings_cpp( generate_strings_cpp(
languages, language_names, string_keys, translations, str(out / "I18nStrings.cpp") languages,
language_names,
string_keys,
translations,
str(out / "I18nStrings.cpp"),
) )
print() print()