Задайте питання та отримайте підсумок документа, вказавши цю сторінку та обраного вами постачальника штучного інтелекту
Вміст цієї сторінки перекладено за допомогою штучного інтелекту.
Переглянути останню версію оригінального вмісту англійськоюЯкщо у вас є ідея щодо покращення цієї документації, будь ласка, долучіться, надіславши pull request на GitHub.
Посилання на документацію на GitHubСкопіювати документацію у форматі Markdown в буфер обміну
Lingui проти Intlayer | Бенчмарк інтернаціоналізації (i18n) у React та Next.js
Lingui та Intlayer - це дві бібліотеки в цьому бенчмарку, які покладаються на компілятор, а не на чистий runtime. Lingui витягує повідомлення з макросів під час збирання та компілює каталоги для кожної локалі. Intlayer компілює словники для кожного компонента та виконує tree-shaking для кожної локалі. У теорії вони мають бути близькими. Числа показують, де вони розходяться.
Дані отримані з Benchmark Bloom, відкритого набору тестів, який створює однаковий додаток з кожною бібліотекою та фіксує, що браузер насправді завантажує та виконує.
Коротко (tl;dr): Lingui найближче підходить до Intlayer за обсягом чистого JavaScript на сторінку: 115-120 КБ проти 118.6 КБ на TanStack Start після налаштування лінивого завантаження (lazy loading), 148.6 КБ проти 141.3 КБ на Next.js. Розрив виникає в інших показниках: компонент Lingui, скомпільований ізольовано, важить 58-153 КБ проти 6-8 КБ у Intlayer, гідратація займає 28-34 мс проти 11-14 мс, резервна локаль джерела витікає на 3-15% рядківenна сторінкахfrу кожній оптимізованій конфігурації, а досягнення цієї оптимізованої конфігурації вимагає ручного вилучення, компіляції та вибору каталогів для кожного маршруту. Intlayer досягає цього без будь-яких налаштувань.
Короткий огляд
- Lingui - На основі макросів (
t`...`,<Trans>,msg), ICU MessageFormat, каталоги.po/ JSON, робочий процесlingui extract+lingui compile. Компілює ідентифікатори повідомлень у короткі хеші, підтримує динамічне завантаження каталогів для кожної локалі. Добре зарекомендований, незалежний від фреймворків, багата екосистема інструментів для перекладачів навколо.po. - Intlayer - Модель контенту, орієнтована на компоненти. Словники
.content.tsрозташовані поруч із компонентом, який вони обслуговують, компілятор часу збирання виконує tree-shaking та ліниве завантаження для кожного компонента та локалі, суворі типи TypeScript генеруються автоматично з вашого контенту, а відсутні переклади призводять до помилки збирання. Включає middleware, помічники SEO, Візуальний редактор / CMS та переклад за допомогою штучного інтелекту.
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
Значки оновлюються автоматично. Показники змінюються з часом.
Порівняння функціональності
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
| Функція | Intlayer (react-intlayer / next-intlayer) | Lingui (@lingui/core / @lingui/react) |
|---|---|---|
| Переклади поруч із компонентами | ✅ Так, .content.ts розташований поруч із кожним компонентом | ⚠️ Вихідні рядки всередині JSX через макроси; переклади у централізованих каталогах .po |
| Інтеграція з TypeScript | ✅ Суворі типи генеруються автоматично з контенту | ⚠️ Макроси типізовані; ідентифікатори повідомлень ні, відсутні записи в каталозі не виявляються |
| Виявлення відсутніх перекладів | ✅ Помилка TypeScript + помилка/попередження під час збирання | ⚠️ lingui extract показує статистику; під час виконання повертається вихідний рядок |
| Багатий контент (JSX / Markdown / компоненти) | ✅ Пряма підтримка | ✅ <Trans> із вкладеними компонентами |
| Підтримка ICU | ⚠️ У розробці | ✅ Так (макроси plural, select, selectOrdinal) |
| Форматування (дати, числа, валюти) | ✅ useNumber, useDate, ... (Intl під капотом) | ✅ i18n.date(), i18n.number() |
| Локалізована маршрутизація та middleware | ✅ Вбудований проксі/middleware, getMultilingualUrls | ❌ Не є частиною ядра |
| SEO-помічники (hreflang, sitemap, robots) | ✅ Вбудовані інструменти | ❌ Вручну |
| Синхронні серверні компоненти | ✅ useIntlayer з next-intlayer/server працює у будь-якому дочірньому компоненті | ⚠️ Потрібен екземпляр I18n для кожного запиту, який передається або задається через setI18n |
| Tree-shaking (відправка лише потрібного вмісту) | ✅ Для кожного компонента та локалі, автоматизовано компілятором | ⚠️ Для кожної локалі через lingui compile; для кожного маршруту потрібен ручний поділ |
| Ліниве завантаження (Lazy loading) | ✅ importMode: 'dynamic' (один рядок конфігурації) | ⚠️ Ручний import() скомпільованих каталогів + i18n.load() / i18n.activate() |
| Очищення невикористаного контенту | ✅ Невикористані словники видаляються під час збирання | ✅ lingui extract --clean видаляє застарілі повідомлення |
| Тестування відсутніх перекладів (CLI / CI) | ✅ npx intlayer content test | ⚠️ Статистика lingui extract (за замовчуванням немає коду помилки завершення) |
| Конвеєр збирання (Build pipeline) | ✅ Один плагін (@intlayer/swc / @intlayer/babel / vite-intlayer) | ⚠️ Плагін макросів (Babel або SWC) + кроки extract + compile |
| Переклад за допомогою ШІ | ✅ Вбудовано, використовує ваші власні ключі постачальників | ❌ Немає |
| Візуальний редактор / CMS | ✅ Безкоштовний Візуальний редактор + додаткова CMS | ❌ Немає (.po працює із зовнішніми системами TMS) |
| Сервер MCP та навички агентів (Agent Skills) | ✅ Так | ❌ Немає |
| Екосистема / спільнота | ⚠️ Менша, але стрімко зростає | ✅ Добре зарекомендована, універсальна |
Бенчмарк
Що вимірювалося
Набір тестів Benchmark Bloom збирає однаковий додаток для кожної бібліотеки: 10 сторінок (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), 10 локалей (en, fr, es, de, it, pt, zh, ja, ko, ru), однакові компоненти та ідентичний вміст. Сторінки вимірюються мовами en та fr. Кожна бібліотека реалізована у чотирьох стратегіях завантаження, від найпростішої конфігурації до оптимальної:
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
| Стратегія | Опис | Хто це використовує |
|---|---|---|
| static | Скомпільований каталог кожної локалі імпортується та завантажується заздалегідь | Швидкі прототипи, код, згенерований ШІ |
| dynamic | Тільки каталог активної локалі імпортується через import(), але він містить усі сторінки | Більшість проєктів |
| scoped-static | Один каталог на маршрут, усі запаковані заздалегідь | Рідко |
| scoped-dynamic | Один каталог на маршрут + лінивий import(). Тільки поточна сторінка та локаль | Додатки з суворим бюджетом продуктивності |
Intlayer не має варіанта "scoped": компілятор автоматично обмежує контекст контенту для кожного компонента, тому його рядки static і dynamic вже оптимізовані за маршрутами.
Для кожного збирання тестовий набір фіксує:
- Розмір бібліотеки (Lib size): розмір gzip порожнього компонента, який імпортує лише бібліотеку i18n. Постійні витрати runtime.
- JS сторінки (Page JS): стиснутий gzip JavaScript, що завантажується на сторінку, усереднений для всіх сторінок і локалей.
- % витоку локалі (Locale leak %): частка перекладених рядків у завантаженому JS, які належать локалі, яку користувач не переглядає (протестовано на
enіfr, тому 50% означає повну присутність іншої вимірюваної мови; при 10 запакованих локалях реальні зайві витрати набагато більші). - % витоку сторінки (Page leak %): частка перекладених рядків у завантаженому JS, які належать сторінці, на якій користувач не перебуває.
- Середній розмір компонента (Component avg): середній розмір gzip кожного компонента, скомпільованого окремо. Показує, скільки runtime та каталогів тягне за собою один компонент.
- Реактивність E2E: час між вибором нової локалі та оновленням
html[lang]у DOM (Playwright, 5 ітерацій). - Гідратація: тривалість фази гідратації React.
Наведені нижче дані отримані під час тестування від 2026-09-12 з@lingui/react6.6.0 таintlayer9.5.1. Тестовий додаток навмисно невеликий (кілька десятків рядків на локаль), тому відсотки витоку описують закономірність: вони збільшуються разом зі зростанням вашого контенту, тоді як витрати runtime залишаються фіксованими.
Результати на Next.js
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
| Бібліотека | Стратегія | Розмір Lib (gz) | Сер. JS сторінки (gz) | Витік локалі | Витік сторінки | Сер. компонента (gz) | Реактивність E2E | Гідратація |
|---|---|---|---|---|---|---|---|---|
| base (без i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
| Lingui | static | 11.9 KB | 207.4 KB | 50.0% | 90.0% | 73.3 KB | 15.3 ms | 15.2 ms |
| Lingui | dynamic | 11.9 KB | 145.4 KB | 2.8% | 89.9% | 19.9 KB | 15.7 ms | 12.7 ms |
| Lingui | scoped-static | 11.9 KB | 148.2 KB | 2.7% | 89.1% | 20.4 KB | 15.1 ms | 13.1 ms |
| Lingui | scoped-dynamic | 11.9 KB | 148.6 KB | 14.8% | 0.0% | 152.6 KB | 16.1 ms | 14.8 ms |
next-intlayer | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
next-intlayer | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
Як інтерпретувати результати
- Витрати runtime. Порожній компонент важить 11.9 КБ gzip з Lingui і 5.5 КБ з Intlayer. На повній сторінці найкраща конфігурація Lingui дає +7.3 КБ у порівнянні з Intlayer (148.6 проти 141.3 КБ); Intlayer додає лише +0.3 КБ до базового додатка без i18n.
- Проста конфігурація коштує дорого. Попереднє завантаження всіх скомпільованих каталогів дає 207.4 КБ на сторінку, що на +66 КБ більше за базовий додаток. Половина виявлених рядків належить до іншої локалі, а 90% - до інших сторінок.
- Динамічне завантаження вирішує проблему локалі, але не сторінки. З одним каталогом на локаль витік сторінки залишається на рівні ~90%: весь каталог
frзавантажується на кожній французькій сторінці. Щоб досягти 0% витоку сторінки, потрібна конфігураціяscoped-dynamic: окремий каталог для кожного маршруту, який створюється та підключається вручну. - Витік резервної мови (fallback). Навіть в оптимізованих конфігураціях 3-15% рядків
enпотрапляють на сторінкиfr. Макроси Lingui зберігають початкове повідомлення як fallback, через що воно потрапляє у бандл поруч із перекладом. Intlayer розв'язує резервні переклади під час збирання та надсилає виключно активну мову. - Розмір компонента різко зростає у
scoped-dynamic. Кожен компонент, скомпільований окремо, важить у середньому 152.6 КБ, оскільки каталог кожного маршруту стає доступним із компонента, який його імпортує. Той самий компонент зuseIntlayer()важить у середньому 6.9 КБ.
Результати на TanStack Start
Відкрийте таблицю в модальному вікні, щоб чітко переглянути всі дані
| Бібліотека | Стратегія | Розмір Lib (gz) | Сер. JS сторінки (gz) | Витік локалі | Витік сторінки | Сер. компонента (gz) | Реактивність E2E | Гідратація |
|---|---|---|---|---|---|---|---|---|
| base (без i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms | 21.6 ms |
| Lingui | static | 11.2 KB | 152.2 KB | 50.0% | 90.0% | 58.0 KB | 3.9 ms | 19.9 ms |
| Lingui | dynamic | 11.2 KB | 115.2 KB | 9.3% | 0.0% | 85.5 KB | 5.9 ms | 28.0 ms |
| Lingui | scoped-static | 11.2 KB | 120.8 KB | 4.0% | 0.0% | 147.9 KB | 7.1 ms | 33.9 ms |
| Lingui | scoped-dynamic | 11.2 KB | 120.2 KB | 8.6% | 0.0% | 83.7 KB | 42.1 ms | 32.9 ms |
intlayer | static | 5.0 KB | 125.8 KB | 50.0% | 0.0% | 8.1 KB | 3.2 ms | 11.5 ms |
intlayer | dynamic | 5.0 KB | 118.6 KB | 0.0% | 0.0% | 6.3 KB | 3.6 ms | 14.1 ms |
@intlayer/lingui (сумісн.) | dynamic | 10.3 KB | 137.0 KB | 9.9% | 0.0% | 12.8 KB | 2.9 ms | 19.7 ms |
Як інтерпретувати результати
- За обсягом JavaScript на сторінку Lingui перемагає з мінімальним відривом.
dynamicLingui досягає 115.2 КБ, що на 3.4 КБ менше за Intlayer (118.6 КБ). Скомпільовані каталоги Lingui з хешованими ідентифікаторами дуже компактні, а маршрутизатор TanStack Start настільки добре ділить код, що витік сторінки становить 0% уже в рядкуdynamic. - Усі інші показники свідчать на користь Intlayer. Гідратація займає 28-34 мс у Lingui проти 11-14 мс у Intlayer:
i18n.load()+i18n.activate()запускаються на клієнті до того, як React зможе завершити гідратацію. Компоненти, скомпільовані ізольовано, важать 58-148 КБ проти 6-8 КБ. Витік локалі ніколи не опускається до 0% (становить 4-9%) через наявність рядків вихідної мови. - Перемикання локалі в оптимізованій конфігурації відбувається повільно.
scoped-dynamicLingui потребує 42 мс для оновленняhtml[lang]: каталог нового маршруту необхідно завантажити та активувати до того, як зміна стане помітною. Intlayer перемикається за 3-4 мс в обох режимах. - Рядок
staticв Intlayer вже має 0% витоку сторінки, оскільки до бандла потрапляють лише словники, імпортовані компонентами поточної сторінки. Один рядок конфігурації (importMode: 'dynamic') повністю прибирає і витік локалі. @intlayer/linguiзберігає синтаксис макросів Lingui та обслуговує їх зі словників Intlayer. Це дещо збільшує розмір сторінки (137 КБ через наявність runtime макросів) заради зменшення розміру компонентів (12.8 КБ) та швидшої гідратації, ніж у нативному Lingui. Це чудовий крок для поступової міграції.
Чому виникає ця різниця? Два компілятори, дві одиниці роботи
Обидві бібліотеки виконують компіляцію. Різниця полягає в тому, що саме вони компілюють.
Lingui компілює каталоги. Макроси у вашому вихідному коді вилучаються у файл .po для кожної локалі, а потім компілюються в модуль JS для кожної локалі. Одиницею роботи є локаль. Подальший поділ за маршрутами чи компонентами означає створення багатьох каталогів, налаштування lingui.config.ts та ручне підключення потрібного каталогу на кожному маршруті. Екземпляр I18n є глобальним; кожен виклик useLingui() підписує компонент на нього.
Скопіюйте код у буфер обміну
Intlayer компілює словники. Кожен файл .content.ts - це словник, прив'язаний до певного ключа; компілятор визначає, який компонент імпортує цей ключ, і генерує для кожного словника та локалі саме той фрагмент JSON, який потрібен цьому компоненту. Одиницею роботи є компонент. Прив'язка до маршруту є природним наслідком: сторінка підтягує лише словники тих компонентів, які вона реально рендерить.
Скопіюйте код у буфер обміну
Ось чому патерн scoped-dynamic є автоматичним результатом збирання для Intlayer і складним ручним конфігураційним проєктом для Lingui.
Щоб отримати показники рядкаdynamic, встановітьdictionary.importMode: 'dynamic'уintlayer.config.ts. Дивіться документацію з оптимізації бандла.
Досвід розробника
Налаштування
Lingui
Скопіюйте код у буфер обміну
Скопіюйте код у буфер обміну
Потім додайте @lingui/babel-plugin-lingui-macro (або @lingui/swc-plugin) до бандлера, запускайте lingui extract після редагування коду, lingui compile перед збиранням і оберніть дерево компонентів у <I18nProvider i18n={i18n}>.
Intlayer
Скопіюйте код у буфер обміну
Додайте intlayer() до vite.config.ts (або withIntlayer() до next.config.ts) та оберніть дерево в <IntlayerProvider>. Жодних кроків extract чи compile: словники створюються автоматично під час роботи бандлера.
Компонент
Lingui
Скопіюйте код у буфер обміну
Англійський текст міститься безпосередньо в компоненті; французький зберігається у файлі src/locales/fr/messages.po під хешованим ідентифікатором після запуску lingui extract. Якщо забути виконати цю команду або compile, застосунок непомітно повернеться до англійського тексту.
Intlayer
Скопіюйте код у буфер обміну
Скопіюйте код у буфер обміну
Обидві локалі зберігаються в одному файлі поруч із компонентом. Відсутнє значення fr спричиняє помилку під час збирання, а невірний ключ призводить до помилки TypeScript.
За межами компонентів
Метадані, завантажувачі (loaders), серверні функції: будь-яке місце без дерева React.
Lingui
Скопіюйте код у буфер обміну
Створення нового екземпляра I18n для кожного виклику, завантаження потрібного каталогу вручну та використання msg + i18n._() замість t. Як зазначено в примітках до бенчмарку, розуміння того, коли саме використовувати t, t` ` , i18n.t(), msg або <Trans>, часто не є інтуїтивним.
Intlayer
Скопіюйте код у буфер обміну
Збережіть макроси Lingui, отримайте словники Intlayer
@intlayer/lingui - це сумісний адаптер для @lingui/core та @lingui/react. Макроси продовжують компілюватися як і раніше; виклики i18n._(), у які вони перетворюються, обслуговуються зі словників Intlayer, а плагіни синхронізації .po зберігають ваші чинні каталоги як єдине джерело правди. Форми множини та селектори ICU відображаються повністю ідентично.
Скопіюйте код у буфер обміну
Збережіть плагін @lingui/babel-plugin-lingui-macro / @lingui/swc-plugin у процесі збирання перед компілятором Intlayer. Дивіться документацію щодо сумісності з Lingui.
Що і коли обрати?
- Обирайте Lingui, якщо вам потрібен ICU MessageFormat із типізованими макросами, ваші перекладачі працюють з файлами
.poв межах наявної системи TMS, ви віддаєте перевагу вбудованим вихідним рядкам безпосередньо в JSX, а ваша команда звикла керувати процесом вилучення, компіляції та розділення каталогів. Розмір JS на сторінку дуже конкурентний після налаштування лінивого завантаження. - Обирайте Intlayer, якщо вам потрібен контент з прив'язкою до компонентів, суворий TypeScript, помилки про відсутні ключі під час збирання, автоматичний tree-shaking та ліниве завантаження без конфігурації, компактні компоненти, швидка гідратація, миттєве перемикання локалей та вбудовані редакційні інструменти (Візуальний редактор, CMS, переклад за допомогою ШІ, сервер MCP).
- Обирайте
@intlayer/lingui, якщо ви вже використовуєте Lingui і прагнете поступово перейти на словники Intlayer без зміни макросів.
Схожі порівняння
- next-intl проти Intlayer (той самий бенчмарк)
- i18next проти Intlayer (той самий бенчмарк)
- Бенчмарк vue-i18n проти Intlayer (той самий бенчмарк)
- Компілятор проти декларативного i18n
Зірки GitHub
Зірки на GitHub є вагомим показником популярності проєкту, довіри спільноти та його довгострокової актуальності. Хоча вони не є прямою оцінкою технічної досконалості, вони відображають, скільки розробників вважають проєкт корисним і стежать за його розвитком.
Висновок
Lingui є найпотужнішою комбінованою бібліотекою (runtime + компілятор) у цьому бенчмарку. Її скомпільовані хешовані каталоги забезпечують обсяг JavaScript на сторінку лише на кілька кілобайтів більший, ніж у Intlayer, а на TanStack Start навіть дещо менший. Якби розмір сторінки був єдиною метрикою, це була б нічия.
Але це не так. Компілятор Lingui зупиняється на межі цілої локалі; все, що нижче (каталоги для кожного маршруту, ліниве завантаження, виключення резервної мови з бандла), вимагає ручного налаштування. Бенчмарк демонструє наслідки цього обмеження: компоненти у 10-20 разів більші, гідратація у 2-3 рази повільніша, 3-15% витоку локалі, якого неможливо позбутися, і перемикання локалі тривалістю 42 мс в оптимізованому режимі. Компілятор Intlayer працює безпосередньо на рівні окремих компонентів, тому ці показники становлять 6-8 КБ, 11-14 мс, 0% та 3-4 мс без будь-яких ручних налаштувань.
Усі вихідні дані, тестові додатки та скрипти доступні у репозиторії Benchmark Bloom. Ви можете запустити їх самостійно.
Зверніться до документа 'Чому Intlayer?' для отримання детальнішої інформації.
Коментарі
Поки що немає коментарів. Будьте першим, хто поділиться своїми думками.
