GitHub user glaterza added a comment to the discussion: Proposal: a translation
guide, with shared principles and per-language conventions
## Update on translations: what we did and what I propose next
**In short:** I propose a glossary file for each language and one shared list
of core terms, next to the catalogs. The AI backfill and the CI checks read
these files. In a local test, the backfill used a glossary term in 5 of 5 runs.
With the prompt on master, it used the term in 0 of 5. The work is 10 small
PRs, one issue and one later proposal. Steps 1 to 4 are the main change.
**What I need from you:** a review of the Translation Guide PR, #45181, and
your view on the direction below. If nobody objects within 7 days, I will start
with step 2.
Thank you, @hainenber and @sadpandajoe, for the reviews of #44397. @hainenber
merged it on 2026-10-10.
### Your suggestions and what happened
| Who | Suggestion | Status |
|---|---|---|
| @rusackas, Aug 26 | Worried that nobody would maintain glossaries. Asked for
automation, such as structured comments in `messages.pot`. Supported shared
rules on the docs site. | #44397 (`i18n:` notes), Translation Guide #45181 |
| @sfirke, Aug 31 | Rules next to each catalog, or a pointer in each `.po` file
to follow and update them | Steps 4 and 10 |
| @rusackas, Sep 14 | Agreed: `--add-comments` first, as its own PR;
tool-checked parts next to the catalogs, prose on the docs site | #44397, and
this plan |
| @rusackas, Sep 16 | Fix the `msgcat` flag; a separate issue for the missing
strings | #44395; #44403, closed by #44467 (@sadpandajoe) |
| @rusackas, Sep 23 | Agreed to clear fuzzy entries with broken placeholders
(#44551); the English fallback as its own PR | #44611 cleared 1,188 entries;
step 7 |
| @goldjee, Oct 1–2 | A glossary per language for the backfill; the same core
terms in every string; two style rules (no full stop after a one-sentence
message; ё or е chosen once) | Steps 3 and 4; the rules are examples in the
Guide |
Also merged: #44587 by @sadpandajoe fixed the Slovak error in SQL Lab.
### Known problems
#### The AI backfill
1. In my test, the model ignored a note when the other languages had wrong
translations. For the Russian `Backend`, I gave five languages wrong words,
such as German «Treiber» ("driver") and French «Serveur» ("server"). The model
then answered «Драйвер» ("driver") in 29 of 30 runs, with or without a note
(`claude-sonnet-4-6`). With the real translations, it answered «Бэкенд» in 12
of 12 runs.
2. The backfill sends the other languages' translations of each string, but not
the terms that the target catalog already uses. So the model can create a new
term for a concept that the catalog already names, as in @goldjee's example,
probably "annotation template".
#### Translator notes
3. pybabel drops a note without an error in four cases:
- a blank line between the note and the call;
- the note inside the parentheses of a call;
- a wrapped Python string with only a comment or nothing after it;
- the second of two calls on one line.
I put a note above each of the 1,005 `_(` and `__(` calls in `superset/`,
without migrations. pybabel dropped 126 of them.
#### The catalogs
4. Some translations are wrong: `Slug` in Dutch and German, `Host` in Italian,
`Backend` in Russian and French, and `URL Slug` in Dutch. I found these by
chance, so the list is not complete. Also, Spanish, Romanian and Serbian use
the same words for "dashboard" and "control panel".
5. Some fuzzy translations that nobody reviewed have a wrong meaning. Superset
shows fuzzy translations on purpose, and this decision is in the howto. For
example, Polish and Dutch show "List Users" as "split number" and "Themes" as
"time". About 14,900 fuzzy entries have no AI backfill comment.
6. No CI check covers placeholders in all catalogs. `msgfmt --check-format
--use-fuzzy` reports 166 errors, and 14 of them are in reviewed entries. Of the
166, 137 are in plural entries, and some of those are correct translations.
7. The Polish catalog has the French header and plural rule, so Polish users
see wrong plural forms, for example «Usunięto 5 pulpity nawigacyjne».
#### The process
8. In the 14 days up to 2026-10-10, 36 commits on master changed
`messages.pot`, on 12 different days. A PR that changes this file often has
merge conflicts, so I keep every step small.
<details>
<summary>Corrections to my earlier comments</summary>
- On #44397, I wrote that the note fixed the Russian `Backend`. That result did
not repeat, and I corrected it there.
- On Sep 17, I wrote that other comments stay out of the catalogs. That was
wrong: pybabel adds every comment line between the `i18n:` line and the call to
the note. #45181 corrects the howto.
- On Sep 17, I wrote that the backend drops fuzzy entries. That was wrong: the
release build compiles the backend with `-f`, and a Docker image built with
`BUILD_TRANSLATIONS=true` uses `--use-fuzzy`.
</details>
### What I propose
Files that a tool reads go next to the catalogs. Rules for people go on the
docs site.
1. Rules for people: the Translation Guide, #45181. It includes @goldjee's two
style rules as examples of decisions that each language makes once.
2. Files for tools: one glossary file per language, next to its catalog, and
one shared list of core terms. For example,
`superset/translations/es/glossary.yaml`:
```yaml
style:
register: informal # tú (informal)
terms:
- source: control panel
target: panel de configuración
why: '"panel de control" already means dashboard in 118 reviewed entries'
avoid: [panel de control]
```
`superset/translations/terms.yaml` lists the core terms, with one line of
English for each. It starts from @goldjee's list. I use "metric" instead of
"measure", because the UI uses "metric" or "metrics" in 193 strings and
"measure" in 2:
```
dashboard, filter, chart, metric, dimension, dataset, column, annotation,
annotation layer, annotation template, database connection, SQL Lab
```
The backfill takes each language's translations of these terms from its
catalog, so a language without a glossary file also benefits. A native speaker
corrects a term in the glossary file. The files will have the ASF license
header, and `MANIFEST.in` already ships every file in `superset/translations`.
3. Tools that read these files:
- With each string, the backfill sends the register, and the glossary terms
and core terms that the string uses. It skips the old translation of a term
that has a note or a glossary entry, because that translation can be wrong.
- The prompt uses one order: a glossary term or a note first, then the terms
of the catalog, then the other languages. For a string with a note, the
backfill does not send the other languages.
- `scripts/translations/backfill_eval.py` translates known hard cases
several times and counts the correct answers. It calls the model through
`claude -p`, so the author of a prompt change runs it by hand.
- The drift check also fails when an `i18n:` comment in the code does not
reach its entry in `messages.pot`.
- An advisory CI check lists translations that use a word from a glossary's
`avoid` list. It checks only entries whose English text contains the `source`
term.
- `babel_update.sh` writes a pointer at the top of each `.po` file that has
a glossary. In the pointer, translators read that they must follow the glossary
and, if needed, update it.
#### Test of a local prototype
I built the backfill part and ran four cases that I chose, 5 times each, with
`claude-sonnet-4-6`:
| Case | Prompt on master | Prototype |
|---|---|---|
| Russian "Backend" with a note | 0 of 5 | 5 of 5 had no "driver", but with
four different words |
| Russian "Backend" with the glossary term «Бэкенд» | 0 of 5 | 5 of 5 |
| Spanish "control panel" with the glossary term «panel de configuración» | 0
of 5 | 5 of 5 |
| Spanish "dashboard" in a new string, with the catalog term «Panel de control»
| 0 of 5 | 5 of 5 |
A glossary term or a catalog term gave the same word in all runs. With a note,
the model chose the right meaning, but it used different words.
<details>
<summary>How the test works</summary>
- In the Russian cases, I gave the model wrong translations in five other
languages, for example German «Treiber» ("driver").
- In the Spanish control-panel case, the other languages have their own correct
words, and these words lead to «panel de control» in Spanish. The new dashboard
string has no translations in other languages.
- A run passes when the answer has the expected word. For the note case, a run
passes when the answer has no "driver", "server" or "controller". The four
words were «Бэкенд», «Движок» ("engine"), «База данных» ("database") and «Тип
системы» ("system type").
- When the prompt also had the translations of the other languages, the note
case stayed at 0 of 5.
</details>
#### Alternatives I rejected
- A glossary only on the docs site: no tool reads it, and on Aug 26 @rusackas
worried that nobody would maintain the glossaries.
- Notes only, without glossary files: in the test, a note did not give one
fixed word.
### Roadmap
Steps 1 to 10 are small, separate PRs. Steps 1 to 4 are the main change.
1. The Translation Guide, #45181. It needs a maintainer's review.
2. The prompt order, no other languages for a string with a note, and
`backfill_eval.py`.
3. `terms.yaml`, and the backfill sends the core-term translations.
4. A glossary file for `es`, which I will write, and the backfill reads
glossary files.
5. Fixes for the real `msgfmt` errors. I check the plural forms, and I ask
native speakers where I cannot judge. Then a CI check for new errors, with a
list of the correct plural forms.
6. The placement check in the drift check.
7. The English fallback in the backend and in the frontend.
8. The Polish header and plural forms, with a Polish speaker.
9. The advisory `avoid` check.
10. The glossary pointer in each `.po` file that has a glossary.
11. An issue with the wrong translations above, including the Romanian and
Serbian "dashboard" and "control panel" words.
12. A proposal for the fuzzy translations that nobody reviewed.
GitHub link:
https://github.com/apache/superset/discussions/43562#discussioncomment-18857741
----
This is an automatically sent email for [email protected].
To unsubscribe, please send an email to:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]