Tinker AI
Read reviews

Outcome

i18n rolled out across 200 components in 1 week; translation keys are consistent; no bugs introduced

4 min read

A team I worked with needed to add internationalization to their React app. The codebase had hardcoded English strings throughout — about 200 components with various amounts of user-facing text. The rollout took one week with Cursor; estimated three weeks without.

i18n is a mechanical task with consistent patterns. AI tools handle it efficiently when set up well.

The setup

The project:

  • React 19 with Next.js
  • Existing English-only UI
  • Need to support Spanish and Portuguese for new markets
  • next-intl for i18n
  • About 200 components touching user-facing text

The plan

For each component:

  1. Extract hardcoded strings to translation keys
  2. Replace strings with t('key.path') calls
  3. Add the keys to the English translation file
  4. Mark for translator review

Plus a few cross-cutting concerns:

  • Date and number formatting
  • Pluralization
  • Direction-aware UI (for future RTL)
  • Language switcher

The .cursorrules section

# Internationalization

This project uses next-intl. Conventions:

- All user-facing strings extract to keys
- Keys use dot notation: feature.subfeature.key
- Use `useTranslations` hook in client components
- Use `getTranslations` in server components
- For pluralization, use ICU plural syntax in the key value
- For interpolation, use {paramName} placeholders

When extracting strings:
- The key path should match the component's purpose
- Group related keys together (e.g., all error messages for a feature)
- Use the existing pattern from already-internationalized components

Always update messages/en.json with the new keys after extracting.
Other locales will be filled in by translators later.

Strings to NOT extract:
- Numerical literals (use Intl.NumberFormat instead)
- Date strings (use Intl.DateTimeFormat instead)  
- API endpoint paths
- Test fixture content
- Internal logging messages

The workflow

For each component:

> /add components/ProfileEditor.tsx
> /add messages/en.json
> 
> Extract all user-facing strings from ProfileEditor to translation keys.
> Update messages/en.json. Use the convention from UserProfile.tsx (which
> is already internationalized).

Cursor produced:

  • Updated component using t('...') calls
  • New keys added to en.json
  • Consistent naming with existing keys

About 5 minutes per component including review.

For 200 components: ~17 hours of focused work over 5 days. Manual estimate was about 50 hours.

What Cursor got right

Key naming consistency. After processing 10 components, Cursor’s key names matched the existing pattern. New keys fit naturally.

Identifying what to extract. Most user-facing strings were correctly identified. Few false positives.

Pluralization handling. When a string clearly had pluralization (e.g., “1 item” vs “5 items”), Cursor used ICU plural syntax.

Hooks vs server components. Cursor correctly used useTranslations in client components and getTranslations in server components.

Avoiding non-translatable strings. Numbers, dates, API paths, log messages — Cursor knew to leave these alone (after the rules clarified).

What needed iteration

Inline JSX with HTML tags. Strings like <span>Click <a>here</a> to continue</span> are tricky to internationalize. Cursor’s first attempts sometimes broke the markup.

Conditional strings. Strings that depend on multiple state variables. Cursor sometimes flattened the conditionals badly. Manual cleanup.

Translator notes. For complex pluralization or context-dependent translations, the en.json should have comments for translators. Cursor didn’t add these by default; I’d add them.

Already-translated components. A few components had partial i18n. Cursor sometimes overwrote existing translations with new keys. I had to be careful.

A specific case

The pricing page had a complex structure:

  • Tier names that don’t translate (brand-specific)
  • Tier descriptions that do translate
  • Feature lists with mixed strings
  • Pluralized “X users” and “Y projects” labels
  • Currency-formatted prices

Cursor handled most of it. The currency formatting needed manual care — using next-intl’s number formatter rather than hardcoded $ signs.

For this kind of complex component, Cursor’s productivity gain was smaller (maybe 40% vs the typical 80%). The complex parts needed human attention regardless.

Translator handoff

After all components were internationalized, the en.json file had 1200+ keys. Translators worked from this file to produce es.json and pt.json.

Cursor wasn’t useful for the actual translation. Translators are the right tool for that.

What Cursor was useful for: organizing the keys into a structure translators could navigate. Grouping by feature, adding context comments where helpful.

Productivity numbers

  • Estimated time: 3 weeks
  • Actual time: 1 week (split between extraction and verification)
  • Cursor API cost: included in Pro subscription
  • Components processed: 200
  • Translation keys created: 1200+
  • Bugs introduced: 0

The 0 bugs is partly because i18n is verifiable — the English version should look the same after extraction. Visual regression testing caught any issues.

What I’d do differently

A few things in retrospect:

Set up visual regression testing first. I added Chromatic mid-project. Earlier setup would have caught issues sooner.

More aggressive pinning of reference components. I pinned UserProfile.tsx as the reference. Pinning 3-4 reference components covering different patterns would have improved consistency.

Translator notes earlier. I added translation context comments at the end. Adding them during extraction would have been less work.

Plan for variable text expansion. Some languages produce 30%+ longer text. UI that fits in English may overflow. I addressed this in iteration; planning for it upfront would have been better.

Worth the AI investment

For i18n specifically, AI tooling is a clear win. Mechanical work, consistent patterns, easy verification. The productivity gain is real and reliable.

For teams with i18n on the to-do list: AI tools change the calculus. What was a multi-week project becomes a multi-day project. The threshold for “we should do this” is lower.

This applies beyond i18n. Other mechanical refactors (TypeScript migration, ORM upgrades, dependency updates) have similar properties. AI tools make them tractable.

The pattern

Mechanical refactors with these properties are AI sweet spots:

  • Consistent transformation pattern
  • Easy to verify automatically
  • Touches many files mechanically
  • Domain knowledge in the rules

i18n hits all four. So do many other tasks. Identifying these tasks in your project produces a list of high-leverage AI tool applications.

Closing

i18n + Cursor was one of the smoothest AI projects I’ve done. The work was tedious but tractable; the AI was helpful; the result is a meaningfully internationalized codebase.

For teams considering i18n rollouts, this is a project worth doing now rather than deferring. The cost is much lower than it used to be. The product benefit (markets you can serve, users you can reach) is real.

If you’ve been deferring i18n: reconsider. AI tools make the project achievable in a way it wasn’t pre-AI.