IntlPull
Guide
11 min read

Best Practices for Managing Translation Keys in 2026

Proven strategies for organizing translation keys at scale. Naming conventions, namespace architecture, and workflow patterns for maintainable i18n.

IntlPull Team
IntlPull Team
03 Feb 2026, 11:44 AM [PST]
On this page
Summary

Proven strategies for organizing translation keys at scale. Naming conventions, namespace architecture, and workflow patterns for maintainable i18n.

Quick Answer

The best practice for translation keys is hierarchical naming with feature-based namespaces: feature.component.element (e.g., checkout.cart.removeButton). Use snake_case or camelCase consistently, keep keys under 50 characters, add descriptions for context, and organize by feature rather than page. IntlPull enforces these patterns automatically through CLI validation and provides AI-powered suggestions when keys don't follow conventions.

Why Key Management Matters

Poor key management creates compound problems:

ProblemImpact
Inconsistent namingTranslators lose context
Duplicate keysWasted translation effort
No namespacesImpossible to find keys
Missing descriptionsWrong translations
Orphan keysBloated translation files

The cost is real: Teams with poor key hygiene spend 2-3x more time on translation management than teams with good conventions.

Naming Convention: The Foundation

{namespace}.{component}.{element}.{modifier}

Examples:

KeyMeaning
auth.login.submitButtonLogin page submit button
checkout.cart.emptyState.titleCart empty state title
common.errors.networkErrorShared network error
settings.profile.avatar.uploadHintAvatar upload hint text

Rules That Work

1. Use Hierarchical Structure

❌ loginSubmitButton
❌ login_submit_button
✅ auth.login.submitButton

2. Be Specific, Not Generic

❌ button.text
❌ title
✅ checkout.payment.submitButton
✅ dashboard.analytics.pageTitle

3. Avoid Positional Names

❌ sidebar.firstItem
❌ modal.button1
✅ sidebar.dashboard
✅ modal.confirmButton

4. Use Consistent Case

❌ auth.Login.Submit (mixed)
✅ auth.login.submit (camelCase throughout)
✅ auth.login.submit (or snake_case: auth.login.submit_button)

IntlPull Enforcement

IntlPull validates key naming in your CI/CD pipeline:

Terminal
1npx @intlpullhq/cli lint --strict
2
3# Output:
4# ❌ loginBtn -> auth.login.submitButton (suggested)
5# ❌ error_msg -> common.errors.generic (suggested)
6# ✅ checkout.cart.itemCount (valid)

Namespace Architecture

Organize by feature, not by page or file type:

messages/
├── auth/
│   ├── en.json
│   └── es.json
├── checkout/
│   ├── en.json
│   └── es.json
├── dashboard/
│   ├── en.json
│   └── es.json
└── common/
    ├── en.json
    └── es.json

Benefits:

  • Easy to find keys related to a feature
  • Can load namespaces on-demand (code splitting)
  • Matches how developers think about the app
  • Clear ownership for each namespace

Flat vs Nested Keys

Both approaches work; choose one and be consistent.

Flat (recommended for <1000 keys):

JSON
1{
2  "auth.login.title": "Sign In",
3  "auth.login.submitButton": "Continue",
4  "auth.login.forgotPassword": "Forgot password?"
5}

Nested (recommended for 1000+ keys):

JSON
1{
2  "auth": {
3    "login": {
4      "title": "Sign In",
5      "submitButton": "Continue",
6      "forgotPassword": "Forgot password?"
7    }
8  }
9}

IntlPull supports both formats and can convert between them automatically.

Key Descriptions: Context for Translators

Always add descriptions. Translators need context to translate accurately.

What to Include in Descriptions

IncludeExample
Where it appears"Shown in the checkout page header"
Maximum length"Max 20 characters for button width"
Variables explained"{count} is the number of items"
Tone guidance"Friendly, encouraging tone"
Screenshot linkLink to design or screenshot

In IntlPull

JSON
1{
2  "checkout.cart.itemCount": {
3    "value": "{count, plural, one {# item} other {# items}}",
4    "description": "Shows item count in cart badge. Max 15 chars. {count} is number of items.",
5    "maxLength": 15,
6    "screenshot": "https://..."
7  }
8}

IntlPull displays descriptions directly in the translation interface, ensuring translators always have context.

Handling Variables and Plurals

Variable Naming

Use meaningful variable names, not positional:

❌ "Hello {0}, you have {1} messages"
✅ "Hello {name}, you have {count} messages"

Plural Handling (ICU Format)

JSON
{
  "cart.items": "{count, plural, =0 {No items} one {# item} other {# items}}"
}

Gender and Selection

JSON
{
  "profile.greeting": "{gender, select, male {He} female {She} other {They}} updated their profile"
}

IntlPull validates ICU syntax during upload and highlights errors before they reach production.

