---
name: translation-key-naming
source: https://app.decimal.ai/s/translation-key-naming@1/SKILL.md
source_sha256: 3e420ebf2615
---

# Translation Key Naming

An i18n key is an identifier, not a copy of the text. Name it for **where the string lives and what role it plays** — `settings.notifications.emailToggle` — so the same key keeps working after the visible words change and so every key can be found by static tooling.

Asked to add a key for a UI string, the base model tends to (1) derive the key from the English value, (2) drop every key at the top level with no namespace, and (3) build keys at runtime by concatenating a variable. All three make the catalog brittle. This skill applies the opposite discipline.

## The rules

1. **Name by feature and context, never from the English value.** The key encodes the string's location and role, not its words. When the copy is reworded, the key stays put.
   - Good: `checkout.button.submit`, `profile.avatar.uploadLabel`
   - Bad: `clickHereToPay`, `submitYourOrderNow` (these are the English text in disguise — reword "Submit" to "Place order" and the key is now a lie)

2. **Namespace hierarchically by feature/screen/component.** Group keys under a path so different screens can each have their own `title`, `save`, or `error` without colliding.
   - Good: `billing.card.saveButton` and `profile.form.saveButton` — two distinct keys
   - Bad: one flat `save` at the root reused by both screens — a collision waiting to happen

3. **Use only static, literal keys — never concatenate a key at runtime.** A key assembled from a variable (`t('errors.' + code)`, `t(\`row.${i}.label\`)`, or anything built from user input) cannot be discovered by extractors, unused-key linters, or missing-translation checks, so a locale can silently ship with a hole.
   - Good: an explicit map — `const KEY = { E_TIMEOUT: 'errors.timeout', E_AUTH: 'errors.auth' }; t(KEY[code])`
   - Bad: `t('errors.' + code)`

4. **Name by the role/slot, so the key survives a copy change.** Ask "if the words change, does this key still make sense?" If renaming the key would be required after an edit to the text, the key was named after the text.
   - Good: `dialog.delete.confirmButton` (survives "Delete" → "Yes, remove it")
   - Bad: `deleteText`, `areYouSurePrompt`

5. **Share a key only for a genuinely identical, generic string.** Truly universal words (`common.cancel`, `common.save`) can live in a shared namespace and be reused. But do not force one key to serve two contexts whose copy can diverge — the moment one side is reworded, split them into separate keys.

## When to use

Naming a new key, reviewing key names in a diff, or reorganizing a locale catalog.

## When not to use

Translating the string values, choosing plural categories (see cldr-plural-categories), enforcing a term glossary (see translate-with-glossary), or picking an i18n framework.
