PluginTranslations
Собирает сообщения из исходных файлов и создает JSON-файл с используемыми переводами. Плагин хранит defaultValue, добавляет новые ключи, удаляет устаревшие и дозаполняет отсутствующие переводы через функцию translate.
Уже существующие переводы сохраняются, а defaultValue обновляется при изменении исходного текста.
translate вызывается параллельно (до 5 потоков) и только для отсутствующих переводов.
ts | Массив с glob-паттернами поиска файлов внутри |
ts | Абсолютный путь к JSON-файлу, в который будут сохраняться переводы |
ts | Массив кодов языков, например |
ts | Базовый язык исходных текстов. Его текст хранится в |
ts | Функция для извлечения сообщений из файла |
ts | Асинхронная функция для перевода текста с |
ts | Функция для генерации уникального ключа перевода. По умолчанию — путь файла с сообщениями относительно |
Пример: сообщения рядом с компонентами
Все messages.ts в проекте собираются в единый JSON. При удалении сообщения или целого файла устаревшие ключи удаляются автоматически.
В данной схеме только один язык, поэтому в итоговом JSON только defaultValue — это удобно для передачи во внешнюю систему переводов
new PluginTranslations([
{
entries: ['**/messages.ts'],
targetFile: path.resolve(rootDir, 'translations/usedTranslations.json'),
languages: ['en'],
baseLanguage: 'en',
getKey({ name }) {
return name;
},
parseMessages(filePath) {
const source = fs.readFileSync(filePath, 'utf8');
const content = source.replace(/^[\s\S]*?export\s+const\s+messages\s*=\s*/, 'return ');
if (content === source) throw new Error(`Messages export not found in: ${filePath}`);
// imported from the library
type TypeMessage = { name: string; defaultValue: string };
function createMessages(scope: string, messages: Record<string, string>) {
const result: Record<string, TypeMessage> = {};
for (const key in messages) {
result[key] = { name: `${scope}/${key}`, defaultValue: messages[key] };
}
return result;
}
const messages = new Function('createMessages', content)(createMessages) as Record<string, TypeMessage>;
return Object.values(messages);
},
async translate() {
return '';
},
},
]),
Запустить Sandbox
import { createMessages } from 'translations/createMessages';
export const messages = createMessages('features/orders/OrderStatusBadge', {
draft: 'Draft',
paid: 'Paid',
});
[ARFA-GEN] [write] translations/usedTranslations.json
[ARFA-GEN] [translations] new key: features/orders/OrderStatusBadge/draft
[ARFA-GEN] [translations] new key: features/orders/OrderStatusBadge/paid
[ARFA-GEN] finished in 0ms
{
"features/orders/OrderStatusBadge/draft": {
"defaultValue": "Draft"
},
"features/orders/OrderStatusBadge/paid": {
"defaultValue": "Paid"
}
}
Пример: синхронизация и перевод сообщений
В этом примере сообщения читаются из JSON. Плагин заполняет отсутствующие переводы через translate, сохраняет существующие и обновляет defaultValue из исходников.
Пример подходит для нескольких языков без внешней системы переводов, когда переводы делаются в полуручном режиме
new PluginTranslations([
{
entries: ['features/**/messages.json'],
targetFile: path.resolve(rootDir, 'translations/translations.json'),
languages: ['en', 'ru'],
baseLanguage: 'en',
parseMessages(filePath) {
const messages: Record<string, string> = JSON.parse(fs.readFileSync(filePath, 'utf8'));
return Object.entries(messages).map(([name, defaultValue]) => ({
name: path.resolve(path.dirname(filePath), name),
defaultValue,
}));
},
async translate({ to, text }) {
return `[${to}] ${text}`;
},
},
]),
Запустить Sandbox
{
"title": "Orders",
"empty": "No orders"
}
[ARFA-GEN] [write] translations/translations.json
[ARFA-GEN] [translations] new key: features/orders/title
[ARFA-GEN] [translations] new key: features/orders/empty
[ARFA-GEN] [translations] features/orders/title: translated to [ru]: "[ru] Orders"
[ARFA-GEN] [translations] features/orders/empty: translated to [ru]: "[ru] No orders"
[ARFA-GEN] finished in 0ms
{
"features/orders/empty": {
"defaultValue": "No orders",
"ru": "[ru] No orders"
},
"features/orders/title": {
"defaultValue": "Orders",
"ru": "[ru] Orders"
}
}