String key naming that survives growth
A localization key is metadata that outlives the code that first wrote it. Text gets rewritten, features get renamed, files get restructured — but the key is usually the one thing that has to stay stable, because translation memory, review history, and every downstream tool are keyed on it. Naming decisions that feel trivial at 200 strings become expensive at 20,000, and by then the cost of changing course is paid by everyone downstream, not just the person who picked the scheme.
Hierarchical namespacing
A flat key list scales badly: two features both wanting a key called title or confirm collide, and there's no way to tell at a glance where a string is used. Namespacing the key by screen or system fixes both problems at once, and it means a search for menu.settings.* returns exactly the strings that screen owns, with nothing else mixed in.
menu.settings.audio.masterVolumeLabel menu.settings.audio.muteButton shop.item.buyConfirm
Stable IDs vs content-derived keys
Some systems derive the key from the source text itself — the English string 'Continue' becomes the key. This is fast to set up but has a specific failure mode: if the English text changes even slightly, the key changes, and every existing translation for that key is orphaned, even though the intended meaning did not change.
A stable, arbitrary ID (menu.continueButton) decouples the key from the source text. The English copy can be tightened or corrected without invalidating translations for every other language — only the value under that key needs re-review, and the translation memory match still applies across the update.
Encoding context in the key
The same English word often needs different translations depending on where it's used — a button label and a full sentence containing the same word are not interchangeable, and many target languages make that difference in register or grammar. A key name that encodes the usage context saves a translator from having to guess, and it saves a reviewer from having to open the game just to see where a string appears:
- shop.buyButton — short, imperative, fits a fixed-width button
- shop.buyConfirmSentence — a full sentence in a confirmation dialog
- tutorial.buyHint — instructional tone, addressed to the player directly
Never reuse one key for two meanings
The single most expensive mistake in key design is using one key in two places where the intended meaning differs. English is unusually tolerant of reusing one word across contexts — Level in a menu heading and Level as in a video game 'stage' can both be the English word Level, but they are different words in many target languages. If both spots share one key, a translator can only supply one translation, and one of the two contexts is wrong by construction — not by translation error, but by a design that hid a real distinction from them.
The fix is cheap at design time and expensive after the fact: never share a key across two logically distinct UI contexts, even when the current English text happens to match. If two strings might diverge in any target language, give them two keys, even if their English values are identical today.
Rename churn and its cost
Renaming a key later is not free. Every rename breaks the link between the old translation and the new key unless the tooling explicitly carries history forward, which most simple export/import pipelines do not. A rename can look like: the old key's translations vanish, and every language shows the fallback or English text until it's retranslated — invisible in a spreadsheet review, very visible in the game.
This is why namespacing and context should be decided early, even roughly. It's far cheaper to start with menu.settings.audio.masterVolumeLabel than to migrate 500 keys away from a flat scheme after translators have already built history against the old names.