Одна из главных проблем i18n в приложениях заключается в том, что о ней вспоминают в последнюю очередь.

Обычно мы разрабатываем продукт, проверяем соответствие рынку (Product-Market Fit) и только спустя месяцы или годы решаем: «Пора выходить на глобальный уровень».

Сложность в том, что решения для i18n носят структурный характер и сильно влияют на работу команды. Куда эффективнее закладывать это в техническое задание с первого дня.

Как же с этим справиться? Заморозить разработку на неделю и рефакторить каждый компонент?

В последнее время я вижу много решений, основанных на compiler-driven подходе. Обещание заманчивое: добавьте пару строк кода, и приложение «само» станет мультиязычным.

Однако есть существенные недостатки:

  • Замедление разработки: Компиляторы добавляют этапы обработки, что особенно заметно в режиме разработки (hot reload).

  • Отсутствие 100% покрытия: В 98% случаев i18n работает корректно, но оставшиеся 2% становятся головной болью. Как перевести функцию getDescription, которая находится вне компонента? Как обрабатывать плюрализацию, вставку переменных, даты и т.д.?

  • Размер бандла: Оптимизация контента часто уходит на второй план. В итоге пользователи могут загружать данные для всех страниц на всех языках ради просмотра одной вкладки.

  • Vendor lock-in: Некоторые решения делают вас зависимыми от платформы, заставляя переплачивать за генерацию переводов.

  • Next.js Server Components: Как сделать серверный контент мультиязычным без лишних сложностей?

В Intlayer мы попытались решить это с помощью гибридного подхода.

Intlayer использует компилятор для обработки компонентов. По аналогии с тем, как React Compiler оборачивает код в useMemo / useCallback, Intlayer извлекает контент и автоматически внедряет функции getIntlayer / useIntlayer.

Вам не нужны блоки <T> или функции t — Intlayer трансформирует компоненты в их исходном виде.

При этом Intlayer — это прежде всего решение для декларативной интернационализации. Это значит, что его можно использовать для метаданных страниц или смешивать контент, управляемый вручную, с работой компилятора.

Основные преимущества:

  • 100% Бесплатно: Нет платы за каждый ключ; перевод стоит ровно столько, сколько запрашивает ваш AI-провайдер.

  • Совместимость: Работает с Vite / Next.js (Webpack / Turbopack) / React / Svelte / Vue / Client и Server side.

  • Гибкость: Можно включать как для разработки, так и только для продакшн-сборок.

  • Оптимизация: Архитектура учитывает размер бандла.

Документация:

Интересно узнать ваше мнение. Какой у вас опыт работы с i18n-компиляторами?

