All articles
i18n

Context Keys Are a UX Problem: Designing String IDs Your Translators Will Thank You For

Abstract design suggesting structure and labeling in an organized grid layout

A translator sees a key called `button.confirm` and a source string that says "Confirm." That is all they have. No indication of what is being confirmed. No indication of what page this button is on, what action it triggers, or what the user just decided. They write "Bestätigen." It is technically correct. It may or may not be contextually correct. They will not know until someone files a localization quality issue weeks later.

Key naming is the least glamorous part of i18n architecture, and it has a direct effect on translator output quality. A well-named key tells a translator where the string is, what it does, and in some cases what it should not say. A poorly named key leaves the translator working in the dark.

The UX Problem in Key Design

When engineers design i18n key naming conventions, they are almost always designing for the developer's use case: how easy is it to call this key from code? Dot notation namespacing (feature.component.element) is the developer-ergonomic choice. It maps to the component hierarchy. It prevents collisions. It groups related strings in one place in the locale file.

From the translator's perspective, `button.confirm` is nearly useless. It says: there is a button, it says something confirmatory. That is not enough to make a good translation decision in a language where word choice depends on context. German has multiple ways to say "confirm" depending on whether the user is confirming a purchase, confirming their identity, confirming a delete action, or confirming they have read a notice. The same is true in Japanese, Arabic, and most non-English languages.

The translator needs to know: confirm what? In what context? What is the consequence of pressing this button?

Key Naming Conventions That Provide Context

The key naming convention that best serves both developers and translators is a hybrid: structured namespacing for developer ergonomics, with semantic specificity at the leaf level.

Include Feature Context in the Namespace

Instead of `button.confirm`, use `checkout.confirm_order.cta` or `account.delete_account.confirm_button`. The namespace carries the feature context. A translator reading `checkout.confirm_order.cta` knows this is the primary call-to-action for confirming an order in the checkout flow. That is enough context to make the right word choice in German.

Name Actions, Not Elements

Key names that describe the UI element (`button.submit`, `link.next`, `label.error`) provide less context than key names that describe the action or meaning (`registration.submit_form`, `pagination.load_next_page`, `validation.email_format_error`).

The test: read the key name out loud. Does it tell you what is happening in the product, or does it tell you what type of HTML element is being labeled? If it only tells you the element type, it is not providing translator context.

Scope Error Messages to Their Error Type

Error message keys are the highest-leverage place for semantic specificity. A key named `error.invalid` tells translators nothing useful. A key named `checkout.payment.card_declined` tells them it is a payment error, in the checkout context, specifically for a declined card. The translation for a declined card message is different from a generic error message in languages where vocabulary differs by domain.

Avoid Reuse Keys When Contexts Differ

The temptation to reuse a key like `common.save` across multiple product contexts looks like DRY (Don't Repeat Yourself) engineering. In localization it is a context collapse. "Save" in a document editor is different from "Save" on a payment method screen is different from "Save" on a settings toggle. In English, "Save" is generic enough that one string works everywhere. In Japanese and German, the verb choice may differ by context. When you force a single key, you force a single translation, and one of those contexts will be subtly wrong.

Create context-specific keys when the action semantics differ across contexts, even if the English string is identical.

Adding Developer-Facing Context Notes

Key name alone can only carry so much context. For strings that are high-stakes (legal copy, error messages with specific consequences, strings in an unusual or non-obvious context), add a translator context note in the locale file or TMS.

In PO format, this is the translator comment field. In XLIFF, it is the `note` element. In JSON, it requires a convention -- a common one is a sibling key with a `_comment` suffix that is not exported to production locale files but is present in the source locale for translator reference.

The context note should answer: what is this string used for, what should the translator know about the context, are there any word choices to avoid or prefer. A note for `checkout.payment.card_declined` might read: "Error shown when a credit or debit card is declined during checkout. Should be sympathetic and avoid technical jargon. Do not use the word 'invalid' -- use 'declined' or local equivalent."

Variable Naming in Interpolated Strings

Interpolated strings (strings with variables: "Hello, {{name}}" or "You have {{count}} items") require special attention for translator context. Translators need to know what the variable represents and whether it can take multiple forms.

Variable names should be descriptive, not positional. `{0}` tells the translator nothing. `{user_name}` is immediately clear. `{item_count}` combined with a plural form directive tells the translator they need to handle singular/plural variation.

For plural forms specifically, use your i18n library's plural form support and document the plural categories in a translator note for languages where plural forms differ from English. Arabic has six plural forms. Russian has four. If your key is `cart.item_count` with a value "{{count}} items," the translator handling Arabic needs to know they will be providing six plural variants, not two.

A Practical Key Audit

If you want to assess how well your current key naming serves translators, run this audit against your source locale file:

  • Keys where the full key name (dot notation path) does not tell you what feature or screen the string belongs to: count and fix.
  • Keys where the value is a single common word ("Confirm", "Save", "Cancel", "Next", "Back") without feature namespace: count and evaluate for context-specific splits.
  • Keys where variable names are positional (`{0}`, `{1}`) rather than descriptive: replace all.
  • Keys for error messages that do not include the error type in the key name: rename with error-type specificity.

Key naming debt compounds with scale. Fixing 50 keys in a 500-key locale file is an afternoon of work. Fixing 500 keys in a 5,000-key file across twelve languages requires translation restarts for the affected keys. The earlier you establish the convention, the less debt accumulates.

Localization that moves with your code.

Try Tonguesage free. Connect a repo and see your first sync in minutes.

Get started free