Dev.to AI 🤖 Ai 👁 0 📖 3 min read

Give the agent the i18n message IDs, not hardcoded English to “fill in later”

The modal works. The CTA says "Save changes". The agent left a comment: // TODO: i18n. There is already a saveChanges id in en.json, and the German file will now drift for a week because nobody wired it. I’ve started tr

The modal works. The CTA says "Save changes". The agent left a comment: // TODO: i18n. There is already a saveChanges id in en.json, and the German file will now drift for a week because nobody wired it.

I’ve started treating hardcoded user-facing English in a localized app as a defect in the PR, not a follow-up. Agents default to literals because that’s the fastest way to make the screenshot look done.

Why “fill in later” never gets filled in

  • The TODO is in a file reviewers skim
  • The string is almost, but not quite, the existing catalog entry (Save vs Save changes)
  • Plurals, ICU, or interpolation ({count} items selected) get faked with ' + n + '
  • A second screen copies the literal, and now you have two source-of-truth problems

If the product is already on react-intl, next-intl, vue-i18n, or i18next, the catalog is the contract. The agent should work inside it.

What to hand the agent

Don’t say “use i18n.” Paste the relevant slice:

{
  "checkout.payCta": "Pay now",
  "checkout.payCtaPending": "Paying…",
  "checkout.itemsSelected": "{count, plural, one {# item selected} other {# items selected}}"
}

And the hook you actually use:

Use t('checkout.payCta') / the existing useTranslations('checkout')
pattern. Do not add hardcoded English for user-visible strings.
If you need a new message, add the id to the English catalog in
this PR with the same naming prefix, and use ICU for counts.
Do not invent a second i18n helper.

If you have a typings file or an id enum, paste that instead of the whole locale. The id list is more useful than a style-guide paragraph.

A simple policy

  • User-visible strings in a localized surface go through the catalog in the same PR
  • Prefer an existing id over a near-duplicate new one
  • New ids follow the existing namespace (screen.elementState), not string1
  • Interpolation and plurals use the project’s ICU / sprintf style, not string concat
  • Aria labels and error text count as user-visible
  • Developer-only log lines can stay as literals unless you already localize those too

Extract-and-upload pipelines (some TMS setups) can wait for a bot to harvest English — but only if that’s already how your repo works. Don’t assume the agent knows that. If harvest is the rule, say so; if the English file is edited in the PR, say that instead.

Review checklist

  1. git diff for quotes in TSX/JSX/Vue templates — new literals in UI paths should be rare
  2. New ids should appear in the catalog, not only in the component
  3. Check plural / interpolation forms against an existing example in the same namespace
  4. Search the catalog for near-duplicate English before accepting a new key

A lint rule (@formatjs/no-literal-string-in-jsx, eslint-plugin-i18next, or your equivalent) is the durable version of this review. Until that’s on, the prompt and the diff still matter.

Reject / send back

Reject

  • "Save changes" in the component with TODO: i18n
  • A new helper like const t = (s) => s “for now”
  • Concatenated sentences that can’t be translated ('Hello, ' + name)
  • A new id that duplicates checkout.payCta with slightly different wording

Accept

  • Existing ids, used the way neighboring components already use them
  • New catalog entries in the same PR, named consistently, with ICU where counts exist
  • A short PR note when a string is intentionally developer-only

Tiny habit

When you ask an agent to add a button or an empty state, paste the message ids (or the namespace) up front. Don’t ask it to “write the copy” in English and promise a localization pass later. Later is how catalogs rot.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.