You know the drill: find every "Save", "Loading...", "User not found". Wrap in t(). Invent keys. Manage locale JSON.
i18.dev detects hardcoded strings, suggests semantic keys, auto-translates to 100+ languages, and refactors your code.
You focus on features, not i18n plumbing.
Read the docsAutomatically detect and extract translatable strings from your codebase using advanced AI.
Generate semantic, organized translation keys automatically.
Context-aware translations powered by advanced AI.
Track changes, create versions, and roll back when needed.
Invite team members, manage permissions, and work together.
Full-featured CLI and REST API for programmatic access.
Choose your i18n library and copy a ready-to-use integration setup.
Internationalization for Next.js that gets out of your way
Copy this prompt and paste it into Cursor AI for quick integration setup
npm install next-intlyour-project/ ├── messages/ │ ├── en.json │ ├── es.json │ └── fr.json ├── scripts/ │ └── pull-translations.js ├── next.config.js └── i18n.ts
I18DEV_API_KEY=your-project-api-key
I18DEV_BASE_URL=https://i18-dev-sass.vercel.app/
I18DEV_MESSAGES_PATH=messagesCreate scripts/pull-translations.js
// pull-translations.js - For next-intl
const fs = require('fs');
const path = require('path');
const https = require('https');
const BASE_URL = process.env.I18DEV_BASE_URL || 'https://i18.dev';
const API_KEY = process.env.I18DEV_API_KEY || 'your-project-api-key';
const MESSAGES_PATH = process.env.I18DEV_MESSAGES_PATH || 'messages';
const API_URL = `${BASE_URL}/api/download-translations?projectId=${API_KEY}`;
const MESSAGES_DIR = path.join(__dirname, '..', MESSAGES_PATH);
async function fetchTranslations() {
return new Promise((resolve, reject) => {
const req = https.get(API_URL, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (error) {
reject(new Error(`Failed to parse JSON: ${error.message}`));
}
});
});
req.on('error', reject);
req.setTimeout(10000, () => { req.destroy(); reject(new Error('Timeout')); });
});
}
function ensureDir(dirPath) {
if (!fs.existsSync(dirPath)) fs.mkdirSync(dirPath, { recursive: true });
}
function updateMessageFiles(translations) {
ensureDir(MESSAGES_DIR);
Object.entries(translations).forEach(([locale, content]) => {
const filePath = path.join(MESSAGES_DIR, `${locale}.json`);
fs.writeFileSync(filePath, JSON.stringify(content, null, 2));
console.log(`✅ Updated ${locale}.json`);
});
}
async function main() {
console.log('🔄 Fetching translations...');
const translations = await fetchTranslations();
console.log('📝 Updating files...');
updateMessageFiles(translations);
console.log('✨ Done!');
}
main().catch(console.error);// i18n.ts
import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server';
const locales = ['en', 'es', 'fr'];
export default getRequestConfig(async ({locale}) => {
if (!locales.includes(locale as any)) notFound();
return {
messages: (await import(`./messages/${locale}.json`)).default
};
});// In your component
import {useTranslations} from 'next-intl';
export default function MyComponent() {
const t = useTranslations('common');
return <h1>{t('hello')}</h1>;
}Add the script to package.json and run:
npm run pullyarn pullpnpm pullFree for personal projects. No credit card required.