Комментарии (4)


  1. DmitryKazakov8
    25.02.2026 21:58

    Довольно часто вижу в ленте статьи по Intlayer - вы стараетесь его популяризировать, но не понимаю практической применимости. Обычно переводы в проектах делаются проще и эффективнее.

    Посмотрим в контексте "ретроспективного внедрения интернационализации" + React. На данный момент все тексты захардкожены в компонентах, бизнес ставит задачу - перевести на несколько языков.

    1.Нужно вынести тексты в объекты, это прекрасно типизируется TS и есть немало инструментов, позволяющих идентифицировать "неиспользуемые ключи в объекте", то есть масштабируемость - хорошая.

    // было
    function Component() {
      return <div>Hello</div>
    }
    
    // стало
    const messages = {
      hello: 'Hello'
    }
    
    function Component() {
      return <div>{messages.hello}</div>
    }

    2.Вынести объект messages в отдельные файлы для переиспользуемости и задать автогенерацию уникальных ключей

    // src/pages/intro/messages.ts
    
    export const messages = wrap(__dirname, {
      hello: 'Hello'
    })
    
    console.log(messages);
    
    // { "src/pages/intro__hello": { default: "Hello" } }

    __dirname здесь - простейший уникальный для файла идентификатор, многие бандлеры умеют с ним работать "из коробки". Но можно использовать любой, прокидывая бандлером.

    3.Добавить возможность подключить шаблонизатор для плюрализации, работы с датами, падежами и т.п., готовых в js-экосистеме масса. Достаточно сделать функцию ln, а движок подбирать по нуждам проекта либо делегировать это сторонней системе вроде Localise.

    function Component() {
      return <div>{ln(messages.hello)}</div>
    }

    Функция ln может под капотом иметь разную реализацию (например, возвращать реакт-компонент) или быть реактивной на сигналах (сменилась локализация - все функции перевызвались, обновив тексты в приложении), это все делается парой строк.

    4.Собрать все тексты в json-файлы и встроить генерацию в бандлер перед сборкой и в watch-режиме

    // translations.json
    { 
      "src/pages/intro__hello": { "default": "Hello", "ru": "", "en": "" } 
    }

    Для многих проектов подойдет автопереводчик с ручной правкой, для более сложных - этот json можно автоматизированно выгружать в облачную систему для переводчиков, которые 1 кнопкой пушат его с переводами обратно в репозиторий.

    Собственно, все. Это база, которая и так есть в большинстве проектов, и может очень гибко настраиваться под стек, в том числе делая отдельные json-чанки под компонент (чтобы не все локализации грузились сразу). С ИИ этапы 1 и 2 делаются за полчаса, 3 и 4 пишутся за день под конкретные технологии и требования в проекте.

    Итог - задача выполнена, при добавлении/удалении ключей в любом модульном messages.ts обновляется JSON, выгружается в систему переводов, и для изменения переводов не нужны разработчики - переводчики могут менять тексты сами, не влияя на код проекта.

    А каждый раз, когда захожу на документацию Intlayer, не понимаю зачем столько бойлерплейта и сложностей, зачем вручную задавать ключи с дубляжом для каждого языка; писать переводы прямо в messages вместо того, чтобы отдавать json переводчикам или в автоперевод (поэкономьте время разработчиков); привязываться к встроенным механизмам шаблонизации (когда часто это должно быть частью локализационной системы типа облачного Localise). И много еще другого, что мне кажется крайне неэффективным, и видя это закрываю вкладку с документацией.

    Скорее всего, пишу это "в пустоту" - половина ваших комментариев на Хабре ИИ-нейрослоп, и все для рекламы, но слишком уж часто эта поделка попадает в ленту.


    1. aymericzip Автор
      25.02.2026 21:58

      Скорее всего, ты прав, и я прошу прощения за навязчивость

      Я действительно делюсь этим, чтобы напомнить о лучших практиках, которые часто игнорируют. Конечно, я также хочу рассказать о своем решении и получить обратную связь. Спасибо за твои замечания, они действительно помогают проекту расти. Я учел все важные моменты

      Этот проект появился потому, что я был недоволен тем подходом, который ты описываешь. На мой взгляд, централизация контента является критической проблемой. Она раздувает бандл приложения и провоцирует конфликты при слиянии веток. Управление неймспейсами и поиск неиспользуемых строк в i18next, next-intl или vue-i18n часто превращаются в настоящий ад. Я хотел создать инструмент, который сам мечтал бы иметь под рукой

      При этом я понимаю, что это решение подойдет не каждому. У меня нет цели переписывать i18next, ведь он и так отлично справляется со своими задачами.

      Буду рад продолжить общение. Пиши мне в любое время, где тебе удобно


      1. DmitryKazakov8
        25.02.2026 21:58

        Вот как раз что я и ожидал - ответ от ИИ, полностью игнорирующий описанный мной концепт, и рекламирующий библиотеку)

        i18next, next-intl или vue-i18n - неоптимизированные библиотеки с неэффективным использованием, тут соглашусь, но я же описал подход, никак с ними не связанный. Файлы message.ts - модульные, а общий json нужен только для переводчиков и удобной выгрузки в системы локализации. В коде его вполне можно разбивать на чанки хоть под каждый модуль, хоть под скоуп модулей (например для страницы src/pages/intro брать все тексты из json с этим префиксом). Это гибкость, универсальность и минимальный бойлерплейт.

        Конфликты при слиянии веток здесь возможны только если параллельно работают над одним и тем же messages.ts - и точно такие же конфликты будут в Intlayer, так как он тоже использует модульные файлы с локализацией (но вроде без сборки их в большой json). Но это "слабые" конфликты, которые легко решаются автоматически, т.к. все ключи - уникальные.

        ИИ захватывает Хабр(


        1. aymericzip Автор
          25.02.2026 21:58

          У тебя есть пример реализации, которым ты можешь поделиться? Мне любопытно