Автор:
    Дата створення:2026-09-02Останнє оновлення:2026-09-02

    Як виявляти відсутні переклади раніше, ніж це зроблять ваші користувачі

    Відсутній переклад майже ніколи не викликає виняткових ситуацій у додатку. Залежно від вашої конфігурації, він або покаже англійський текст користувачеві в Японії, або виведе checkout.summary.total прямо на робочій сторінці в продакшені. Обидва випадки потрапляють у реліз, проходять код-рев'ю і виявляються клієнтом, а не вами.

    Зміст

    Це працює незалежно від бібліотеки, яку ви використовуєте

    Жодна порада тут не прив'язана до одного конкретного стеку. Описані нижче рівні виявлення функціонують однаково в i18next, react-i18next, next-intl, react-intl, vue-i18n, next-translate або Lingui, оскільки всі вони розв'язують ключі за однаковим принципом і зазнають збоїв аналогічно.

    Інструменти також портативні. Якщо ваші тексти зараз зберігаються в каталогах JSON, плагін Sync JSON підключає Intlayer до цих файлів, надаючи команди аудиту, заповнення та тестування без переміщення контенту і без зміни жодного імпорту:

    intlayer.config.ts
    import { syncJSON } from "@intlayer/sync-json-plugin";
    
    const config = {
      plugins: [
        syncJSON({
          source: ({ key, locale }) => `./locales/${locale}/${key}.json`,
          format: "i18next", // або "icu" для next-intl / react-intl
        }),
      ],
    };
    
    export default config;
    

    Якщо ви бажаєте зберегти runtime API незмінним, адаптери сумісності створюють аліаси для useTranslation, $t тощо на рівні збирача пакетів. У будь-якому разі сприймайте наведені нижче команди як конкретну реалізацію ідеї, а не як непохитну вимогу.

    Чому прогалини залишаються непомітними

    Кожна бібліотека i18n розв'язує ключ через один і той самий ланцюжок: знайти в активній локалі, відкотитися до типової локалі (fallback), а якщо це не вдалося — повернути сам строковий ключ. Саме цей останній крок створює проблему. Немає помилки, немає попередження на продакшені та немає провалених тестів, оскільки жодна ланка пайплайну не вважає відсутність перекладу аномалією.

    Фолбек лише погіршує ситуацію замість того, щоб допомагати. Сторінка, яка мовчки відрендерилася англійською мовою, виглядає цілком нормально для англомовного розробника та для будь-якої автоматизованої перевірки. Проблема помітна лише тій людині, яка не розуміє цього тексту.

    Тому питання полягає не в тому, "як обробляти відсутні переклади під час виконання". А в тому, "як зробити злиття коду з відсутнім перекладом принципово неможливим".

    Чотири рівні, на яких їх можна перехопити

    Кожен рівень ловить те, що інші пропускають. Доцільно поєднувати декілька рівнів.

    Рівень Що знаходить Що пропускає
    Типи Ключі, яких взагалі не існує Ключ існує, але не має значення в ja
    Лінтер Захардкоджені рядки, які ніколи не виносилися Ключі, відсутні в конкретному каталозі
    Аудит Покриття локалями кожного оголошеного ключа Текст, який взагалі ніколи не робили доступним до перекладу
    Тести рендеру Ключі, які розв'язуються, але рендеряться хибно Все, що не покрите тестами

    Найчастіша прогалина в командах — це третій рядок: розробники знають, що їхні ключі коректні за типами, але жоден інструмент не перевіряє наявність реального значення в кожній із вісімнадцяти мов.

    Рівень 1: зробіть ключ типом, а не звичайним рядком

    t("checkout.summry.total") — це одрук, який без проблем компілюється. Якщо ваші ключі — прості рядки, кожне перейменування несе ризик у продакшені, а кожне видалення залишає ключі-сироти.

    Типізовані ключі перетворюють це на помилку збірки. react-i18next підтримує це через declaration merging, next-intl виводить типи зі структури повідомлень, Lingui генерує ідентифікатори з тексту джерела, а Intlayer генерує суворі типи з файлів оголошення контенту. Усі варіанти працюють; різниця полягає лише в обсязі налаштувань.

    Цей рівень є необхідним, але недостатнім. Типи описують структуру вашого типового каталогу. Вони нічого не кажуть про те, чи є в корейській локалі значення для цього ключа.

    Рівень 2: лінтинг рядків, які так і не стали ключами

    Переклад, який ви не можете знайти, часто є тим, який ніколи не виносився в словники. Захардкоджений напис у компоненті невидимий для будь-якого аудиту каталогів, тому що для інструментів цього рядка просто не існує.

    Плагін ESLint для Intlayer вирішує це правилом no-raw-text, доповненим правилом no-unused-content для зворотної ситуації: контент оголошено, але він більше ніде не використовується.

    eslint.config.mjs
    import intlayer from "@intlayer/eslint-plugin";
    
    export default [
      intlayer.configs.recommended,
      {
        rules: {
          "@intlayer/no-raw-text": "error",
          "@intlayer/no-unused-content": "warn",
        },
      },
    ];
    

    no-unused-content оберігає каталоги від безкінечного розростання. Мертві ключі не ламають роботу програми, але необґрунтовано збільшують рахунки від бюро перекладів. Повний перелік правил наведено в документації до плагіна ESLint.

    Рівень 3: аудит покриття локалей

    Це той самий рівень, який відповідає на головне запитання. Intlayer постачає його як команду CLI:

    bash
    npx intlayer content test
    

    Вона зчитує налаштовані локалі та оголошені словники, а потім детально звітує, яким ключам бракує яких мов і в якому файлі.

    Важлива деталь перед тим, як вбудовувати команду в пайплайни: CLI виводить звіт, але завжди завершується з кодом 0. Якщо ви додасте її в надії зламати збірку, ви отримаєте зелений білд із довгим списком у логах, який ніхто не прочитає. Для зупинки збірки використовуйте програмний API, описаний нижче.

    Рівень 4: перевірка через assertions у тестовому наборі

    listMissingTranslations() повертає той самий аудит у вигляді об'єкта даних, що ідеально підходить для створення блокувального бар'єра збірки (build gate).

    i18n.test.ts
    /* @vitest-environment node */
    import { listMissingTranslations } from "intlayer/cli";
    import { describe, expect, it } from "vitest";
    
    describe("translations", () => {
      it("has no missing required locales", async () => {
        const result = await listMissingTranslations();
    
        if (result.missingRequiredLocales.length > 0) {
          console.log(result.missingTranslations);
        }
    
        expect(result.missingRequiredLocales).toHaveLength(0);
      });
    });
    

    Повертаються три поля з чітким розмежуванням:

    • missingTranslations: за кожним ключем вказано, яких саме мов бракує та з якого файлу. Це друкується у разі провалу тесту.
    • missingLocales: об'єднання всіх відсутніх мов за всіма ключами.
    • missingRequiredLocales: обмежено лише параметром requiredLocales у вашій конфігурації (або всіма локалями, якщо параметр не було задано).

    requiredLocales робить перевірку життєздатною

    Підтримка вісімнадцяти мов не означає, що всі вісімнадцять мають бути готові на 100% для виконання деплою. Більшість команд поділяють мови на критичний рівень, що блокує реліз, та рівень, який доповнюється поступово.

    intlayer.config.ts
    import { Locales, type IntlayerConfig } from "intlayer";
    
    const config: IntlayerConfig = {
      internationalization: {
        locales: [
          Locales.ENGLISH,
          Locales.FRENCH,
          Locales.JAPANESE,
          Locales.POLISH,
        ],
        requiredLocales: [Locales.ENGLISH, Locales.FRENCH],
        defaultLocale: Locales.ENGLISH,
      },
    };
    
    export default config;
    

    Без requiredLocales кожна оголошена локаль стає суворо обов'язковою, і збірка лишатиметься червоною, доки не з'явиться останній переклад. Це найчастіше призводить до того, що команди повністю вимикають цю перевірку.

    Пошук прогалин, які вже потрапили в продакшен

    Описані рівні запобігають появі нових прогалин. Для додатка, який уже працює на продакшені, допомагають два підходи.

    Псевдолокалізація. Запустіть тестову локаль, де кожен рядок трансформується, наприклад [!!! Ĉĥéçķöũţ !!!]. Усе, що продовжує відображатися звичайною англійською, захардкоджене в коді. Це дозволяє за десять хвилин виявити те, чого аудит каталогів принципово не здатний помітити.

    Краулінг власного сайту. Якщо у вас локалізовані URL, завантажте вибірку сторінок для кожної мови та виконайте пошук рядків типової мови в HTML. Сторінка за адресою /ja/, що містить фразу "Add to cart", вказує або на відсутній переклад, або на неочікуваний фолбек.

    bash
    curl -s https://example.com/ja/checkout | grep -c "Add to cart"
    

    Заповнення прогалин

    Коли ви знаєте, чого саме не вистачає, команда intlayer fill заповнює порожні поля, а опція autoFill може генерувати файли для кожної локалі безпосередньо під час створення контенту. Див. autoFill.

    Слід усвідомлювати: автоматичне машинне заповнення перетворює видиму прогалину на невидиму. Ключ отримав значення, аудит стає зеленим, але текст ще ніхто з людей не вичитував. Використовуйте це для розблокування релізу, але обов'язково передавайте критичні тексти на перевірку людині перед показом клієнтам. Це допоміжний каркас, а не остаточна відповідь.

    Поширені помилки

    • Сприймати фолбек як захисний механізм. Це спосіб аварійного рендерингу, а не страховка. Сторінка, яка тихо показує англійський текст — це непомічена помилка.
    • Покладатися на звіт CLI для блокування CI. intlayer content test завершується з кодом нуль. Використовуйте assertion у тестах.
    • Вимагати стовідсоткової присутності кожної локалі. Перевірку видалять, щойно вона заблокує терміновий реліз.
    • Аудит лише каталогів без перевірки реального екрана. Захардкоджені рядки не можуть бути знайдені в каталозі за визначенням.
    • Тестування виключно типової локалі. Єдина локаль, яка гарантовано ніколи не буде відсутня.
    • Зупинка процесу на машинному заповненні. Зелений аудит без жодної перевірки якості тексту.

    Корисні посилання

    Коментарі

    Поки що немає коментарів. Будьте першим, хто поділиться своїми думками.

    Схожі публікації

    Останні публікації