@intlayer/docs 9.5.2 → 9.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/blog/ar/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ar/i18next_vs_intlayer.md +445 -0
- package/blog/ar/is_i18next_outdated.md +1 -1
- package/blog/ar/is_next-intl_outdated.md +1 -1
- package/blog/ar/is_vue-i18n_outdated.md +1 -1
- package/blog/ar/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ar/lingui_vs_intlayer.md +381 -0
- package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ar/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ar/next-intl_vs_intlayer.md +397 -0
- package/blog/ar/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ar/vue-i18n_vs_intlayer-vue-i18n.md +286 -0
- package/blog/ar/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/de/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/de/i18next_vs_intlayer.md +445 -0
- package/blog/de/is_i18next_outdated.md +1 -1
- package/blog/de/is_next-intl_outdated.md +1 -1
- package/blog/de/is_vue-i18n_outdated.md +1 -1
- package/blog/de/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/de/lingui_vs_intlayer.md +381 -0
- package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/de/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/de/next-intl_vs_intlayer.md +415 -0
- package/blog/de/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/de/vue-i18n_vs_intlayer_benchmark.md +355 -0
- package/blog/en/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/en/i18next_vs_intlayer.md +445 -0
- package/blog/en/is_i18next_outdated.md +1 -1
- package/blog/en/is_next-intl_outdated.md +1 -1
- package/blog/en/is_vue-i18n_outdated.md +1 -1
- package/blog/en/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/en/lingui_vs_intlayer.md +381 -0
- package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/en/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/en/next-intl_vs_intlayer.md +415 -0
- package/blog/en/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/en/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/en/vue-i18n_vs_intlayer.md +1 -1
- package/blog/en/vue-i18n_vs_intlayer_benchmark.md +361 -0
- package/blog/en-GB/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/en-GB/i18next_vs_intlayer.md +445 -0
- package/blog/en-GB/is_i18next_outdated.md +1 -1
- package/blog/en-GB/is_next-intl_outdated.md +1 -1
- package/blog/en-GB/is_vue-i18n_outdated.md +1 -1
- package/blog/en-GB/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/en-GB/lingui_vs_intlayer.md +381 -0
- package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/en-GB/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/en-GB/next-intl_vs_intlayer.md +415 -0
- package/blog/en-GB/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/en-GB/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/en-GB/vue-i18n_vs_intlayer.md +1 -1
- package/blog/en-GB/vue-i18n_vs_intlayer_benchmark.md +245 -0
- package/blog/es/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/es/i18next_vs_intlayer.md +445 -0
- package/blog/es/is_i18next_outdated.md +1 -1
- package/blog/es/is_next-intl_outdated.md +1 -1
- package/blog/es/is_vue-i18n_outdated.md +1 -1
- package/blog/es/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/es/lingui_vs_intlayer.md +381 -0
- package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/es/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/es/next-intl_vs_intlayer.md +417 -0
- package/blog/es/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/es/vue-i18n_vs_intlayer_benchmark.md +363 -0
- package/blog/fr/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/fr/i18next_vs_intlayer.md +445 -0
- package/blog/fr/is_i18next_outdated.md +1 -1
- package/blog/fr/is_next-intl_outdated.md +1 -1
- package/blog/fr/is_vue-i18n_outdated.md +1 -1
- package/blog/fr/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/fr/lingui_vs_intlayer.md +381 -0
- package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/fr/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/fr/next-intl_vs_intlayer.md +417 -0
- package/blog/fr/vue-i18n_vs_intlayer-vue-i18n.md +287 -0
- package/blog/fr/vue-i18n_vs_intlayer_benchmark.md +39 -0
- package/blog/hi/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/hi/i18next_vs_intlayer.md +445 -0
- package/blog/hi/is_i18next_outdated.md +1 -1
- package/blog/hi/is_next-intl_outdated.md +1 -1
- package/blog/hi/is_vue-i18n_outdated.md +1 -1
- package/blog/hi/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/hi/lingui_vs_intlayer.md +381 -0
- package/blog/hi/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/hi/next-intl_vs_intlayer.md +397 -0
- package/blog/hi/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/hi/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/hi/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/id/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/id/i18next_vs_intlayer.md +445 -0
- package/blog/id/is_i18next_outdated.md +1 -1
- package/blog/id/is_next-intl_outdated.md +1 -1
- package/blog/id/is_vue-i18n_outdated.md +1 -1
- package/blog/id/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/id/lingui_vs_intlayer.md +381 -0
- package/blog/id/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/id/next-intl_vs_intlayer-next-intl.md +310 -0
- package/blog/id/next-intl_vs_intlayer.md +397 -0
- package/blog/id/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/id/vue-i18n_vs_intlayer-vue-i18n.md +36 -0
- package/blog/id/vue-i18n_vs_intlayer.md +1 -1
- package/blog/id/vue-i18n_vs_intlayer_benchmark.md +41 -0
- package/blog/it/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/it/i18next_vs_intlayer.md +445 -0
- package/blog/it/is_i18next_outdated.md +1 -1
- package/blog/it/is_next-intl_outdated.md +1 -1
- package/blog/it/is_vue-i18n_outdated.md +1 -1
- package/blog/it/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/it/lingui_vs_intlayer.md +381 -0
- package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/it/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/it/next-intl_vs_intlayer.md +418 -0
- package/blog/it/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/it/vue-i18n_vs_intlayer_benchmark.md +34 -0
- package/blog/ja/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ja/i18next_vs_intlayer.md +447 -0
- package/blog/ja/is_i18next_outdated.md +1 -1
- package/blog/ja/is_next-intl_outdated.md +1 -1
- package/blog/ja/is_vue-i18n_outdated.md +1 -1
- package/blog/ja/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ja/lingui_vs_intlayer.md +381 -0
- package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ja/next-intl_vs_intlayer-next-intl.md +310 -0
- package/blog/ja/next-intl_vs_intlayer.md +422 -0
- package/blog/ja/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ja/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ja/vue-i18n_vs_intlayer.md +1 -1
- package/blog/ja/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/ko/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ko/i18next_vs_intlayer.md +447 -0
- package/blog/ko/is_i18next_outdated.md +1 -1
- package/blog/ko/is_next-intl_outdated.md +1 -1
- package/blog/ko/is_vue-i18n_outdated.md +1 -1
- package/blog/ko/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ko/lingui_vs_intlayer.md +381 -0
- package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ko/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ko/next-intl_vs_intlayer.md +397 -0
- package/blog/ko/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/ko/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ko/vue-i18n_vs_intlayer.md +1 -1
- package/blog/ko/vue-i18n_vs_intlayer_benchmark.md +366 -0
- package/blog/pl/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/pl/i18next_vs_intlayer.md +445 -0
- package/blog/pl/is_i18next_outdated.md +1 -1
- package/blog/pl/is_next-intl_outdated.md +1 -1
- package/blog/pl/is_vue-i18n_outdated.md +1 -1
- package/blog/pl/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/pl/lingui_vs_intlayer.md +381 -0
- package/blog/pl/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/pl/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/pl/next-intl_vs_intlayer.md +397 -0
- package/blog/pl/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/pl/vue-i18n_vs_intlayer-vue-i18n.md +289 -0
- package/blog/pl/vue-i18n_vs_intlayer.md +1 -1
- package/blog/pl/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/pt/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/pt/i18next_vs_intlayer.md +445 -0
- package/blog/pt/is_i18next_outdated.md +1 -1
- package/blog/pt/is_next-intl_outdated.md +1 -1
- package/blog/pt/is_vue-i18n_outdated.md +1 -1
- package/blog/pt/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/pt/lingui_vs_intlayer.md +381 -0
- package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/pt/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/pt/next-intl_vs_intlayer.md +411 -0
- package/blog/pt/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/pt/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/ru/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/ru/i18next_vs_intlayer.md +445 -0
- package/blog/ru/is_i18next_outdated.md +1 -1
- package/blog/ru/is_next-intl_outdated.md +1 -1
- package/blog/ru/is_vue-i18n_outdated.md +1 -1
- package/blog/ru/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/ru/lingui_vs_intlayer.md +381 -0
- package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/ru/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/ru/next-intl_vs_intlayer.md +417 -0
- package/blog/ru/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/ru/vue-i18n_vs_intlayer_benchmark.md +54 -0
- package/blog/tr/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/tr/i18next_vs_intlayer.md +445 -0
- package/blog/tr/is_i18next_outdated.md +1 -1
- package/blog/tr/is_next-intl_outdated.md +1 -1
- package/blog/tr/is_vue-i18n_outdated.md +1 -1
- package/blog/tr/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/tr/lingui_vs_intlayer.md +381 -0
- package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/tr/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/tr/next-intl_vs_intlayer.md +397 -0
- package/blog/tr/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/tr/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/tr/vue-i18n_vs_intlayer.md +1 -1
- package/blog/tr/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/uk/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/uk/i18next_vs_intlayer.md +445 -0
- package/blog/uk/is_i18next_outdated.md +1 -1
- package/blog/uk/is_next-intl_outdated.md +1 -1
- package/blog/uk/is_vue-i18n_outdated.md +1 -1
- package/blog/uk/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/uk/lingui_vs_intlayer.md +381 -0
- package/blog/uk/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/uk/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/uk/next-intl_vs_intlayer.md +397 -0
- package/blog/uk/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/uk/vue-i18n_vs_intlayer-vue-i18n.md +270 -0
- package/blog/uk/vue-i18n_vs_intlayer.md +1 -1
- package/blog/uk/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/vi/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/vi/i18next_vs_intlayer.md +445 -0
- package/blog/vi/is_i18next_outdated.md +1 -1
- package/blog/vi/is_next-intl_outdated.md +1 -1
- package/blog/vi/is_vue-i18n_outdated.md +1 -1
- package/blog/vi/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/vi/lingui_vs_intlayer.md +381 -0
- package/blog/vi/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/vi/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/vi/next-intl_vs_intlayer.md +397 -0
- package/blog/vi/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/vi/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/vi/vue-i18n_vs_intlayer.md +1 -1
- package/blog/vi/vue-i18n_vs_intlayer_benchmark.md +0 -0
- package/blog/zh/i18next_vs_intlayer-i18next.md +327 -0
- package/blog/zh/i18next_vs_intlayer.md +445 -0
- package/blog/zh/is_i18next_outdated.md +1 -1
- package/blog/zh/is_next-intl_outdated.md +1 -1
- package/blog/zh/is_vue-i18n_outdated.md +1 -1
- package/blog/zh/lingui_vs_intlayer-lingui.md +304 -0
- package/blog/zh/lingui_vs_intlayer.md +381 -0
- package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1 -1
- package/blog/zh/next-intl_vs_intlayer-next-intl.md +309 -0
- package/blog/zh/next-intl_vs_intlayer.md +422 -0
- package/blog/zh/react-i18next_vs_react-intl_vs_intlayer.md +1 -1
- package/blog/zh/vue-i18n_vs_intlayer-vue-i18n.md +288 -0
- package/blog/zh/vue-i18n_vs_intlayer.md +1 -1
- package/blog/zh/vue-i18n_vs_intlayer_benchmark.md +30 -0
- package/dist/cjs/generated/blog.entry.cjs +160 -0
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/generated/frequentQuestions.entry.cjs +20 -0
- package/dist/cjs/generated/frequentQuestions.entry.cjs.map +1 -1
- package/dist/esm/generated/blog.entry.mjs +160 -0
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/generated/frequentQuestions.entry.mjs +20 -0
- package/dist/esm/generated/frequentQuestions.entry.mjs.map +1 -1
- package/dist/types/generated/blog.entry.d.ts +8 -0
- package/dist/types/generated/blog.entry.d.ts.map +1 -1
- package/dist/types/generated/frequentQuestions.entry.d.ts +1 -0
- package/dist/types/generated/frequentQuestions.entry.d.ts.map +1 -1
- package/docs/ar/benchmark/nextjs.md +1 -1
- package/docs/ar/benchmark/solid.md +1 -1
- package/docs/ar/benchmark/svelte.md +1 -1
- package/docs/ar/benchmark/tanstack.md +1 -1
- package/docs/ar/benchmark/vue.md +1 -1
- package/docs/ar/interest_of_intlayer.md +1 -1
- package/docs/bn/interest_of_intlayer.md +1 -1
- package/docs/cs/interest_of_intlayer.md +1 -1
- package/docs/de/benchmark/nextjs.md +1 -1
- package/docs/de/benchmark/solid.md +1 -1
- package/docs/de/benchmark/svelte.md +1 -1
- package/docs/de/benchmark/tanstack.md +1 -1
- package/docs/de/benchmark/vue.md +1 -1
- package/docs/de/interest_of_intlayer.md +1 -1
- package/docs/en/benchmark/nextjs.md +1 -1
- package/docs/en/benchmark/solid.md +1 -1
- package/docs/en/benchmark/svelte.md +1 -1
- package/docs/en/benchmark/tanstack.md +1 -1
- package/docs/en/benchmark/vue.md +1 -1
- package/docs/en/interest_of_intlayer.md +1 -1
- package/docs/en-GB/benchmark/nextjs.md +1 -1
- package/docs/en-GB/benchmark/solid.md +1 -1
- package/docs/en-GB/benchmark/svelte.md +1 -1
- package/docs/en-GB/benchmark/tanstack.md +1 -1
- package/docs/en-GB/benchmark/vue.md +1 -1
- package/docs/en-GB/interest_of_intlayer.md +1 -1
- package/docs/es/benchmark/nextjs.md +1 -1
- package/docs/es/benchmark/solid.md +1 -1
- package/docs/es/benchmark/svelte.md +1 -1
- package/docs/es/benchmark/tanstack.md +1 -1
- package/docs/es/benchmark/vue.md +1 -1
- package/docs/es/interest_of_intlayer.md +1 -1
- package/docs/fr/benchmark/nextjs.md +1 -1
- package/docs/fr/benchmark/solid.md +1 -1
- package/docs/fr/benchmark/svelte.md +1 -1
- package/docs/fr/benchmark/tanstack.md +1 -1
- package/docs/fr/benchmark/vue.md +1 -1
- package/docs/fr/interest_of_intlayer.md +1 -1
- package/docs/hi/benchmark/nextjs.md +1 -1
- package/docs/hi/benchmark/solid.md +1 -1
- package/docs/hi/benchmark/svelte.md +1 -1
- package/docs/hi/benchmark/tanstack.md +1 -1
- package/docs/hi/benchmark/vue.md +1 -1
- package/docs/hi/interest_of_intlayer.md +1 -1
- package/docs/id/benchmark/nextjs.md +1 -1
- package/docs/id/benchmark/solid.md +1 -1
- package/docs/id/benchmark/svelte.md +1 -1
- package/docs/id/benchmark/tanstack.md +1 -1
- package/docs/id/benchmark/vue.md +1 -1
- package/docs/id/interest_of_intlayer.md +1 -1
- package/docs/it/benchmark/nextjs.md +1 -1
- package/docs/it/benchmark/solid.md +1 -1
- package/docs/it/benchmark/svelte.md +1 -1
- package/docs/it/benchmark/tanstack.md +1 -1
- package/docs/it/benchmark/vue.md +1 -1
- package/docs/it/interest_of_intlayer.md +1 -1
- package/docs/ja/benchmark/nextjs.md +1 -1
- package/docs/ja/benchmark/solid.md +1 -1
- package/docs/ja/benchmark/svelte.md +1 -1
- package/docs/ja/benchmark/tanstack.md +1 -1
- package/docs/ja/benchmark/vue.md +1 -1
- package/docs/ja/interest_of_intlayer.md +1 -1
- package/docs/ko/benchmark/nextjs.md +1 -1
- package/docs/ko/benchmark/solid.md +1 -1
- package/docs/ko/benchmark/svelte.md +1 -1
- package/docs/ko/benchmark/tanstack.md +1 -1
- package/docs/ko/benchmark/vue.md +1 -1
- package/docs/ko/interest_of_intlayer.md +1 -1
- package/docs/nl/interest_of_intlayer.md +1 -1
- package/docs/pl/benchmark/nextjs.md +1 -1
- package/docs/pl/benchmark/solid.md +1 -1
- package/docs/pl/benchmark/svelte.md +1 -1
- package/docs/pl/benchmark/tanstack.md +1 -1
- package/docs/pl/benchmark/vue.md +1 -1
- package/docs/pl/interest_of_intlayer.md +1 -1
- package/docs/pt/benchmark/nextjs.md +1 -1
- package/docs/pt/benchmark/solid.md +1 -1
- package/docs/pt/benchmark/svelte.md +1 -1
- package/docs/pt/benchmark/tanstack.md +1 -1
- package/docs/pt/benchmark/vue.md +1 -1
- package/docs/pt/interest_of_intlayer.md +1 -1
- package/docs/ru/benchmark/nextjs.md +1 -1
- package/docs/ru/benchmark/solid.md +1 -1
- package/docs/ru/benchmark/svelte.md +1 -1
- package/docs/ru/benchmark/tanstack.md +1 -1
- package/docs/ru/benchmark/vue.md +1 -1
- package/docs/ru/interest_of_intlayer.md +1 -1
- package/docs/tr/benchmark/nextjs.md +1 -1
- package/docs/tr/benchmark/solid.md +1 -1
- package/docs/tr/benchmark/svelte.md +1 -1
- package/docs/tr/benchmark/tanstack.md +1 -1
- package/docs/tr/benchmark/vue.md +1 -1
- package/docs/tr/interest_of_intlayer.md +1 -1
- package/docs/uk/benchmark/nextjs.md +1 -1
- package/docs/uk/benchmark/solid.md +1 -1
- package/docs/uk/benchmark/svelte.md +1 -1
- package/docs/uk/benchmark/tanstack.md +1 -1
- package/docs/uk/benchmark/vue.md +1 -1
- package/docs/uk/interest_of_intlayer.md +1 -1
- package/docs/ur/interest_of_intlayer.md +1 -1
- package/docs/vi/benchmark/nextjs.md +1 -1
- package/docs/vi/benchmark/solid.md +1 -1
- package/docs/vi/benchmark/svelte.md +1 -1
- package/docs/vi/benchmark/tanstack.md +1 -1
- package/docs/vi/benchmark/vue.md +1 -1
- package/docs/vi/interest_of_intlayer.md +1 -1
- package/docs/zh/benchmark/nextjs.md +1 -1
- package/docs/zh/benchmark/solid.md +1 -1
- package/docs/zh/benchmark/svelte.md +1 -1
- package/docs/zh/benchmark/tanstack.md +1 -1
- package/docs/zh/benchmark/vue.md +1 -1
- package/docs/zh/interest_of_intlayer.md +1 -1
- package/docs/zh-TW/interest_of_intlayer.md +1 -1
- package/frequent_questions/ar/claude_code_token_consumption.md +152 -0
- package/frequent_questions/de/claude_code_token_consumption.md +152 -0
- package/frequent_questions/en/claude_code_token_consumption.md +152 -0
- package/frequent_questions/en-GB/claude_code_token_consumption.md +152 -0
- package/frequent_questions/es/claude_code_token_consumption.md +152 -0
- package/frequent_questions/fr/claude_code_token_consumption.md +152 -0
- package/frequent_questions/hi/claude_code_token_consumption.md +152 -0
- package/frequent_questions/id/claude_code_token_consumption.md +152 -0
- package/frequent_questions/it/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ja/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ko/claude_code_token_consumption.md +152 -0
- package/frequent_questions/pl/claude_code_token_consumption.md +152 -0
- package/frequent_questions/pt/claude_code_token_consumption.md +152 -0
- package/frequent_questions/ru/claude_code_token_consumption.md +152 -0
- package/frequent_questions/tr/claude_code_token_consumption.md +152 -0
- package/frequent_questions/uk/claude_code_token_consumption.md +152 -0
- package/frequent_questions/vi/claude_code_token_consumption.md +152 -0
- package/frequent_questions/zh/claude_code_token_consumption.md +152 -0
- package/package.json +6 -6
- package/src/generated/blog.entry.ts +160 -0
- package/src/generated/frequentQuestions.entry.ts +20 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-13
|
|
3
|
+
updatedAt: 2026-09-13
|
|
4
|
+
title: "Lingui проти Intlayer: Бенчмарк та порівняння 2026"
|
|
5
|
+
description: "Дві бібліотеки i18n на основі компілятора протестовані на Next.js та TanStack Start. Розмір бандла, витік контенту, розмір компонентів, гідратація, реактивність перемикання локалей та досвід розробника."
|
|
6
|
+
keywords:
|
|
7
|
+
- Lingui
|
|
8
|
+
- Intlayer
|
|
9
|
+
- Internationalization
|
|
10
|
+
- i18n
|
|
11
|
+
- Benchmark
|
|
12
|
+
- Bundle size
|
|
13
|
+
- Compiler
|
|
14
|
+
- Blog
|
|
15
|
+
- Next.js
|
|
16
|
+
- TanStack Start
|
|
17
|
+
- JavaScript
|
|
18
|
+
- React
|
|
19
|
+
slugs:
|
|
20
|
+
- blog
|
|
21
|
+
- lingui-vs-intlayer
|
|
22
|
+
author: aymericzip
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Lingui проти Intlayer | Бенчмарк інтернаціоналізації (i18n) у React та Next.js
|
|
26
|
+
|
|
27
|
+
Lingui та Intlayer - це дві бібліотеки в цьому бенчмарку, які покладаються на **компілятор**, а не на чистий runtime. Lingui витягує повідомлення з макросів під час збирання та компілює каталоги для кожної локалі. Intlayer компілює словники для кожного компонента та виконує tree-shaking для кожної локалі. У теорії вони мають бути близькими. Числа показують, де вони розходяться.
|
|
28
|
+
|
|
29
|
+
Дані отримані з [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom), відкритого набору тестів, який створює однаковий додаток з кожною бібліотекою та фіксує, що браузер насправді завантажує та виконує.
|
|
30
|
+
|
|
31
|
+
<TOC/>
|
|
32
|
+
|
|
33
|
+
> **Коротко (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 досягає цього без будь-яких налаштувань.
|
|
34
|
+
|
|
35
|
+
## Короткий огляд
|
|
36
|
+
|
|
37
|
+
- **Lingui** - На основі макросів (`` t`...` ``, `<Trans>`, `msg`), ICU MessageFormat, каталоги `.po` / JSON, робочий процес `lingui extract` + `lingui compile`. Компілює ідентифікатори повідомлень у короткі хеші, підтримує динамічне завантаження каталогів для кожної локалі. Добре зарекомендований, незалежний від фреймворків, багата екосистема інструментів для перекладачів навколо `.po`.
|
|
38
|
+
- **Intlayer** - Модель контенту, орієнтована на компоненти. Словники `.content.ts` розташовані поруч із компонентом, який вони обслуговують, компілятор часу збирання виконує tree-shaking та ліниве завантаження для кожного компонента та локалі, суворі типи TypeScript генеруються автоматично з вашого контенту, а відсутні переклади призводять до помилки збирання. Включає middleware, помічники SEO, Візуальний редактор / CMS та переклад за допомогою штучного інтелекту.
|
|
39
|
+
|
|
40
|
+
| Бібліотека | Зірки GitHub | Всього комітів | Останній коміт | Перша версія | Версія NPM | Завантаження NPM |
|
|
41
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
42
|
+
| `aymericzip/intlayer` | [](https://github.com/aymericzip/intlayer/stargazers) | [](https://github.com/aymericzip/intlayer/commits) | [](https://github.com/aymericzip/intlayer/commits) | Квітень 2024 | [](https://www.npmjs.com/package/intlayer) | [](https://www.npmjs.com/package/intlayer) |
|
|
43
|
+
| `lingui/js-lingui` | [](https://github.com/lingui/js-lingui/stargazers) | [](https://github.com/lingui/js-lingui/commits) | [](https://github.com/lingui/js-lingui/commits) | Грудень 2016 | [](https://www.npmjs.com/package/@lingui/core) | [](https://www.npmjs.com/package/@lingui/core) |
|
|
44
|
+
|
|
45
|
+
> Значки оновлюються автоматично. Показники змінюються з часом.
|
|
46
|
+
|
|
47
|
+
## Порівняння функціональності
|
|
48
|
+
|
|
49
|
+
| Функція | Intlayer (`react-intlayer` / `next-intlayer`) | Lingui (`@lingui/core` / `@lingui/react`) |
|
|
50
|
+
| --------------------------------------------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
51
|
+
| **Переклади поруч із компонентами** | ✅ Так, `.content.ts` розташований поруч із кожним компонентом | ⚠️ Вихідні рядки всередині JSX через макроси; переклади у централізованих каталогах `.po` |
|
|
52
|
+
| **Інтеграція з TypeScript** | ✅ Суворі типи генеруються автоматично з контенту | ⚠️ Макроси типізовані; ідентифікатори повідомлень ні, відсутні записи в каталозі не виявляються |
|
|
53
|
+
| **Виявлення відсутніх перекладів** | ✅ Помилка TypeScript + помилка/попередження під час збирання | ⚠️ `lingui extract` показує статистику; під час виконання повертається вихідний рядок |
|
|
54
|
+
| **Багатий контент (JSX / Markdown / компоненти)** | ✅ Пряма підтримка | ✅ `<Trans>` із вкладеними компонентами |
|
|
55
|
+
| **Підтримка ICU** | ⚠️ У розробці | ✅ Так (макроси `plural`, `select`, `selectOrdinal`) |
|
|
56
|
+
| **Форматування (дати, числа, валюти)** | ✅ `useNumber`, `useDate`, ... (Intl під капотом) | ✅ `i18n.date()`, `i18n.number()` |
|
|
57
|
+
| **Локалізована маршрутизація та middleware** | ✅ Вбудований проксі/middleware, `getMultilingualUrls` | ❌ Не є частиною ядра |
|
|
58
|
+
| **SEO-помічники (hreflang, sitemap, robots)** | ✅ Вбудовані інструменти | ❌ Вручну |
|
|
59
|
+
| **Синхронні серверні компоненти** | ✅ `useIntlayer` з `next-intlayer/server` працює у будь-якому дочірньому компоненті | ⚠️ Потрібен екземпляр `I18n` для кожного запиту, який передається або задається через `setI18n` |
|
|
60
|
+
| **Tree-shaking (відправка лише потрібного вмісту)** | ✅ Для кожного компонента та локалі, автоматизовано компілятором | ⚠️ Для кожної локалі через `lingui compile`; для кожного маршруту потрібен ручний поділ |
|
|
61
|
+
| **Ліниве завантаження (Lazy loading)** | ✅ `importMode: 'dynamic'` (один рядок конфігурації) | ⚠️ Ручний `import()` скомпільованих каталогів + `i18n.load()` / `i18n.activate()` |
|
|
62
|
+
| **Очищення невикористаного контенту** | ✅ Невикористані словники видаляються під час збирання | ✅ `lingui extract --clean` видаляє застарілі повідомлення |
|
|
63
|
+
| **Тестування відсутніх перекладів (CLI / CI)** | ✅ `npx intlayer content test` | ⚠️ Статистика `lingui extract` (за замовчуванням немає коду помилки завершення) |
|
|
64
|
+
| **Конвеєр збирання (Build pipeline)** | ✅ Один плагін (`@intlayer/swc` / `@intlayer/babel` / `vite-intlayer`) | ⚠️ Плагін макросів (Babel або SWC) + кроки `extract` + `compile` |
|
|
65
|
+
| **Переклад за допомогою ШІ** | ✅ Вбудовано, використовує ваші власні ключі постачальників | ❌ Немає |
|
|
66
|
+
| **Візуальний редактор / CMS** | ✅ Безкоштовний Візуальний редактор + додаткова CMS | ❌ Немає (`.po` працює із зовнішніми системами TMS) |
|
|
67
|
+
| **Сервер MCP та навички агентів (Agent Skills)** | ✅ Так | ❌ Немає |
|
|
68
|
+
| **Екосистема / спільнота** | ⚠️ Менша, але стрімко зростає | ✅ Добре зарекомендована, універсальна |
|
|
69
|
+
|
|
70
|
+
## Бенчмарк
|
|
71
|
+
|
|
72
|
+
### Що вимірювалося
|
|
73
|
+
|
|
74
|
+
Набір тестів [Benchmark Bloom](https://github.com/intlayer-org/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`. Кожна бібліотека реалізована у чотирьох **стратегіях завантаження**, від найпростішої конфігурації до оптимальної:
|
|
75
|
+
|
|
76
|
+
| Стратегія | Опис | Хто це використовує |
|
|
77
|
+
| ------------------ | ------------------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
78
|
+
| **static** | Скомпільований каталог кожної локалі імпортується та завантажується заздалегідь | Швидкі прототипи, код, згенерований ШІ |
|
|
79
|
+
| **dynamic** | Тільки каталог активної локалі імпортується через `import()`, але він містить усі сторінки | Більшість проєктів |
|
|
80
|
+
| **scoped-static** | Один каталог на маршрут, усі запаковані заздалегідь | Рідко |
|
|
81
|
+
| **scoped-dynamic** | Один каталог на маршрут + лінивий `import()`. Тільки поточна сторінка та локаль | Додатки з суворим бюджетом продуктивності |
|
|
82
|
+
|
|
83
|
+
Intlayer не має варіанта "scoped": компілятор автоматично обмежує контекст контенту **для кожного компонента**, тому його рядки `static` і `dynamic` вже оптимізовані за маршрутами.
|
|
84
|
+
|
|
85
|
+
Для кожного збирання тестовий набір фіксує:
|
|
86
|
+
|
|
87
|
+
- **Розмір бібліотеки (Lib size)**: розмір gzip порожнього компонента, який імпортує лише бібліотеку i18n. Постійні витрати runtime.
|
|
88
|
+
- **JS сторінки (Page JS)**: стиснутий gzip JavaScript, що завантажується на сторінку, усереднений для всіх сторінок і локалей.
|
|
89
|
+
- **% витоку локалі (Locale leak %)**: частка перекладених рядків у завантаженому JS, які належать локалі, яку користувач **не** переглядає (протестовано на `en` і `fr`, тому 50% означає повну присутність іншої вимірюваної мови; при 10 запакованих локалях реальні зайві витрати набагато більші).
|
|
90
|
+
- **% витоку сторінки (Page leak %)**: частка перекладених рядків у завантаженому JS, які належать сторінці, на якій користувач **не** перебуває.
|
|
91
|
+
- **Середній розмір компонента (Component avg)**: середній розмір gzip кожного компонента, скомпільованого окремо. Показує, скільки runtime та каталогів тягне за собою один компонент.
|
|
92
|
+
- **Реактивність E2E**: час між вибором нової локалі та оновленням `html[lang]` у DOM (Playwright, 5 ітерацій).
|
|
93
|
+
- **Гідратація**: тривалість фази гідратації React.
|
|
94
|
+
|
|
95
|
+
> Наведені нижче дані отримані під час тестування від **2026-09-12** з `@lingui/react` 6.6.0 та `intlayer` 9.5.1. Тестовий додаток навмисно невеликий (кілька десятків рядків на локаль), тому відсотки витоку описують **закономірність**: вони збільшуються разом зі зростанням вашого контенту, тоді як витрати runtime залишаються фіксованими.
|
|
96
|
+
|
|
97
|
+
### Результати на Next.js
|
|
98
|
+
|
|
99
|
+
| Бібліотека | Стратегія | Розмір Lib (gz) | Сер. JS сторінки (gz) | Витік локалі | Витік сторінки | Сер. компонента (gz) | Реактивність E2E | Гідратація |
|
|
100
|
+
| ------------------- | -------------- | --------------: | --------------------: | -----------: | -------------: | -------------------: | ---------------: | ---------: |
|
|
101
|
+
| **base** (без i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
|
|
102
|
+
| Lingui | static | 11.9 KB | 207.4 KB | 50.0% | 90.0% | 73.3 KB | 15.3 ms | 15.2 ms |
|
|
103
|
+
| Lingui | dynamic | 11.9 KB | 145.4 KB | 2.8% | 89.9% | 19.9 KB | 15.7 ms | 12.7 ms |
|
|
104
|
+
| Lingui | scoped-static | 11.9 KB | 148.2 KB | 2.7% | 89.1% | 20.4 KB | 15.1 ms | 13.1 ms |
|
|
105
|
+
| Lingui | scoped-dynamic | 11.9 KB | 148.6 KB | 14.8% | 0.0% | 152.6 KB | 16.1 ms | 14.8 ms |
|
|
106
|
+
| **`next-intlayer`** | static | **5.5 KB** | **141.3 KB** | **0.0%** | **0.0%** | **8.5 KB** | **15.5 ms** | 16.9 ms |
|
|
107
|
+
| **`next-intlayer`** | dynamic | **5.5 KB** | **141.3 KB** | **0.0%** | **0.0%** | **6.9 KB** | **15.3 ms** | 15.9 ms |
|
|
108
|
+
|
|
109
|
+
**Як інтерпретувати результати**
|
|
110
|
+
|
|
111
|
+
- **Витрати runtime.** Порожній компонент важить 11.9 КБ gzip з Lingui і 5.5 КБ з Intlayer. На повній сторінці найкраща конфігурація Lingui дає **+7.3 КБ** у порівнянні з Intlayer (148.6 проти 141.3 КБ); Intlayer додає лише **+0.3 КБ** до базового додатка без i18n.
|
|
112
|
+
- **Проста конфігурація коштує дорого.** Попереднє завантаження всіх скомпільованих каталогів дає **207.4 КБ на сторінку**, що на +66 КБ більше за базовий додаток. Половина виявлених рядків належить до іншої локалі, а 90% - до інших сторінок.
|
|
113
|
+
- **Динамічне завантаження вирішує проблему локалі, але не сторінки.** З одним каталогом на локаль витік сторінки залишається на рівні ~90%: весь каталог `fr` завантажується на кожній французькій сторінці. Щоб досягти 0% витоку сторінки, потрібна конфігурація `scoped-dynamic`: окремий каталог для кожного маршруту, який створюється та підключається вручну.
|
|
114
|
+
- **Витік резервної мови (fallback).** Навіть в оптимізованих конфігураціях **3-15% рядків `en` потрапляють на сторінки `fr`**. Макроси Lingui зберігають початкове повідомлення як fallback, через що воно потрапляє у бандл поруч із перекладом. Intlayer розв'язує резервні переклади під час збирання та надсилає виключно активну мову.
|
|
115
|
+
- **Розмір компонента різко зростає у `scoped-dynamic`.** Кожен компонент, скомпільований окремо, важить у середньому **152.6 КБ**, оскільки каталог кожного маршруту стає доступним із компонента, який його імпортує. Той самий компонент з `useIntlayer()` важить у середньому **6.9 КБ**.
|
|
116
|
+
|
|
117
|
+
### Результати на TanStack Start
|
|
118
|
+
|
|
119
|
+
| Бібліотека | Стратегія | Розмір Lib (gz) | Сер. JS сторінки (gz) | Витік локалі | Витік сторінки | Сер. компонента (gz) | Реактивність E2E | Гідратація |
|
|
120
|
+
| ---------------------------- | -------------- | --------------: | --------------------: | -----------: | -------------: | -------------------: | ---------------: | ---------: |
|
|
121
|
+
| **base** (без i18n) | - | 0.0 KB | 111.0 KB | 0.0% | 0.0% | 0.7 KB | 8.1 ms | 21.6 ms |
|
|
122
|
+
| Lingui | static | 11.2 KB | 152.2 KB | 50.0% | 90.0% | 58.0 KB | 3.9 ms | 19.9 ms |
|
|
123
|
+
| Lingui | dynamic | 11.2 KB | 115.2 KB | 9.3% | 0.0% | 85.5 KB | 5.9 ms | 28.0 ms |
|
|
124
|
+
| Lingui | scoped-static | 11.2 KB | 120.8 KB | 4.0% | 0.0% | 147.9 KB | 7.1 ms | 33.9 ms |
|
|
125
|
+
| Lingui | scoped-dynamic | 11.2 KB | 120.2 KB | 8.6% | 0.0% | 83.7 KB | 42.1 ms | 32.9 ms |
|
|
126
|
+
| **`intlayer`** | static | **5.0 KB** | **125.8 KB** | 50.0% | **0.0%** | **8.1 KB** | **3.2 ms** | 11.5 ms |
|
|
127
|
+
| **`intlayer`** | dynamic | **5.0 KB** | **118.6 KB** | **0.0%** | **0.0%** | **6.3 KB** | **3.6 ms** | 14.1 ms |
|
|
128
|
+
| `@intlayer/lingui` (сумісн.) | dynamic | 10.3 KB | 137.0 KB | 9.9% | 0.0% | 12.8 KB | 2.9 ms | 19.7 ms |
|
|
129
|
+
|
|
130
|
+
**Як інтерпретувати результати**
|
|
131
|
+
|
|
132
|
+
- **За обсягом JavaScript на сторінку Lingui перемагає з мінімальним відривом.** `dynamic` Lingui досягає **115.2 КБ**, що на 3.4 КБ менше за Intlayer (118.6 КБ). Скомпільовані каталоги Lingui з хешованими ідентифікаторами дуже компактні, а маршрутизатор TanStack Start настільки добре ділить код, що витік сторінки становить 0% уже в рядку `dynamic`.
|
|
133
|
+
- **Усі інші показники свідчать на користь Intlayer.** Гідратація займає **28-34 мс** у Lingui проти **11-14 мс** у Intlayer: `i18n.load()` + `i18n.activate()` запускаються на клієнті до того, як React зможе завершити гідратацію. Компоненти, скомпільовані ізольовано, важать **58-148 КБ** проти **6-8 КБ**. Витік локалі ніколи не опускається до 0% (становить 4-9%) через наявність рядків вихідної мови.
|
|
134
|
+
- **Перемикання локалі в оптимізованій конфігурації відбувається повільно.** `scoped-dynamic` Lingui потребує **42 мс** для оновлення `html[lang]`: каталог нового маршруту необхідно завантажити та активувати до того, як зміна стане помітною. Intlayer перемикається за **3-4 мс** в обох режимах.
|
|
135
|
+
- **Рядок `static` в Intlayer вже має 0% витоку сторінки**, оскільки до бандла потрапляють лише словники, імпортовані компонентами поточної сторінки. Один рядок конфігурації (`importMode: 'dynamic'`) повністю прибирає і витік локалі.
|
|
136
|
+
- **`@intlayer/lingui`** зберігає синтаксис макросів Lingui та обслуговує їх зі словників Intlayer. Це дещо збільшує розмір сторінки (137 КБ через наявність runtime макросів) заради зменшення розміру компонентів (12.8 КБ) та швидшої гідратації, ніж у нативному Lingui. Це чудовий крок для поступової міграції.
|
|
137
|
+
|
|
138
|
+
## Чому виникає ця різниця? Два компілятори, дві одиниці роботи
|
|
139
|
+
|
|
140
|
+
Обидві бібліотеки виконують компіляцію. Різниця полягає в тому, **що** саме вони компілюють.
|
|
141
|
+
|
|
142
|
+
**Lingui компілює каталоги.** Макроси у вашому вихідному коді вилучаються у файл `.po` для кожної локалі, а потім компілюються в модуль JS для кожної локалі. Одиницею роботи є **локаль**. Подальший поділ за маршрутами чи компонентами означає створення багатьох каталогів, налаштування `lingui.config.ts` та ручне підключення потрібного каталогу на кожному маршруті. Екземпляр `I18n` є глобальним; кожен виклик `useLingui()` підписує компонент на нього.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
.
|
|
146
|
+
├── lingui.config.ts
|
|
147
|
+
└── src
|
|
148
|
+
├── i18n.ts # setupI18n(), load(), activate()
|
|
149
|
+
├── locales
|
|
150
|
+
│ ├── en
|
|
151
|
+
│ │ ├── messages.po
|
|
152
|
+
│ │ └── messages.mjs # вихідний результат lingui compile
|
|
153
|
+
│ └── fr
|
|
154
|
+
│ ├── messages.po
|
|
155
|
+
│ └── messages.mjs
|
|
156
|
+
├── components
|
|
157
|
+
│ └── Counter.tsx # const { t } = useLingui(); t`Increment`
|
|
158
|
+
└── routes
|
|
159
|
+
└── $locale
|
|
160
|
+
└── about.tsx # await import(`../locales/${locale}/messages.mjs`)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Intlayer компілює словники.** Кожен файл `.content.ts` - це словник, прив'язаний до певного ключа; компілятор визначає, який компонент імпортує цей ключ, і генерує для кожного словника та локалі саме той фрагмент JSON, який потрібен цьому компоненту. Одиницею роботи є **компонент**. Прив'язка до маршруту є природним наслідком: сторінка підтягує лише словники тих компонентів, які вона реально рендерить.
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
.
|
|
167
|
+
├── intlayer.config.ts
|
|
168
|
+
└── src
|
|
169
|
+
├── components
|
|
170
|
+
│ └── Counter
|
|
171
|
+
│ ├── index.tsx # useIntlayer("counter")
|
|
172
|
+
│ └── index.content.ts
|
|
173
|
+
└── routes
|
|
174
|
+
└── $locale
|
|
175
|
+
├── about.tsx
|
|
176
|
+
└── about.content.ts
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Ось чому патерн `scoped-dynamic` є автоматичним результатом збирання для Intlayer і складним ручним конфігураційним проєктом для Lingui.
|
|
180
|
+
|
|
181
|
+
> Щоб отримати показники рядка `dynamic`, встановіть `dictionary.importMode: 'dynamic'` у `intlayer.config.ts`. Дивіться [документацію з оптимізації бандла](https://intlayer.org/uk/doc/concept/bundle-optimization).
|
|
182
|
+
|
|
183
|
+
## Досвід розробника
|
|
184
|
+
|
|
185
|
+
### Налаштування
|
|
186
|
+
|
|
187
|
+
**Lingui**
|
|
188
|
+
|
|
189
|
+
```ts fileName="lingui.config.ts"
|
|
190
|
+
import { defineConfig } from "@lingui/cli";
|
|
191
|
+
|
|
192
|
+
export default defineConfig({
|
|
193
|
+
sourceLocale: "en",
|
|
194
|
+
locales: ["en", "fr"],
|
|
195
|
+
catalogs: [
|
|
196
|
+
{
|
|
197
|
+
path: "<rootDir>/src/locales/{locale}/messages",
|
|
198
|
+
include: ["src"],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
```ts fileName="src/i18n.ts"
|
|
205
|
+
import { setupI18n } from "@lingui/core";
|
|
206
|
+
|
|
207
|
+
export const loadCatalog = async (locale: string) => {
|
|
208
|
+
const { messages } = await import(`./locales/${locale}/messages.mjs`);
|
|
209
|
+
const i18n = setupI18n();
|
|
210
|
+
i18n.load(locale, messages);
|
|
211
|
+
i18n.activate(locale);
|
|
212
|
+
return i18n;
|
|
213
|
+
};
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Потім додайте `@lingui/babel-plugin-lingui-macro` (або `@lingui/swc-plugin`) до бандлера, запускайте `lingui extract` після редагування коду, `lingui compile` перед збиранням і оберніть дерево компонентів у `<I18nProvider i18n={i18n}>`.
|
|
217
|
+
|
|
218
|
+
**Intlayer**
|
|
219
|
+
|
|
220
|
+
```ts fileName="intlayer.config.ts"
|
|
221
|
+
import { type IntlayerConfig, Locales } from "intlayer";
|
|
222
|
+
|
|
223
|
+
const config: IntlayerConfig = {
|
|
224
|
+
internationalization: {
|
|
225
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
226
|
+
defaultLocale: Locales.ENGLISH,
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export default config;
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Додайте `intlayer()` до `vite.config.ts` (або `withIntlayer()` до `next.config.ts`) та оберніть дерево в `<IntlayerProvider>`. Жодних кроків extract чи compile: словники створюються автоматично під час роботи бандлера.
|
|
234
|
+
|
|
235
|
+
### Компонент
|
|
236
|
+
|
|
237
|
+
**Lingui**
|
|
238
|
+
|
|
239
|
+
```tsx fileName="src/components/Counter.tsx"
|
|
240
|
+
import { useState } from "react";
|
|
241
|
+
import { useLingui } from "@lingui/react/macro";
|
|
242
|
+
import { Trans } from "@lingui/react/macro";
|
|
243
|
+
|
|
244
|
+
export const Counter = () => {
|
|
245
|
+
const { t, i18n } = useLingui();
|
|
246
|
+
const [count, setCount] = useState(0);
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<div>
|
|
250
|
+
<p>{i18n.number(count)}</p>
|
|
251
|
+
<button aria-label={t`Counter`} onClick={() => setCount((c) => c + 1)}>
|
|
252
|
+
<Trans>Increment</Trans>
|
|
253
|
+
</button>
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
};
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Англійський текст міститься безпосередньо в компоненті; французький зберігається у файлі `src/locales/fr/messages.po` під хешованим ідентифікатором після запуску `lingui extract`. Якщо забути виконати цю команду або `compile`, застосунок непомітно повернеться до англійського тексту.
|
|
260
|
+
|
|
261
|
+
**Intlayer**
|
|
262
|
+
|
|
263
|
+
```ts fileName="src/components/Counter/index.content.ts"
|
|
264
|
+
import { t, type Dictionary } from "intlayer";
|
|
265
|
+
|
|
266
|
+
const counterContent = {
|
|
267
|
+
key: "counter",
|
|
268
|
+
content: {
|
|
269
|
+
label: t({ en: "Counter", fr: "Compteur" }),
|
|
270
|
+
increment: t({ en: "Increment", fr: "Incrémenter" }),
|
|
271
|
+
},
|
|
272
|
+
} satisfies Dictionary;
|
|
273
|
+
|
|
274
|
+
export default counterContent;
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```tsx fileName="src/components/Counter/index.tsx"
|
|
278
|
+
import { useState } from "react";
|
|
279
|
+
import { useIntlayer } from "react-intlayer";
|
|
280
|
+
import { useNumber } from "react-intlayer/format";
|
|
281
|
+
|
|
282
|
+
export const Counter = () => {
|
|
283
|
+
const { label, increment } = useIntlayer("counter");
|
|
284
|
+
const number = useNumber();
|
|
285
|
+
const [count, setCount] = useState(0);
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<div>
|
|
289
|
+
<p>{number(count)}</p>
|
|
290
|
+
<button aria-label={label} onClick={() => setCount((c) => c + 1)}>
|
|
291
|
+
{increment}
|
|
292
|
+
</button>
|
|
293
|
+
</div>
|
|
294
|
+
);
|
|
295
|
+
};
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Обидві локалі зберігаються в одному файлі поруч із компонентом. Відсутнє значення `fr` спричиняє помилку під час збирання, а невірний ключ призводить до помилки TypeScript.
|
|
299
|
+
|
|
300
|
+
### За межами компонентів
|
|
301
|
+
|
|
302
|
+
Метадані, завантажувачі (loaders), серверні функції: будь-яке місце без дерева React.
|
|
303
|
+
|
|
304
|
+
**Lingui**
|
|
305
|
+
|
|
306
|
+
```ts fileName="src/routes/$locale/about.tsx"
|
|
307
|
+
import { setupI18n } from "@lingui/core";
|
|
308
|
+
import { msg } from "@lingui/core/macro";
|
|
309
|
+
|
|
310
|
+
const title = msg`About us`;
|
|
311
|
+
|
|
312
|
+
export const loader = async ({ params }: { params: { locale: string } }) => {
|
|
313
|
+
const { messages } = await import(
|
|
314
|
+
`../../locales/${params.locale}/messages.mjs`
|
|
315
|
+
);
|
|
316
|
+
const i18n = setupI18n({
|
|
317
|
+
locale: params.locale,
|
|
318
|
+
messages: { [params.locale]: messages },
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
return { title: i18n._(title) };
|
|
322
|
+
};
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Створення нового екземпляра `I18n` для кожного виклику, завантаження потрібного каталогу вручну та використання `msg` + `i18n._()` замість `t`. Як зазначено в [примітках до бенчмарку](https://github.com/intlayer-org/benchmark-bloom/blob/main/report/NOTE.md), розуміння того, коли саме використовувати `t`, `` t` ` ``, `i18n.t()`, `msg` або `<Trans>`, часто не є інтуїтивним.
|
|
326
|
+
|
|
327
|
+
**Intlayer**
|
|
328
|
+
|
|
329
|
+
```ts fileName="src/routes/$locale/about.tsx"
|
|
330
|
+
import { getIntlayer } from "intlayer";
|
|
331
|
+
|
|
332
|
+
export const loader = async ({ params }: { params: { locale: string } }) => {
|
|
333
|
+
const { title } = getIntlayer("about-metadata", params.locale);
|
|
334
|
+
|
|
335
|
+
return { title };
|
|
336
|
+
};
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
## Збережіть макроси Lingui, отримайте словники Intlayer
|
|
340
|
+
|
|
341
|
+
`@intlayer/lingui` - це сумісний адаптер для `@lingui/core` та `@lingui/react`. Макроси продовжують компілюватися як і раніше; виклики `i18n._()`, у які вони перетворюються, обслуговуються зі словників Intlayer, а плагіни синхронізації `.po` зберігають ваші чинні каталоги як єдине джерело правди. Форми множини та селектори ICU відображаються повністю ідентично.
|
|
342
|
+
|
|
343
|
+
```ts fileName="vite.config.ts"
|
|
344
|
+
import { defineConfig } from "vite";
|
|
345
|
+
import { lingui } from "@intlayer/lingui/plugin";
|
|
346
|
+
|
|
347
|
+
export default defineConfig({
|
|
348
|
+
plugins: [lingui()],
|
|
349
|
+
});
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Збережіть плагін `@lingui/babel-plugin-lingui-macro` / `@lingui/swc-plugin` у процесі збирання перед компілятором Intlayer. Дивіться [документацію щодо сумісності з Lingui](https://intlayer.org/uk/doc/compatibility/lingui).
|
|
353
|
+
|
|
354
|
+
## Що і коли обрати?
|
|
355
|
+
|
|
356
|
+
- **Обирайте Lingui**, якщо вам потрібен **ICU MessageFormat** із типізованими макросами, ваші перекладачі працюють з файлами **`.po`** в межах наявної системи TMS, ви віддаєте перевагу вбудованим вихідним рядкам безпосередньо в JSX, а ваша команда звикла керувати процесом вилучення, компіляції та розділення каталогів. Розмір JS на сторінку дуже конкурентний після налаштування лінивого завантаження.
|
|
357
|
+
- **Обирайте Intlayer**, якщо вам потрібен **контент з прив'язкою до компонентів**, **суворий TypeScript**, **помилки про відсутні ключі під час збирання**, **автоматичний tree-shaking та ліниве завантаження без конфігурації**, компактні компоненти, швидка гідратація, миттєве перемикання локалей та вбудовані редакційні інструменти (Візуальний редактор, CMS, переклад за допомогою ШІ, сервер MCP).
|
|
358
|
+
- **Обирайте `@intlayer/lingui`**, якщо ви вже використовуєте Lingui і прагнете поступово перейти на словники Intlayer без зміни макросів.
|
|
359
|
+
|
|
360
|
+
## Схожі порівняння
|
|
361
|
+
|
|
362
|
+
- [next-intl проти Intlayer](https://intlayer.org/uk/blog/next-intl-vs-intlayer) (той самий бенчмарк)
|
|
363
|
+
- [i18next проти Intlayer](https://intlayer.org/uk/blog/i18next-vs-intlayer) (той самий бенчмарк)
|
|
364
|
+
- [Бенчмарк vue-i18n проти Intlayer](https://intlayer.org/uk/blog/vue-i18n-vs-intlayer-benchmark) (той самий бенчмарк)
|
|
365
|
+
- [Компілятор проти декларативного i18n](https://intlayer.org/uk/blog/compiler-vs-declarative-i18n)
|
|
366
|
+
|
|
367
|
+
## Зірки GitHub
|
|
368
|
+
|
|
369
|
+
Зірки на GitHub є вагомим показником популярності проєкту, довіри спільноти та його довгострокової актуальності. Хоча вони не є прямою оцінкою технічної досконалості, вони відображають, скільки розробників вважають проєкт корисним і стежать за його розвитком.
|
|
370
|
+
|
|
371
|
+
[](https://star-history.com/#lingui/js-lingui&aymericzip/intlayer)
|
|
372
|
+
|
|
373
|
+
## Висновок
|
|
374
|
+
|
|
375
|
+
Lingui є найпотужнішою комбінованою бібліотекою (runtime + компілятор) у цьому бенчмарку. Її скомпільовані хешовані каталоги забезпечують обсяг JavaScript на сторінку лише на кілька кілобайтів більший, ніж у Intlayer, а на TanStack Start навіть дещо менший. Якби розмір сторінки був єдиною метрикою, це була б нічия.
|
|
376
|
+
|
|
377
|
+
Але це не так. Компілятор Lingui зупиняється на межі цілої локалі; все, що нижче (каталоги для кожного маршруту, ліниве завантаження, виключення резервної мови з бандла), вимагає ручного налаштування. Бенчмарк демонструє наслідки цього обмеження: компоненти **у 10-20 разів більші**, гідратація **у 2-3 рази повільніша**, **3-15% витоку локалі**, якого неможливо позбутися, і перемикання локалі тривалістю **42 мс** в оптимізованому режимі. Компілятор Intlayer працює безпосередньо на рівні окремих компонентів, тому ці показники становлять **6-8 КБ**, **11-14 мс**, **0%** та **3-4 мс** без будь-яких ручних налаштувань.
|
|
378
|
+
|
|
379
|
+
Усі вихідні дані, тестові додатки та скрипти доступні у [репозиторії Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom). Ви можете запустити їх самостійно.
|
|
380
|
+
|
|
381
|
+
Зверніться до документа ['Чому Intlayer?'](https://intlayer.org/uk/doc/why) для отримання детальнішої інформації.
|
|
@@ -1473,7 +1473,7 @@ export const config = {
|
|
|
1473
1473
|
|
|
1474
1474
|
Зірки на GitHub є потужним індикатором популярності проєкту, довіри спільноти та його довгострокової значущості. Хоча це не прямий показник технічної якості, вони відображають, скільки розробників вважають проєкт корисним, стежать за його розвитком і, ймовірно, приймуть його у використання. Для оцінки цінності проєкту зірки допомагають порівнювати залученість між альтернативами та дають уявлення про зростання екосистеми.
|
|
1475
1475
|
|
|
1476
|
-
[](https://
|
|
1476
|
+
[](https://star-history.com/#i18next/next-i18next&amannn/next-intl&aymericzip/intlayer)
|
|
1477
1477
|
|
|
1478
1478
|
## Висновок
|
|
1479
1479
|
|