6月1日 02:21
How to manage i18next translation resources and workflows?
Translation Management Platform Integration
i18next-locize-backend
javascriptimport Locize from 'i18next-locize-backend'; i18next .use(Locize) .init({ backend: { projectId: 'your-project-id', apiKey: 'your-api-key', referenceLng: 'en', version: 'latest' } });
Crowdin Integration
javascript// load from Crowdin using i18next-http-backend i18next .use(HttpBackend) .init({ backend: { loadPath: 'https://cdn.crowdin.com/api/v2/projects/{{projectId}}/translations/{{lng}}/{{ns}}?apiKey={{apiKey}}', queryStringParams: { projectId: 'your-project-id', apiKey: 'your-api-key' } } });
Automatic Translation Extraction
Using i18next-scanner
bashnpm install --save-dev i18next-scanner
javascript// gulpfile.js const gulp = require('gulp'); const scanner = require('i18next-scanner'); gulp.task('i18next', function() { return gulp.src(['src/**/*.{js,jsx,ts,tsx}']) .pipe(scanner({ lngs: ['en', 'zh', 'fr'], resource: { loadPath: 'locales/{{lng}}/{{ns}}.json', savePath: 'locales/{{lng}}/{{ns}}.json' }, keySeparator: '.', nsSeparator: ':', defaultValue: '__TRANSLATION__' })) .pipe(gulp.dest('locales')); });
Using Babel Plugin
javascript// .babelrc { "plugins": [ ["i18next-extract", { "locales": ["en", "zh"], "outputPath": "locales/{{locale}}/{{ns}}.json", "keyAsDefaultValue": true }] ] }
Translation Workflow
Development Process
- Extract Translation Keys: Use scanning tools to extract translation keys from code
- Add Translations: Add or update translations in translation files
- Commit Code: Commit translation files to version control
- Send for Translation: Send content needing translation to translation team
- Merge Translations: Merge translated content back into codebase
Automated Workflow
javascript// CI/CD integration example const { execSync } = require('child_process'); // extract translations execSync('npm run extract:translations'); // check for new translation keys const newKeys = checkNewTranslationKeys(); if (newKeys.length > 0) { console.log('New translation keys found:', newKeys); // send notification or create issue notifyTranslationTeam(newKeys); } // run tests execSync('npm test');
Translation Quality Assurance
Translation Validation
javascriptfunction validateTranslations(translations) { const errors = []; Object.keys(translations).forEach(lang => { const langTranslations = translations[lang]; Object.keys(langTranslations).forEach(key => { const translation = langTranslations[key]; // check for unclosed interpolation placeholders if (translation.includes('{{') && !translation.includes('}}')) { errors.push(`${lang}.${key}: Unclosed interpolation placeholder`); } // check for HTML tags if (/<[^>]*>/g.test(translation)) { errors.push(`${lang}.${key}: Contains HTML tags`); } // check length if (translation.length > 500) { errors.push(`${lang}.${key}: Translation too long`); } }); }); return errors; }
Translation Coverage Check
javascriptfunction checkTranslationCoverage(translations) { const referenceLang = 'en'; const referenceKeys = Object.keys(translations[referenceLang]); const coverage = {}; Object.keys(translations).forEach(lang => { if (lang === referenceLang) return; const langKeys = Object.keys(translations[lang]); const missingKeys = referenceKeys.filter(key => !langKeys.includes(key)); coverage[lang] = { total: referenceKeys.length, translated: langKeys.length, missing: missingKeys, percentage: (langKeys.length / referenceKeys.length) * 100 }; }); return coverage; }
Translation Update Strategy
Incremental Updates
javascriptasync function updateTranslations(newTranslations) { const currentTranslations = await loadCurrentTranslations(); Object.keys(newTranslations).forEach(lang => { if (!currentTranslations[lang]) { currentTranslations[lang] = {}; } Object.assign(currentTranslations[lang], newTranslations[lang]); }); await saveTranslations(currentTranslations); }
Version Control
javascript// track translation changes using Git const { execSync } = require('child_process'); function commitTranslations(message) { execSync('git add locales/'); execSync(`git commit -m "${message}"`); execSync('git tag translations-v' + Date.now()); }
Translation Platform Integration
Locize
javascriptimport locize from 'locize'; import locizeBackend from 'i18next-locize-backend'; const locizeOptions = { projectId: 'your-project-id', apiKey: 'your-api-key', referenceLng: 'en', version: 'latest' }; i18next .use(locizeBackend) .use(locize.plugin()) .init({ backend: locizeOptions, locizeLastUsed: locizeOptions, saveMissing: true, debug: true });
PhraseApp
javascriptimport PhraseBackend from 'i18next-phraseapp-backend'; i18next .use(PhraseBackend) .init({ backend: { projectId: 'your-project-id', apiKey: 'your-api-key', version: 'latest' } });
Best Practices
- Automated Extraction: Use tools to automatically extract translation keys
- Version Control: Include translation files in version control
- Continuous Integration: Validate translation quality in CI/CD
- Translation Management: Use professional translation management platforms
- Quality Assurance: Implement translation validation and coverage checks
- Team Collaboration: Establish clear translation workflows
- Documentation Maintenance: Keep translation documentation updated