Skip to content

PluginTranslations ​

Собирает сообщения из исходных файлов и создает JSON-файл с используемыми переводами. Плагин хранит defaultValue, добавляет новые ключи, удаляет устаревшие и дозаполняет отсутствующие переводы через функцию translate.

Уже существующие переводы сохраняются, а defaultValue обновляется при изменении исходного текста.

translate вызывается параллельно (до 5 потоков) и только для отсутствующих переводов.

ts
entries: Array<string>

Массив с glob-паттернами поиска файлов внутри rootDir

ts
targetFile: string

Абсолютный путь к JSON-файлу, в который будут сохраняться переводы

ts
languages: Array<string>

Массив кодов языков, например ['en', 'ru', 'de']

ts
baseLanguage: string

Базовый язык исходных текстов. Его текст хранится в defaultValue; отдельный перевод для этого языка автоматически не создаётся. translate вызывается только для остальных языков

ts
parseMessages: (filePath: string) => Array<{ 
  name: string; 
  defaultValue: string 
}>

Функция для извлечения сообщений из файла

ts
translate: (params: { 
  to: string; 
  text: string 
}) => Promise<string>

Асинхронная функция для перевода текста с baseLanguage на указанный в languages язык

ts
getKey?: (params: { 
  rootDir: string; 
  name: string 
}) => string

Функция для генерации уникального ключа перевода. По умолчанию — путь файла с сообщениями относительно rootDir

Пример: сообщения рядом с компонентами

Все messages.ts в проекте собираются в единый JSON. При удалении сообщения или целого файла устаревшие ключи удаляются автоматически.
В данной схеме только один язык, поэтому в итоговом JSON только defaultValue — это удобно для передачи во внешнюю систему переводов

ts
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
USER: features/orders/OrderStatusBadge/messages.ts создан с содержимым:
ts
import { createMessages } from 'translations/createMessages';

export const messages = createMessages('features/orders/OrderStatusBadge', {
  draft: 'Draft',
  paid: 'Paid',
});
ARFA Generator выводит логи:
txt
[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
ARFA Generator сгенерировал файлы:
json
{
  "features/orders/OrderStatusBadge/draft": {
    "defaultValue": "Draft"
  },
  "features/orders/OrderStatusBadge/paid": {
    "defaultValue": "Paid"
  }
}

Пример: синхронизация и перевод сообщений

В этом примере сообщения читаются из JSON. Плагин заполняет отсутствующие переводы через translate, сохраняет существующие и обновляет defaultValue из исходников.
Пример подходит для нескольких языков без внешней системы переводов, когда переводы делаются в полуручном режиме

ts
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
USER: features/orders/messages.json создан с содержимым:
json
{
  "title": "Orders",
  "empty": "No orders"
}
ARFA Generator выводит логи:
txt
[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
ARFA Generator сгенерировал файлы:
json
{
  "features/orders/empty": {
    "defaultValue": "No orders",
    "ru": "[ru] No orders"
  },
  "features/orders/title": {
    "defaultValue": "Orders",
    "ru": "[ru] Orders"
  }
}

MIT License