Skip to content

Commit 7c97f9e

Browse files
cagnuleinclaude
andcommitted
Add fitness/cycling domain glossary to ollama-translate.py
Inject per-language term glossary into the Ollama prompt so domain-specific words are translated correctly (e.g. "Gears" → "Marce" in Italian, not "Ingranaggi"). Covers Italian, French, Spanish, German and Portuguese. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 86dcd67 commit 7c97f9e

1 file changed

Lines changed: 91 additions & 1 deletion

File tree

tools/ollama-translate.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,82 @@
4040
"Watt",
4141
}
4242

43+
# Domain-specific glossary for fitness/cycling terms.
44+
# Keys are English source terms (case-sensitive), values are the preferred translation.
45+
# Add entries here when the LLM picks the wrong word for a domain-specific concept.
46+
GLOSSARY: dict[str, dict[str, str]] = {
47+
"Italian": {
48+
"Gears": "Marce",
49+
"Gear": "Marcia",
50+
"Gear +": "Marcia +",
51+
"Gear -": "Marcia -",
52+
"Gears +": "Marce +",
53+
"Gears -": "Marce -",
54+
"Cadence": "Cadenza",
55+
"Resistance": "Resistenza",
56+
"Inclination": "Inclinazione",
57+
"Incline": "Pendenza",
58+
"Peloton Resistance": "Resistenza Peloton",
59+
"Watts": "Watt",
60+
"Lap": "Giro",
61+
"Stride": "Passo",
62+
"Step Count": "Contapassi",
63+
"Ramp": "Rampa",
64+
},
65+
"French": {
66+
"Gears": "Vitesses",
67+
"Gear": "Vitesse",
68+
"Gear +": "Vitesse +",
69+
"Gear -": "Vitesse -",
70+
"Gears +": "Vitesses +",
71+
"Gears -": "Vitesses -",
72+
"Cadence": "Cadence",
73+
"Resistance": "Résistance",
74+
"Inclination": "Inclinaison",
75+
"Incline": "Pente",
76+
"Lap": "Tour",
77+
},
78+
"Spanish": {
79+
"Gears": "Marchas",
80+
"Gear": "Marcha",
81+
"Gear +": "Marcha +",
82+
"Gear -": "Marcha -",
83+
"Gears +": "Marchas +",
84+
"Gears -": "Marchas -",
85+
"Cadence": "Cadencia",
86+
"Resistance": "Resistencia",
87+
"Inclination": "Inclinación",
88+
"Incline": "Pendiente",
89+
"Lap": "Vuelta",
90+
},
91+
"German": {
92+
"Gears": "Gänge",
93+
"Gear": "Gang",
94+
"Gear +": "Gang +",
95+
"Gear -": "Gang -",
96+
"Gears +": "Gänge +",
97+
"Gears -": "Gänge -",
98+
"Cadence": "Kadenz",
99+
"Resistance": "Widerstand",
100+
"Inclination": "Neigung",
101+
"Incline": "Steigung",
102+
"Lap": "Runde",
103+
},
104+
"Portuguese": {
105+
"Gears": "Marchas",
106+
"Gear": "Marcha",
107+
"Gear +": "Marcha +",
108+
"Gear -": "Marcha -",
109+
"Gears +": "Marchas +",
110+
"Gears -": "Marchas -",
111+
"Cadence": "Cadência",
112+
"Resistance": "Resistência",
113+
"Inclination": "Inclinação",
114+
"Incline": "Inclinação",
115+
"Lap": "Volta",
116+
},
117+
}
118+
43119

44120
def should_skip_source(text: str) -> bool:
45121
s = text.strip()
@@ -94,12 +170,26 @@ def count_accelerators(text: str) -> int:
94170
return count
95171

96172

173+
def build_glossary_section(target_language: str) -> str:
174+
lang_glossary = GLOSSARY.get(target_language, {})
175+
if not lang_glossary:
176+
return ""
177+
lines = [f'- "{en}" → "{tr}"' for en, tr in lang_glossary.items()]
178+
return (
179+
"\nDomain glossary (fitness/cycling context — use these translations exactly):\n"
180+
+ "\n".join(lines)
181+
+ "\n"
182+
)
183+
184+
97185
def call_ollama(
98186
model: str,
99187
source_text: str,
100188
target_language: str,
101189
timeout: int = 180,
102190
) -> str:
191+
glossary_section = build_glossary_section(target_language)
192+
103193
prompt = f"""You are translating UI strings for QZ, a Qt/QML fitness app.
104194
105195
Translate from English to {target_language}.
@@ -118,7 +208,7 @@ def call_ollama(
118208
- Do not translate brand/product/protocol names: {", ".join(BRANDS)}.
119209
- Keep the translation short and suitable for a mobile app UI.
120210
- If the source text is already a brand name, protocol name, number, symbol, or file pattern, return it unchanged.
121-
211+
{glossary_section}
122212
Source text:
123213
{source_text}
124214
"""

0 commit comments

Comments
 (0)