Skip to content

Commit 009b5b0

Browse files
committed
Add a new script to translate .en.yml file to other languages
1 parent 7b1e247 commit 009b5b0

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

translate_missing.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env python3
2+
"""
3+
translate_missing.py
4+
5+
This script translates missing or empty keys from the English i18n YAML
6+
file (hyrax.en.yml) into one or more target languages using a local
7+
LibreTranslate endpoint.
8+
9+
Why Python?
10+
- Preserves YAML formatting, comments, and inline/block style using ruamel.yaml
11+
- Ruby's built-in YAML tools rewrite formatting, causing unnecessary diffs
12+
in Git when only translation values change.
13+
- This script is run occasionally, so introducing a small Python helper
14+
is practical for keeping translation diffs clean.
15+
16+
Usage:
17+
18+
Set Up:
19+
1. Make sure LibreTranslate is running locally in a separate shell:
20+
$ pip install libretranslate
21+
$ libretranslate
22+
23+
Run the script:
24+
25+
All at once (multiple languages):
26+
$ python translate_missing.py es zh it fr pt-BR
27+
28+
One at a time (single language):
29+
$ python translate_missing.py es
30+
"""
31+
import json
32+
import sys
33+
import time
34+
import requests
35+
from ruamel.yaml import YAML
36+
from pathlib import Path
37+
38+
# ----------------------
39+
# Configuration
40+
# ----------------------
41+
SOURCE_LANG = "en"
42+
INPUT_FILE = Path("config/locales/hyrax.en.yml")
43+
LIBRETRANSLATE_URL = "http://127.0.0.1:5000/translate"
44+
45+
yaml = YAML()
46+
yaml.explicit_start = True # Add '---' at the top
47+
yaml.preserve_quotes = True
48+
yaml.width = 4096 # avoid folding long lines
49+
50+
# ----------------------
51+
# Load source YAML once
52+
# ----------------------
53+
source_data = yaml.load(INPUT_FILE.read_text())
54+
source = source_data[SOURCE_LANG]
55+
56+
# ----------------------
57+
# Translation helper
58+
# ----------------------
59+
def translate_text(text, source_lang=SOURCE_LANG, target_lang="es"):
60+
if text is None or str(text).strip() == "":
61+
return text
62+
try:
63+
resp = requests.post(
64+
LIBRETRANSLATE_URL,
65+
data={"q": text, "source": source_lang, "target": target_lang},
66+
)
67+
resp.raise_for_status()
68+
translated = json.loads(resp.text)["translatedText"]
69+
print(f"Translated ({target_lang}): {text}{translated}")
70+
return translated
71+
except Exception as e:
72+
print(f"⚠️ Translation error for '{text}': {e}")
73+
return text
74+
75+
# ----------------------
76+
# Recursive merge & translate
77+
# ----------------------
78+
def deep_merge_translate(source_dict, target_dict, target_lang):
79+
result = target_dict.copy()
80+
for key, value in source_dict.items():
81+
if isinstance(value, dict):
82+
result[key] = deep_merge_translate(value, result.get(key, {}), target_lang)
83+
else:
84+
if key not in result or str(result[key]).strip() == "":
85+
result[key] = translate_text(value, target_lang=target_lang)
86+
return result
87+
88+
# ----------------------
89+
# Main loop over target languages
90+
# ----------------------
91+
if len(sys.argv) < 2:
92+
print("Usage: python translate_locales.py <lang1> [<lang2> ...]")
93+
sys.exit(1)
94+
95+
for target_lang in sys.argv[1:]:
96+
print(f"\n=== Translating into {target_lang} ===")
97+
output_file = Path(f"config/locales/hyrax.{target_lang}.yml")
98+
99+
# Load existing target YAML if present
100+
if output_file.exists():
101+
target_data = yaml.load(output_file.read_text())
102+
target = target_data.get(target_lang, {})
103+
else:
104+
target = {}
105+
106+
# Merge and translate
107+
merged = deep_merge_translate(source, target, target_lang)
108+
109+
# Write back preserving formatting
110+
output_data = {target_lang: merged}
111+
with output_file.open("w") as f:
112+
yaml.dump(output_data, f)
113+
114+
print(f"✅ Updated {output_file} — existing translations preserved.")

0 commit comments

Comments
 (0)