i18n Locale Extractor
Prerequisites & Dependencies
- Node.js 18+ with npm or pnpm
- Mandatory packages:
npm i -g i18next-extract or npm i react-i18next i18next
- A codebase with hardcoded strings (JSX, HTML, or plain text)
- Optional:
npm i -D json5 for flexible JSON handling during extraction
Execution Steps
- Scan the codebase for hardcoded string literals: search for
\", '\, or template literals used in innerText, placeholder, alt, or render() calls
- Extract each unique string and assign a message ID (camelCase or UUID) to avoid collisions
- Group strings by namespace or component (e.g.,
login, header, footer) to produce a structured JSON tree
- Generate the initial translation file in the format expected by your i18n library:
- i18next:
{ "login": { "username": "Username", "password": "Password" } }
- react-i18next: same JSON structure, consumed via
<Translation>
- Replace the original hardcoded strings in the source code with
i18next.t('message.id') calls (or t('login.username') for namespaced access)
- Validate the extraction by building the app and checking that no missing keys appear in the console warnings
- Commit the translation JSON files (
en.json, es.json, etc.) and continue translating with your team
// Example: extracted en.json for a login form
{
"login": {
"title": "Sign in to your account",
"username": "Username",
"password": "Password",
"submit": "Log in",
"forgot_password": "Forgot password?"
},
"header": {
"logo": "Acme Corp",
"nav_home": "Home",
"nav_profile": "Profile"
}
}
// Example: replacing hardcoded strings in a React component
import React from 'react';
import i18next from 'i18next';
import { useTranslation } from 'react-i18next';
const LoginForm = () => {
const { t } = useTranslation();
return (
<form>
<h2>{t('login.title')}</h2>
<div>
<label>{t('login.username')}</label>
<input type="text" placeholder={t('login.username')} />
</div>
<div>
<label>{t('login.password')}</label>
<input type="password" placeholder={t('login.password')} />
</div>
<button type="submit">{t('login.submit')}</button>
<a href="/forgot">{t('login.forgot_password')}</a>
</form>
);
};
export default LoginForm;
// Initialization (usually in entry point)
i18next.init({
lng: 'en',
resources: {
en: { translation: require('./locales/en.json') },
// ... other locales
},
fallbackLng: 'en',
});
# Extract strings using i18next-extract CLI
i18next-extract -p i18next-extract-defaults.js
# Generate missing locale files
cpLocales/en.json locales/es.json
1---2name: i18n-locale-extractor3description: Extract hardcoded UI text strings into structured internationalization JSON translation files.4metadata:5 source: skills/i18n-locale-extractor/i18n-locale-extractor.md6---78# i18n Locale Extractor910## Prerequisites & Dependencies11- Node.js 18+ with npm or pnpm12- Mandatory packages: `npm i -g i18next-extract` or `npm i react-i18next i18next`13- A codebase with hardcoded strings (JSX, HTML, or plain text)14- Optional: `npm i -D json5` for flexible JSON handling during extraction1516## Execution Steps171. Scan the codebase for hardcoded string literals: search for `\"`, `'\`, or template literals used in `innerText`, `placeholder`, `alt`, or `render()` calls182. Extract each unique string and assign a message ID (camelCase or UUID) to avoid collisions193. Group strings by namespace or component (e.g., `login`, `header`, `footer`) to produce a structured JSON tree204. Generate the initial translation file in the format expected by your i18n library:21 - **i18next**: `{ "login": { "username": "Username", "password": "Password" } }`22 - **react-i18next**: same JSON structure, consumed via `<Translation>`235. Replace the original hardcoded strings in the source code with `i18next.t('message.id')` calls (or `t('login.username')` for namespaced access)246. Validate the extraction by building the app and checking that no missing keys appear in the console warnings257. Commit the translation JSON files (`en.json`, `es.json`, etc.) and continue translating with your team2627```json28// Example: extracted en.json for a login form29{30 "login": {31 "title": "Sign in to your account",32 "username": "Username",33 "password": "Password",34 "submit": "Log in",35 "forgot_password": "Forgot password?"36 },37 "header": {38 "logo": "Acme Corp",39 "nav_home": "Home",40 "nav_profile": "Profile"41 }42}43```4445```javascript46// Example: replacing hardcoded strings in a React component47import React from 'react';48import i18next from 'i18next';49import { useTranslation } from 'react-i18next';5051const LoginForm = () => {52 const { t } = useTranslation();5354 return (55 <form>56 <h2>{t('login.title')}</h2>57 <div>58 <label>{t('login.username')}</label>59 <input type="text" placeholder={t('login.username')} />60 </div>61 <div>62 <label>{t('login.password')}</label>63 <input type="password" placeholder={t('login.password')} />64 </div>65 <button type="submit">{t('login.submit')}</button>66 <a href="/forgot">{t('login.forgot_password')}</a>67 </form>68 );69};7071export default LoginForm;7273// Initialization (usually in entry point)74i18next.init({75 lng: 'en',76 resources: {77 en: { translation: require('./locales/en.json') },78 // ... other locales79 },80 fallbackLng: 'en',81});82```8384```bash85# Extract strings using i18next-extract CLI86i18next-extract -p i18next-extract-defaults.js8788# Generate missing locale files89cpLocales/en.json locales/es.json90```