A package holds every language of one application. Creating one package per language splits the source of truth and makes progress impossible to read at a glance.
A namespace is the origin file, and it becomes the file name on export. Renaming
common to general does not move the keys — it creates a
second namespace and leaves the first one behind. Decide the file layout before the first
import.
fr.common.json, common.fr.json and
locales/fr/common.json are all detected automatically.
translations_final_v2.json is not, and someone will eventually import it as
the wrong language.
The preview is computed by the same code that does the write, so the numbers it shows are the numbers you will get. A preview that reports thirty keys removed when you expected none usually means the wrong file, the wrong namespace, or the wrong language.
Target-language files can only fill keys the source already defines. Importing French into an empty package produces a report full of no such key in the source language, and nothing is written — correctly, because a translation with no source is not a translation.
Do not clean out old language files from the project's Files tab. The sequence of uploaded files is the version history of the source material, and every import in this App points back at the exact file it read.
The validator refuses a translation that loses or gains a %s,
%1$s, {count}, {{name}} or an HTML tag. That is not
pedantry: an application that runs sprintf on a string missing its argument
crashes, and it crashes only for the users of that one language, which is exactly where
nobody is looking.
Word order changes between languages, and the validator allows it — it compares which
placeholders are present and how many, not where they sit.
%2$s de %1$s is a perfectly valid translation of %1$s of %2$s.
Managers can save past the validator. The right reason is a genuine source-string bug; the wrong reason is being in a hurry. Every override is recorded in the package history.
The AI context is sent with every request and is the single biggest lever on quality. Two useful sentences beat two paragraphs of vague adjectives:
"A B2B logistics dashboard used by warehouse staff. Formal register, address the user politely, keep labels short. 'Shipment' always means a physical consignment, never a document."
AI output is saved as Draft for a reason. Machine translation of UI strings is good at grammar and bad at context: it will confidently translate a button label as a full sentence, or a product name as a common noun. Read the drafts, then confirm them.
Running the AI over five thousand keys produces five thousand drafts nobody will read, and they will be confirmed in bulk out of fatigue. Namespace by namespace is a better rhythm.
Under Settings → AI → Operations, the translation operation can have its own provider, key and model. That is how you find out what localisation actually costs, and it lets you use a cheaper model here than for the workspace's other AI features.
Translated means a person typed it. Reviewed should mean a second person signed it off. If everyone marks their own work reviewed, the status stops carrying information and the progress bars start lying.
Outdated is the App telling you precisely which translations drifted. It is a short, finite list right after an import; left alone for three releases it becomes the reason a language quietly rots.
A translator needs Translate strings, not Manage. Manage includes import, export, the GitHub connection and the ability to override the placeholder validator.
Someone who cannot see the project cannot see its packages, whatever their App permissions say. Add translators to the project, not around it.
Contents: read & write on a single repository is all the App needs.
A classic token with full repo scope gives it far more than it will ever use.
Pulling first means you translate the current source text. Pulling after a week of work means discovering that half of it is already outdated.
The overwrite gate exists because the alternative is silently destroying someone's work. When it appears, open the files on GitHub and look at what changed. Usually a developer added a key by hand — in which case pull, import, and push cleanly instead of overwriting.
Push to a working branch and open a pull request. The App deliberately refuses to
force-update a branch that moved underneath it, but it cannot judge whether a commit
belongs on main.