Avoiding Common Mistakes

1. String Concatenation

JavaScript
1// ❌ Breaks in many languages (word order varies)
2t('cart.total') + ': ' + price
3
4// ✅ Use variables
5t('cart.totalWithPrice', { price })
6// "Total: {price}" or "{price}: Total" depending on language

2. Hardcoded Punctuation

JavaScript
1// ❌ Some languages use different punctuation
2t('question') + '?'
3
4// ✅ Include punctuation in the key
5t('question') // "Are you sure?"

3. Splitting Sentences

JSX
1// ❌ Impossible to translate naturally
2<span>{t('click')}</span> <a>{t('here')}</a> <span>{t('toContinue')}</span>
3
4// ✅ Use rich text support
5<Trans i18nKey="clickToContinue">
6  Click <a>here</a> to continue
7</Trans>

4. Assuming Text Length

CSS
1/* ❌ German is ~30% longer than English */
2.button { width: 100px; }
3
4/* ✅ Allow for expansion */
5.button { min-width: 100px; padding: 0 1rem; }

Workflow Patterns

Developer Workflow

  1. Create key in code with placeholder text
  2. CLI extracts keys automatically (npx @intlpullhq/cli extract)
  3. Push to IntlPull (npx @intlpullhq/cli upload)
  4. AI translates or assign to translator
  5. Pull translations (npx @intlpullhq/cli download)

Review Workflow

  1. Developer creates key with English value
  2. IntlPull AI generates translations
  3. Reviewer approves or edits in dashboard
  4. Approved translations sync to codebase

Cleanup Workflow (Quarterly)

Terminal
1# Find unused keys
2npx @intlpullhq/cli unused
3
4# Remove orphaned keys
5npx @intlpullhq/cli prune --dry-run
6npx @intlpullhq/cli prune --confirm

IntlPull tracks key usage and flags keys that haven't been referenced in your codebase.

Scaling Patterns

For 100-1,000 Keys

  • Single namespace is fine
  • Flat key structure works
  • Manual review is manageable

For 1,000-10,000 Keys

  • Feature-based namespaces required
  • Nested key structure helps
  • Automated validation essential
  • Weekly cleanup reviews

For 10,000+ Keys

  • Strict namespace governance
  • Code owners per namespace
  • Automated orphan detection
  • Monthly audit process

IntlPull scales to 100,000+ keys with namespace-level permissions, automated quality checks, and usage analytics.

Frequently Asked Questions

What is the best naming convention for translation keys?

Use hierarchical dot notation: feature.component.element (e.g., auth.login.submitButton). This provides clear context, easy searching, and natural grouping. Avoid generic names like button.text or positional names like modal.button1. Be consistent with case (camelCase or snake_case throughout).

How should I organize translation keys for a large app?

Organize by feature/domain using namespaces. Create separate files/namespaces for auth, checkout, dashboard, settings, etc., plus a common namespace for shared strings. This enables code splitting, clear ownership, and easier maintenance. IntlPull supports namespace-level permissions for large teams.

How do I handle translation key descriptions?

Add descriptions to every key that isn't self-explanatory. Include: where it appears (context), maximum character length, explanation of variables, tone guidance, and links to screenshots/designs. IntlPull displays descriptions in the translator interface and can flag keys missing descriptions.

How often should I clean up unused translation keys?

Run orphan detection monthly, full cleanup quarterly. Unused keys bloat bundles and confuse translators. IntlPull's npx @intlpullhq/cli unused command identifies keys not referenced in your codebase. Run prune with --dry-run first to preview deletions before confirming.

Should I use flat or nested translation key structures?

Use flat structure for <1,000 keys, nested for larger projects. Flat (auth.login.title: Sign In) is simpler and easier to search. Nested (auth: { login: { title: ... } }) scales better and matches code structure. IntlPull supports both and can convert between formats.

How do I prevent translation key naming inconsistencies?

Use automated validation in CI/CD. IntlPull's CLI includes a lint command that validates key naming against configurable rules. Run npx @intlpullhq/cli lint --strict in your pipeline to catch inconsistencies before they merge. The CLI also suggests corrections for malformed keys.

Summary

Key best practices:

  1. Use hierarchical naming: feature.component.element
  2. Organize by feature with namespaces
  3. Add descriptions for translator context
  4. Use ICU format for plurals and variables
  5. Validate automatically with CLI tools
  6. Clean up unused keys regularly

IntlPull enforces these patterns through CLI validation, automated suggestions, and usage tracking. Our AI even learns your project's conventions and suggests consistent key names as you work.

Ready for organized translations? Start free with IntlPull — AI-powered key suggestions included.

Tags
i18n
translation-keys
best-practices
organization
2026
IntlPull Team
IntlPull Team
Engineering

Building tools to help teams ship products globally. Follow us for more insights on localization and i18n.