Extracting i18n Keys with AI
Converting an existing React app to support multiple languages is sometimes a tedious process of finding hardcoded strings and replacing them with translation keys.
Lingo.dev CLI works seamlessly with AI-powered IDEs like Cursor, GitHub Copilot, and similar tools to automate the extraction of translatable content from your React components.
The concept explained below can be used for any tech stack, but for simplicity and to demonstrate the idea, we'll use a hello world React app as an example.
Prerequisites
Before extracting keys, set up basic internationalization in your React app. For complete setup instructions, see the react-intl documentation.
After following the internationalization setup for your tech stack, your project should have:
- Ability to switch between languages dynamically in the app
- Basic project structure for organizing translation files
Setup Process
Install and configure Lingo.dev CLI:
npx lingo.dev@latest init
Create empty source file:
mkdir -p src/locales
echo '{}' > src/locales/en.json
Configure i18n.json:
{
"locale": {
"source": "en",
"targets": ["es", "fr", "de"]
},
"buckets": {
"json": {
"include": ["src/locales/[locale].json"]
}
}
}
Extracting Keys with AI
Select your React component and use your AI IDE to extract hardcoded strings:
Before extraction:
function WelcomeCard() {
return (
<div className="card">
<h2>Welcome to our platform</h2>
<p>Start your journey with us today</p>
<button>Get started</button>
</div>
);
}
Requirements for extraction:
- Replace hardcoded strings with react-intl hooks and components
- Use ICU formatting for variables and plurals
- Structure keys hierarchically by component organization
- Add all keys to the source JSON file
- Maintain consistent naming conventions
AI prompt:
Extract all hardcoded strings from React components and:
1. Replace with react-intl:
- Use useIntl hook for dynamic strings
- Use FormattedMessage for static text
- Add ICU formatting for variables ({name}) and plurals ({count})
2. Structure translation keys:
- Group by component hierarchy (components.*, pages.*)
- Use descriptive, nested keys (header.nav.home)
- Match component structure in JSON
3. Update locales:
- Add all keys to src/locales/en.json
- Maintain consistent naming across app
After AI extraction:
import { useIntl } from "react-intl";
function WelcomeCard() {
const intl = useIntl();
return (
<div className="card">
<h2>{intl.formatMessage({ id: "welcome.title" })}</h2>
<p>{intl.formatMessage({ id: "welcome.description" })}</p>
<button>{intl.formatMessage({ id: "welcome.getStarted" })}</button>
</div>
);
}
Generated en.json:
{
"welcome.title": "Welcome to our platform",
"welcome.description": "Start your journey with us today",
"welcome.getStarted": "Get started"
}
Batch Processing
For multiple components, select all files and use the same comprehensive prompt. AI IDEs like Cursor, GitHub Copilot, and others can process multiple files simultaneously, maintaining consistent key naming across your application.
Translation Generation
Once your AI IDE extracts the keys, generate translations:
npx lingo.dev@latest i18n
This creates translated versions of your source file:
src/locales/
en.json (source with extracted keys)
es.json (Spanish translations)
fr.json (French translations)
de.json (German translations)
Validation
After extraction, verify your setup:
Check translation coverage:
npx lingo.dev@latest i18n --frozen
This command fails if any translations are missing, ensuring complete coverage.
Test with different locales:
// Switch locale in your app to verify translations work
<IntlProvider locale="es" messages={spanishMessages}>
<WelcomeCard />
</IntlProvider>