[i18n] French translations in production: what is still broken, and a fix for each (supersedes #13530)
I opened #13530 in June. I've re-checked every point against the current state (latest l10n_main export and Crowdin project settings, 2026-09-17). Two claims there were inaccurate, several problems got worse, and there are new ones. This issue replaces it with verified facts and one concrete fix per problem.
Summary
| # | Problem | Fix |
|---|---|---|
| 1 | No translation has reached main since 2026-06-20 |
Rotate CROWDIN_PRS, alert on stale l10n PRs |
| 2 | Broken machine translations still ship in 100+ pieces | Roll back + CI check on technical identifiers |
| 3 | The Custom API Call block is translated separately in every piece | Exclude it from translation extraction |
| 4 | The piece docs teach the workflow that Crowdin overwrites | Update the docs page, CONTRIBUTING and PR template |
| 5 | Unreviewed and untranslated strings ship as-is | Document proofreader access, review export settings |
1. No translation has reached main since 2026-06-20
The last merged Crowdin PR is #13815 (2026-06-20). #13894 then stayed open until 2026-09-08, because the required Lint PR check rejects the title "New Crowdin updates". Its replacement #15370 is still open: the Auto Merge Crowdin PRs Action run of 2026-09-10 failed with HttpError: Bad credentials.
Nothing alerted anyone for almost three months.
→ Rotate CROWDIN_PRS, and fail a scheduled job when the newest l10n PR is older than N days.
2. Broken machine translations still ship
From the latest l10n_main export (757 fr.json):
| Source | Shipped French | Pieces |
|---|---|---|
PUT |
"EFFACER" (= erase) | 133 |
GET / POST / DELETE |
"OBTENIR" / "POSTER" / "SUPPRIMER" | 133 |
HEAD |
"TÊTE" | 121 |
First Name |
"First Name" (left untranslated) | 96 |
Text |
"Texte du texte" ("text of the text") | 53 |
Page Size |
"Nombre d'élément" | 29 |
Table |
"Tableau" (grid view, not a database table) | 14 |
Upsert Row |
"Lignée supérieure" ("upper lineage") | 3 |
The HTTP methods are the worst: picking "EFFACER" in the method dropdown sends a PUT.
→ Add a CI check that technical identifiers (HTTP methods, JSON, placeholders) stay verbatim, and roll back the existing damage.
3. The Custom API Call block is translated separately in every piece
createCustomApiCallAction (packages/pieces/common) is extracted into each piece's translation.json, so Crowdin holds 479 separate French copies of the same form, each pre-translated independently. They disagree: Headers is "En-têtes" in 209 pieces and "Headers" in 267.
This is a technical form for raw HTTP calls, and its vocabulary is English. #15248 (2026-09-07) redesigned it (Timeout, Return Error as Output, URL, JSON Body…). Pieces depend on pieces-common via workspace:*, so every regeneration of a piece's translation.json pushes the new labels as new strings — ~479 pieces × 8 languages, all pre-translated again.
→ Exclude the block from extraction (generateTranslationFileFromPiece / pieceTranslation.pathsToValuesToTranslate) or mark it do-not-translate, and reset the existing translations.
4. The piece docs teach the workflow that Crowdin overwrites
docs/build-pieces/piece-reference/i18n.mdx tells piece authors to copy translation.json to fr.json and translate it themselves; Crowdin appears only as a tip. Crowdin's sync later replaces that file, so the work is silently lost. CONTRIBUTING.md and the PR template don't mention translations at all.
(Correction to #13530: docs/about/i18n.mdx does describe Crowdin, since 2023.)
→ Make Crowdin the only documented path on that page, and add one line to CONTRIBUTING.md and the PR template.
5. Unreviewed and untranslated strings ship as-is
Current project settings: AI pre-translation is on for all 8 languages, TM pre-translation auto-approves 100% matches, and exportApprovedOnly and skipUntranslatedStrings are both false. Untranslated strings therefore ship as English copies — the Outseta fr.json on main contains "Account Created": "Account Created" — and unreviewed AI output ships as if reviewed.
Approval is the only lock. (Correction to #13530: translators can approve — I was granted proofreader rights — but nothing documents how to ask for them.) → Document how to request proofreader access for a locale, and confirm pre-translation never replaces an existing human translation.
Related
- #15586 — auth texts of pieces with several auth methods are never translated (30 pieces)
I maintain 14 pieces and keep their French approved in Crowdin. Happy to help test any of these changes.
Source: activepieces/activepieces