@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,289 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-13
|
|
3
|
+
updatedAt: 2026-09-13
|
|
4
|
+
title: "vue-i18n vs @intlayer/vue-i18n: Ten sam API, Inny Bundle"
|
|
5
|
+
description: Co się zmienia, gdy aplikacja Vue 3 zachowuje swoje wywołania vue-i18n, ale obsługuje je za pośrednictwem adaptera kompatybilności @intlayer/vue-i18n. JavaScript na stronę, rozmiar runtime, rozmiar komponentu i wyciek zmierzony na tym samym kodzie Vite + Vue, plus to, co adapter zachowuje, ignoruje i nie może zastąpić.
|
|
6
|
+
keywords:
|
|
7
|
+
- vue-i18n
|
|
8
|
+
- "@intlayer/vue-i18n"
|
|
9
|
+
- Intlayer
|
|
10
|
+
- Compat adapter
|
|
11
|
+
- Migration
|
|
12
|
+
- Internationalization
|
|
13
|
+
- i18n
|
|
14
|
+
- Benchmark
|
|
15
|
+
- Bundle size
|
|
16
|
+
- Blog
|
|
17
|
+
- Vue
|
|
18
|
+
- Nuxt
|
|
19
|
+
- Vite
|
|
20
|
+
slugs:
|
|
21
|
+
- blog
|
|
22
|
+
- vue-i18n-vs-intlayer-vue-i18n
|
|
23
|
+
author: aymericzip
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# vue-i18n VS @intlayer/vue-i18n | Ten sam API, Inny Bundle
|
|
27
|
+
|
|
28
|
+
`@intlayer/vue-i18n` to adapter kompatybilności: ujawnia API `vue-i18n` (`createI18n`, `useI18n`, `t()`, `d()`, `n()`, `$t`, `v-t`, `i18n.global.locale`...) i serwuje go ze słowników skompilowanych przez Intlayer. Twoje pliki `.vue` się nie zmieniają. Zmienia się to, do czego `t("footer.github")` jest związane.
|
|
29
|
+
|
|
30
|
+
Artykuł ten mierzy tę wymianę na tej samej aplikacji Vite + Vue 3, zbudowanej raz z `vue-i18n` i raz z adapterem. Liczby pochodzą z [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom). Aby porównać `vue-i18n` i Intlayer jako biblioteki, przeczytaj [vue-i18n vs Intlayer](https://intlayer.org/blog/vue-i18n-vs-intlayer) i [porównanie wydajności vue-i18n vs Intlayer](https://intlayer.org/blog/vue-i18n-vs-intlayer-benchmark). Ten artykuł dotyczy tego, co adapter zmienia, gdy zachowujesz swoje komponenty takie, jakie są.
|
|
31
|
+
|
|
32
|
+
<TOC/>
|
|
33
|
+
|
|
34
|
+
> **tl;dr**: Na tej samej aplikacji Vite + Vue 3, zastąpienie `vue-i18n` przez `@intlayer/vue-i18n` zmniejszyło JavaScript na stronę z **134.9 KB na 47.0 KB** gzip (aplikacja bez i18n waży 41.3 KB), runtime z **24.3 KB na 7.9 KB**, średni komponent z **196 KB na 8.4 KB**, i wyciek stringów z obcych stron z **90% na 0%**, bez edycji któregokolwiek pliku `.vue`. `createI18n({ messages })` pozostaje funkcjonalne jako fallback; usuń importy JSON, aby uzyskać wymienione wyżej liczby. Bloki SFC `<i18n>` i runtime `setLocaleMessage()` to dwie funkcje, które się nie przenoszą.
|
|
35
|
+
|
|
36
|
+
## Co to jest `@intlayer/vue-i18n`
|
|
37
|
+
|
|
38
|
+
`vue-i18n` to runtime. `createI18n({ messages: { en, fr, ... } })` buduje globalną instancję zawierającą każdą wiadomość każdej lokalizacji; `useI18n()` wiąże każdy komponent z nią; `t("footer.github")` przechodzi po drzewie w czasie renderowania. Ten projekt sprawia, że bloki SFC `<i18n>` i `setLocaleMessage()` są możliwe, i jest to również powód, dla którego graf zależności każdego komponentu obejmuje całe drzewo.
|
|
39
|
+
|
|
40
|
+
`@intlayer/vue-i18n` zachowuje API i zastępuje drzewo:
|
|
41
|
+
|
|
42
|
+
1. **Import aliasing.** `vueI18nVitePlugin()` z `@intlayer/vue-i18n/plugin` opakowuje `vite-intlayer` i dodaje `resolve.alias`, aby `vue-i18n` rozwiązywał się do `@intlayer/vue-i18n`. Żaden import nie jest zmieniam.
|
|
43
|
+
2. **JSON jako źródło prawdy.** Plugin `syncJSON` odczytuje istniejący plik `locales/{locale}.json` z `format: "vue-i18n"` (dzięki czemu `{name}`, `{0}` interpolacja listy i `"car | cars"` plurale z pipe są prawidłowo parsowane) i zapisuje tłumaczenia z powrotem, gdy CLI lub CMS je aktualizuje.
|
|
44
|
+
3. **Call-site binding.** Passe optymalizacji Intlayer przepisuje miejsca wywołania `useI18n()` tak, aby komponent otrzymywał słowniki dla swoich kluczy w aktywnym ustawieniu regionalnym, jako imporyt, które bundler może śledzić i dzielić.
|
|
45
|
+
|
|
46
|
+
```vue fileName="src/components/Footer.vue"
|
|
47
|
+
<!-- Twój kod, bez zmian -->
|
|
48
|
+
<script setup lang="ts">
|
|
49
|
+
import { useI18n } from "vue-i18n";
|
|
50
|
+
|
|
51
|
+
const { t } = useI18n();
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<a href="https://github.com/intlayer-org/benchmark-bloom">{{
|
|
56
|
+
t("footer.github")
|
|
57
|
+
}}</a>
|
|
58
|
+
</template>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```ts fileName="Co emituje kompilator (uproszczone)"
|
|
62
|
+
import _dicHash_footer from "../.intlayer/dictionaries/footer.mjs";
|
|
63
|
+
import { useDictionary as useI18n } from "@intlayer/vue-i18n";
|
|
64
|
+
|
|
65
|
+
// Komponent nie ma już dostępu do globalnego drzewa wiadomości. Dotyka tylko `footer`.
|
|
66
|
+
const { t } = useI18n(_dicHash_footer);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Komponent nie ma już dostępu do globalnego drzewa wiadomości. Dotyka tylko `footer`. Dlatego kolumna rozmiaru komponentu poniżej spada z 196 KB do 8 KB.
|
|
70
|
+
|
|
71
|
+
## Co adapter zachowuje, ignoruje i nie zastępuje
|
|
72
|
+
|
|
73
|
+
| API `vue-i18n` | Z `@intlayer/vue-i18n` |
|
|
74
|
+
| ------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `useI18n()` → `{ t, d, n, te, tm, rt, locale, availableLocales }` | ✅ Zachowane. Klucze `t` są typowane względem Twoich słowników |
|
|
76
|
+
| `t("key", { name })`, `t("key", [a, b])`, `t("key", count)` | ✅ Zachowane. `{name}`, `{0}` i plurale rozdzielone znakiem pipe rozpoznawane jak poprzednio |
|
|
77
|
+
| `d(date, "long")`, `n(value, "currency")` | ✅ Zachowane. `datetimeFormats` / `numberFormats` z `createI18n()` są honorowane, wspierane przez natywny `Intl` |
|
|
78
|
+
| `i18n.global.locale.value = "fr"` | ✅ Zachowane. Pisana `WritableComputedRef` wspierana przez klienta Intlayer; reaktywność zachowuje się jak wcześniej |
|
|
79
|
+
| `$t`, `$tc`, `$te`, `$tm`, `$rt`, `$d`, `$n`, `$i18n` (Options API) | ✅ Zachowane. Zarejestrowane na `app.config.globalProperties` przez `app.use(i18n)` |
|
|
80
|
+
| `v-t` directive | ✅ Zachowane |
|
|
81
|
+
| `legacy: true` | ✅ Akceptowane |
|
|
82
|
+
| `createI18n({ messages })` | ⚠️ `messages` są używane jako **fallback w runtime** z ostrzeżeniem dev. Usuń importy JSON dla zmniejszenia bundla |
|
|
83
|
+
| `setLocaleMessage()`, `mergeLocaleMessage()` | ❌ Ostrzeżenie i nic się nie dzieje. Ładowanie wiadomości w runtime jest zastępowane słownikami w czasie budowania |
|
|
84
|
+
| SFC `<i18n>` custom blocks | ❌ Nie są czytane. Przenieś te wiadomości do lokalizacyjnego JSON-a (lub `.content.ts` obok komponentu) |
|
|
85
|
+
| `@nuxtjs/i18n` | ⚠️ Osobny adapter, zobacz [dokumentację kompatybilności Nuxt](https://intlayer.org/doc/compatibility/nuxtjs-i18n) |
|
|
86
|
+
|
|
87
|
+
## Benchmark
|
|
88
|
+
|
|
89
|
+
### Co zostało zmierzone
|
|
90
|
+
|
|
91
|
+
Zestawienie [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom) buduje **tę samą aplikację Vite + Vue 3** z każdą konfiguracją: **10 stron** (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), **10 lokalizacji** (`en`, `fr`, `es`, `de`, `it`, `pt`, `zh`, `ja`, `ko`, `ru`), identyczne komponenty i identyczną treść. Strony są mierzone w `en` i `fr`.
|
|
92
|
+
|
|
93
|
+
Oba zostały zbudowane w konfiguracji **static**, takiej jaką wysyła większość projektów Vue: dla `vue-i18n`, każdy JSON lokalizacji importowany i przekazywany do `createI18n({ messages })`; dla adaptera, te same komponenty z zmienionymi `vite.config.ts` i `intlayer.config.ts` oraz usuniętym importem `messages`. Native `vue-intlayer` jest zawarty jako punkt odniesienia.
|
|
94
|
+
|
|
95
|
+
Dla każdego buildu, zestaw rejestruje:
|
|
96
|
+
|
|
97
|
+
- **Lib size**: rozmiar gzip (i zminifikowany) pustego komponentu, który tylko importuje bibliotekę i18n.
|
|
98
|
+
- **Page JS**: gzip JavaScript pobrany na stronę, uśredniony dla wszystkich stron i locales.
|
|
99
|
+
- **Locale leak %**: udział przetłumaczonych stringów w pobranym JS, które należą do locale'u, którego użytkownik **nie** przegląda.
|
|
100
|
+
- **Page leak %**: udział przetłumaczonych stringów w pobranym JS, które należą do strony, na której użytkownik **nie** jest.
|
|
101
|
+
- **Component avg**: średni rozmiar gzip każdego komponentu skompilowanego w izolacji.
|
|
102
|
+
- **E2E reactivity**: czas ścienno-zegarowy między wybraniem nowego locale a aktualizacją `html[lang]` w DOM (Playwright, 5 iteracji).
|
|
103
|
+
- **Page load**: `PerformanceNavigationTiming.duration`.
|
|
104
|
+
|
|
105
|
+
> Liczby poniżej pochodzą z uruchomienia z dnia **2026-09-12** przy użyciu `vue-i18n` 11.4.0 i `@intlayer/vue-i18n` 9.5.1. Aplikacja testowa jest celowo mała (kilkadziesiąt stringów na locale), więc procenty wycieków opisują **wzorzec**: rosną wraz z Twoją zawartością, podczas gdy koszt runtime pozostaje stały.
|
|
106
|
+
|
|
107
|
+
### Wyniki na Vite + Vue 3
|
|
108
|
+
|
|
109
|
+
| Setup | Strategy | Rozmiar lib (gz) | Rozmiar lib (min) | Średni JS strony (gz) | Wyciek locale | Wyciek strony | Średnia lib komponentu (gz) | Reaktywność E2E | Ładowanie strony |
|
|
110
|
+
| ------------------------ | -------- | ---------------: | ----------------: | --------------------: | ------------: | ------------: | --------------------------: | --------------: | ---------------: |
|
|
111
|
+
| **base** (brak i18n) | - | 0.0 KB | 0.0 KB | 41.3 KB | 0.0% | - | 1.1 KB | 1.8 ms | 10.8 ms |
|
|
112
|
+
| `vue-i18n` | static | 24.3 KB | 83.2 KB | 134.9 KB | 50.0% | 90.0% | 196.0 KB | 2.8 ms | 13.6 ms |
|
|
113
|
+
| **`@intlayer/vue-i18n`** | static | **7.9 KB** | **23.2 KB** | **47.0 KB** | **15.0%** | **0.0%** | **8.4 KB** | **1.5 ms** | **9.3 ms** |
|
|
114
|
+
| `vue-intlayer` (native) | static | 3.9 KB | 11.1 KB | 57.1 KB | 56.8% | 0.0% | 7.7 KB | 4.5 ms | 13.8 ms |
|
|
115
|
+
| `vue-intlayer` (native) | dynamic | 3.9 KB | 11.1 KB | 59.8 KB | 50.0% | 0.0% | 6.5 KB | 4.0 ms | 15.8 ms |
|
|
116
|
+
|
|
117
|
+
> Kolumna page-leak aplikacji bazowej jest pusta: bez biblioteki i18n fingerprinting wybiera zakodowane na stałe ciągi w udostępnianych fragmentach i liczba nie jest znacząca.
|
|
118
|
+
|
|
119
|
+
**Jak to czytać**
|
|
120
|
+
|
|
121
|
+
- **88 KB mniej na stronę, te same komponenty.** `vue-i18n` bierze aplikację 41.3 KB do **134.9 KB**. Build adaptera z tymi samymi komponentami ląduje na **47.0 KB**, 5.7 KB powyżej aplikacji bazowej. Większość różnicy to 74.9 KB `src/locales`, które `createI18n({ messages })` ściąga na każdą stronę, a adapter nigdy nie bundluje jako blok.
|
|
122
|
+
- **Runtime zmniejsza się 3x.** Pusty komponent, który importuje tylko `vue-i18n`, kosztuje **24.3 KB gzip / 83.2 KB minified**: `@intlify/core-base`, compiler wiadomości i runtime. Adapter kosztuje **7.9 KB / 23.2 KB**, większość z tego to core Intlayera plus powierzchnia API `vue-i18n`.
|
|
123
|
+
- **Komponenty: 23x mniejsze.** Komponent `useI18n()` skompilowany w izolacji średnio ważyć **196 KB**, ponieważ `t` jest powiązany z instancją, która przechowuje każdą wiadomość każdej lokalizacji. Z adapterem ten sam komponent ważyć średnio **8.4 KB**: osiąga własny słownik.
|
|
124
|
+
- **Wyciek danych.** `vue-i18n` wysyła każdą locale i stringi każdej strony na każdej stronie: 50% wyciek locale (na dwóch identyfikowanych locale; z dziesięcioma bundlowanymi locale rzeczywiste marnotrawstwo jest wyższe), 90% wyciek strony. Adapter zmniejsza wyciek strony do **0%**, ponieważ każdy komponent importuje tylko swoje słowniki. Wyciek locale wynosi 15% w tym przebiegu `static`; `importMode: 'dynamic'` to ustawienie, które go usuwa, a ta konfiguracja nie była częścią tego przebiegu Vue.
|
|
125
|
+
- **Reaktywność i ładowanie strony.** Przełączanie locale jest tanie dla obu (1,5-2,8 ms); system reaktywności Vue sprawia, że tak jest, gdy wiadomości są w pamięci. Ładowanie strony zmienia się z 13,6 ms na **9,3 ms**, zgodnie z 88 KB mniej JavaScriptu do analizy.
|
|
126
|
+
- **O natywnych wierszach.** `vue-intlayer` w tym uruchomieniu zawierał każdą lokalizację w trybie `static` i osiągnął 57,1 KB z runtimem 3,9 KB; zsynchronizowane słowniki adaptera zawierały mniej ciągów obcych lokalizacji, stąd niższa liczba na stronę. Natywny runtime pozostaje najlżejszy z trzech, a jego model `.content.ts` to miejsce, gdzie bloki SFC `<i18n>` znajdują swój odpowiednik.
|
|
127
|
+
|
|
128
|
+
## Dlaczego liczby się zmieniają
|
|
129
|
+
|
|
130
|
+
Nic w `src/components/` się nie zmieniło, więc zyski pochodzą z tego, do czego wiąże się `useI18n`.
|
|
131
|
+
|
|
132
|
+
**Za pomocą `vue-i18n`**, binding to instancja globalna. `createI18n({ messages: { en, fr, ... } })` to jeden import, który zawiera wszystko; każdy komponent, który wywołuje `useI18n()`, może uzyskać dostęp do całości, dlatego bundler nie może podzielić się poniżej instancji. Optymalizacja oznacza, że _ty_ dzielisz `en.json` po trasach, wywołujesz `setLocaleMessage()` w routerze guard, i utrzymujesz mapę trasy do pliku w miarę przenoszenia się komponentów.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
.
|
|
136
|
+
├── locales
|
|
137
|
+
│ ├── en.json # ciągi znaków każdej strony
|
|
138
|
+
│ └── fr.json
|
|
139
|
+
└── src
|
|
140
|
+
├── i18n.ts # createI18n({ messages: { en, fr, ... } })
|
|
141
|
+
├── main.ts # app.use(i18n)
|
|
142
|
+
└── components
|
|
143
|
+
└── Footer.vue # useI18n(); t("footer.github")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Z `@intlayer/vue-i18n`**, binding to słownik. `syncJSON` zamienia każdy klucz najwyższego poziomu w `en.json` na słownik; przebieg optymalizacji przekazuje komponentowi te, których klucze nosi, jako importy, które bundler śledzi i dzieli na stronę.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
.
|
|
150
|
+
├── intlayer.config.ts # syncJSON({ format: "vue-i18n", source: ... })
|
|
151
|
+
├── locales
|
|
152
|
+
│ ├── en.json # unchanged, still the source of truth
|
|
153
|
+
│ └── fr.json
|
|
154
|
+
├── .intlayer/ # generated: one dictionary per top-level key, per locale
|
|
155
|
+
└── src
|
|
156
|
+
├── i18n.ts # createI18n({}) ← messages import removed
|
|
157
|
+
├── main.ts # app.use(i18n) ← unchanged
|
|
158
|
+
└── components
|
|
159
|
+
└── Footer.vue # useI18n(); t("footer.github") ← unchanged
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Import `messages` w `i18n.ts` to jest jedyna linia do usunięcia. To daje 88 KB.
|
|
163
|
+
|
|
164
|
+
## Migracja w trzech krokach
|
|
165
|
+
|
|
166
|
+
<Steps>
|
|
167
|
+
<Step number={1} title="Instalacja">
|
|
168
|
+
|
|
169
|
+
```bash packageManager="npm"
|
|
170
|
+
npx intlayer init --interactive
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
```bash packageManager="pnpm"
|
|
174
|
+
pnpm dlx intlayer init --interactive
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```bash packageManager="yarn"
|
|
178
|
+
yarn dlx intlayer init --interactive
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```bash packageManager="bun"
|
|
182
|
+
bunx intlayer init --interactive
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Polecenie wykrywa `vue-i18n`, instaluje `intlayer`, `vue-intlayer`, `@intlayer/vue-i18n` i `@intlayer/sync-json-plugin`, oraz wstępnie wypełnia `intlayer.config.ts`. Zachowaj `vue-i18n` zainstalowany: jest to peer dependency i dostarcza typy.
|
|
186
|
+
|
|
187
|
+
</Step>
|
|
188
|
+
<Step number={2} title="Wskaż Intlayer na pliki lokalizacyjne">
|
|
189
|
+
|
|
190
|
+
```ts fileName="intlayer.config.ts"
|
|
191
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
192
|
+
import { syncJSON } from "@intlayer/sync-json-plugin";
|
|
193
|
+
|
|
194
|
+
const config: IntlayerConfig = {
|
|
195
|
+
internationalization: {
|
|
196
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
197
|
+
defaultLocale: Locales.ENGLISH,
|
|
198
|
+
},
|
|
199
|
+
dictionary: {
|
|
200
|
+
// "static" łączy każdą locale; "dynamic" ładuje aktywną na żądanie
|
|
201
|
+
importMode: "dynamic",
|
|
202
|
+
format: "vue-i18n",
|
|
203
|
+
},
|
|
204
|
+
plugins: [
|
|
205
|
+
syncJSON({
|
|
206
|
+
// dialekt vue-i18n: {name}, {0}, "car | cars"
|
|
207
|
+
format: "vue-i18n",
|
|
208
|
+
source: ({ locale }) => `./locales/${locale}.json`,
|
|
209
|
+
location: "locales",
|
|
210
|
+
}),
|
|
211
|
+
],
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
export default config;
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`locales/{locale}.json` pozostaje w swoim miejscu. Każdy klucz na najwyższym poziomie (`footer`, `hero`...) staje się słownikiem.
|
|
218
|
+
|
|
219
|
+
</Step>
|
|
220
|
+
<Step number={3} title="Dodaj plugin i usuń import wiadomości">
|
|
221
|
+
|
|
222
|
+
```ts fileName="vite.config.ts"
|
|
223
|
+
import { defineConfig } from "vite";
|
|
224
|
+
import vue from "@vitejs/plugin-vue";
|
|
225
|
+
import { vueI18nVitePlugin } from "@intlayer/vue-i18n/plugin";
|
|
226
|
+
|
|
227
|
+
export default defineConfig({
|
|
228
|
+
plugins: [vue(), vueI18nVitePlugin()],
|
|
229
|
+
});
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```ts fileName="src/i18n.ts"
|
|
233
|
+
import { createI18n } from "vue-i18n";
|
|
234
|
+
|
|
235
|
+
// Przed: createI18n({ locale: "en", messages: { en, fr, es } })
|
|
236
|
+
export const i18n = createI18n({ locale: "en" });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`vueI18nVitePlugin()` opakowuje `vite-intlayer` (obserwacja zawartości, kompilacja słownika, przebieg optymalizacji) i aliasuje `vue-i18n` do adaptera. Usunięcie importu `messages` to to, co zmniejsza 88 KB; pozostawienie go sprawia, że aplikacja działa, ale wysyła oba.
|
|
240
|
+
|
|
241
|
+
</Step>
|
|
242
|
+
</Steps>
|
|
243
|
+
|
|
244
|
+
### Co można usunąć później
|
|
245
|
+
|
|
246
|
+
| Plik / wzorzec | Powód |
|
|
247
|
+
| ---------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
248
|
+
| `import en from "./locales/en.json"` i podobne | Używane tylko jako fallback przez adapter. To jest miejsce, gdzie były 88 KB |
|
|
249
|
+
| `setLocaleMessage()` w guardach routera | No-op. Ładowanie per-route to teraz zadanie kompilatora |
|
|
250
|
+
| `@intlify/unplugin-vue-i18n` | Niepotrzebne: prekompiluje wiadomości i bloki SFC, których adapter nie czyta |
|
|
251
|
+
| Bloki SFC `<i18n>` | Nie są odczytywane; przenieś je do JSON-a locale'a lub do `.content.ts` na komponent |
|
|
252
|
+
|
|
253
|
+
### Co zyskujesz poza zmniejszeniem rozmiaru
|
|
254
|
+
|
|
255
|
+
- **Wpisane klucze.** `t("footer.github")` jest wpisany względem skompilowanego słownika `footer`; błędna ścieżka to błąd TypeScript zamiast klucza renderowanego jako tekst.
|
|
256
|
+
- **`npx intlayer test`** powoduje niepowodzenie CI na brakującym kluczu w dowolnym locale'u. **`npx intlayer fill`** tłumaczy brakujące za pomocą twojego klucza providera (OpenAI, Anthropic, Mistral, Gemini...) i zapisuje je z powrotem do `locales/{locale}.json`.
|
|
257
|
+
- **Edytor wizualny i CMS** działają na tym samym JSON-ie, więc osoby niebędące programistami edytują przez interfejs użytkownika, a pliki są aktualizowane.
|
|
258
|
+
- **Stopniowe przejście do `.content.ts`.** Każdy komponent może przejść z `useI18n()` na `useIntlayer("footer")` ze współlokalizowanym plikiem content. Słowniki JSON i `.content.ts` współistnieją i się łączą.
|
|
259
|
+
|
|
260
|
+
## Limity, które warto znać przed rozpoczęciem
|
|
261
|
+
|
|
262
|
+
- **Bloki `<i18n>` SFC nie są czytane.** Jeśli Twoje wiadomości znajdują się wewnątrz komponentów, muszą przejść do plików locale (lub do `.content.ts`, co jest tym samym pomysłem z typami).
|
|
263
|
+
- **Dynamiczne ładowanie wiadomości nie istnieje.** `setLocaleMessage()` i `mergeLocaleMessage()` ostrzegają i zwracają. Tłumaczenia pobrane z CMS w czasie rzeczywistym wymagają CMS-u Intlayer lub poleceń `intlayer pull` / `push`.
|
|
264
|
+
- **`messages` to fallback, nie darmowy.** Utrzymywanie importów JSON w `createI18n()` utrzymuje 75 KB w bundle. Usuń je, gdy `intlayer test` przejdzie pomyślnie.
|
|
265
|
+
- **Adapter nie jest natywnym runtimem.** 7,9 KB wobec 3,9 KB dla `vue-intlayer`. Gdy każdy komponent przejdzie na `useIntlayer`, możesz go usunąć.
|
|
266
|
+
|
|
267
|
+
## Kiedy użyć którego?
|
|
268
|
+
|
|
269
|
+
- **Pozostań na `vue-i18n`** jeśli Twoja aplikacja zależy od bloków SFC `<i18n>`, od przepływów runtime `setLocaleMessage()`, lub jeśli 90 KB na stronę nie stanowi problemu dla Twojej audience.
|
|
270
|
+
- **Używaj `@intlayer/vue-i18n`** jeśli jesteś na `vue-i18n` i chcesz zaoszczędzić 88 KB, mieć komponenty 23x mniejsze, 0% wycieku strony, typed keys i CI checks bez edytowania pliku `.vue`. To jest punkt wejścia dla istniejącej codebase `vue-i18n`.
|
|
271
|
+
- **Idź natywnie (`vue-intlayer`)** dla nowych projektów, lub gdy adapter wykonał swoje zadanie. Ma najlżejszy runtime (3,9 KB) i model per-component `.content.ts`, który zastępuje bloki `<i18n>` typed content.
|
|
272
|
+
|
|
273
|
+
## Powiązane porównania
|
|
274
|
+
|
|
275
|
+
- [vue-i18n vs Intlayer](https://intlayer.org/blog/vue-i18n-vs-intlayer) (funkcje i DX)
|
|
276
|
+
- [vue-i18n vs Intlayer benchmark](https://intlayer.org/blog/vue-i18n-vs-intlayer-benchmark) (biblioteki, ten sam benchmark)
|
|
277
|
+
- [next-intl vs @intlayer/next-intl](https://intlayer.org/blog/next-intl-vs-intlayer-next-intl) (ta sama seria adapterów)
|
|
278
|
+
- [i18next vs @intlayer/i18next](https://intlayer.org/blog/i18next-vs-intlayer-i18next) (ta sama seria adapterów)
|
|
279
|
+
- [Lingui vs @intlayer/lingui](https://intlayer.org/blog/lingui-vs-intlayer-lingui) (ta sama seria adapterów)
|
|
280
|
+
- [Przewodnik migracji: vue-i18n do Intlayer](https://intlayer.org/doc/migration/vue-i18n)
|
|
281
|
+
- [Compat adapter reference: vue-i18n](https://intlayer.org/doc/compatibility/vue-i18n), [Nuxt i18n](https://intlayer.org/doc/compatibility/nuxtjs-i18n)
|
|
282
|
+
|
|
283
|
+
## Podsumowanie
|
|
284
|
+
|
|
285
|
+
`@intlayer/vue-i18n` zmienia to, do czego `useI18n()` jest powiązane: z globalnej instancji zawierającej każdą wiadomość każdej lokalizacji na słownik skompilowany dla tego komponentu. W tej samej aplikacji Vite + Vue 3, która jest **88 KB mniejsza na stronę**, **3x mniejszy runtime**, **23x mniejsze komponenty** i **0% wycieków strony**, dla pliku konfiguracyjnego, linii pluginu i jednego usuniętego importu. Bloki SFC `<i18n>` i ładowanie wiadomości w runtime to dwie rzeczy, które nie są obsługiwane, a natywny runtime `vue-intlayer` pozostaje o połowę mniejszy.
|
|
286
|
+
|
|
287
|
+
Wszystkie surowe dane, aplikacje testowe i skrypty znajdują się w [repozytorium Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom). Uruchom je sam.
|
|
288
|
+
|
|
289
|
+
Więcej szczegółów znajdziesz w dokumentacji ['Why Intlayer?'](https://intlayer.org/doc/why).
|
|
@@ -235,7 +235,7 @@ Korzystając z `intlayer`, możesz zadeklarować swoją zawartość w formacie u
|
|
|
235
235
|
|
|
236
236
|
Gwiazdy na GitHubie są silnym wskaźnikiem popularności projektu, zaufania społeczności oraz jego długoterminowej istotności. Choć nie są bezpośrednim miernikiem jakości technicznej, odzwierciedlają, ilu deweloperów uważa projekt za użyteczny, śledzi jego rozwój i jest skłonnych go przyjąć. Przy szacowaniu wartości projektu, gwiazdy pomagają porównać zainteresowanie różnymi alternatywami oraz dostarczają wglądu w rozwój ekosystemu.
|
|
237
237
|
|
|
238
|
-
[](https://
|
|
238
|
+
[](https://star-history.com/#intlify/vue-i18n&aymericzip/intlayer)
|
|
239
239
|
|
|
240
240
|
## Podsumowanie
|
|
241
241
|
|
|
File without changes
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-13
|
|
3
|
+
updatedAt: 2026-09-13
|
|
4
|
+
title: "i18next vs @intlayer/i18next: Mesma API, Outro Bundle"
|
|
5
|
+
description: O que muda quando uma aplicação React ou Next.js mantém suas chamadas de i18next, react-i18next e next-i18next mas as executa através dos adaptadores @intlayer/i18next. JavaScript por página, tamanho de componentes, vazamento de conteúdo e hidratação medidos no mesmo código, além do que os adaptadores mantêm, ignoram e não substituem.
|
|
6
|
+
keywords:
|
|
7
|
+
- i18next
|
|
8
|
+
- react-i18next
|
|
9
|
+
- next-i18next
|
|
10
|
+
- "@intlayer/i18next"
|
|
11
|
+
- "@intlayer/react-i18next"
|
|
12
|
+
- "@intlayer/next-i18next"
|
|
13
|
+
- Intlayer
|
|
14
|
+
- Adaptador de compatibilidade
|
|
15
|
+
- Migração
|
|
16
|
+
- Internacionalização
|
|
17
|
+
- i18n
|
|
18
|
+
- Benchmark
|
|
19
|
+
- Tamanho de bundle
|
|
20
|
+
- Blog
|
|
21
|
+
- Next.js
|
|
22
|
+
- React
|
|
23
|
+
slugs:
|
|
24
|
+
- blog
|
|
25
|
+
- i18next-vs-intlayer-i18next
|
|
26
|
+
author: aymericzip
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# i18next VS @intlayer/i18next | Mesma API, Outro Bundle
|
|
30
|
+
|
|
31
|
+
`@intlayer/i18next`, `@intlayer/react-i18next` e `@intlayer/next-i18next` são adaptadores de compatibilidade. Eles expõem a API do `i18next` que seu código já utiliza (`useTranslation`, `t()`, `<Trans>`, `i18n.changeLanguage()`, `getFixedT`, `serverSideTranslations`...) e a fornecem a partir de dicionários compilados pelo Intlayer. Os componentes não mudam. O runtime abaixo deles sim.
|
|
32
|
+
|
|
33
|
+
Este artigo analisa essa substituição na mesma aplicação Next.js, construída uma vez com `next-i18next` e outra com `@intlayer/next-i18next`. Os dados são do [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom). Para comparar `i18next` e Intlayer como bibliotecas completas, leia [i18next vs Intlayer](https://intlayer.org/pt/blog/i18next-vs-intlayer). Este artigo se concentra no que o adaptador transforma quando você preserva seu código como está.
|
|
34
|
+
|
|
35
|
+
<TOC/>
|
|
36
|
+
|
|
37
|
+
> **tl;dr**: Na mesma aplicação Next.js, substituir `next-i18next` por `@intlayer/next-i18next` reduziu o JavaScript por página de **218.5 KB para 150.7 KB** gzip (setup básico) e superou o setup do `next-i18next` totalmente otimizado (163.4 KB) em **12.7 KB**. O componente médio caiu de **78.5 KB para 9.7 KB**, o vazamento de strings para outras páginas foi de **~90% para 0%**, a hidratação de **15.6 ms para 11.3 ms** e o runtime de **19.7 KB para 9.4 KB**. Nenhum componente foi editado; apenas um arquivo de provider foi ajustado. Plugins do `i18next` (backends, detectores de idioma) são aceitos mas não realizam nada: não há mais nada para carregar ou detectar em tempo de execução.
|
|
38
|
+
|
|
39
|
+
## O que é o `@intlayer/i18next`
|
|
40
|
+
|
|
41
|
+
O `i18next` é um runtime. `i18n.init({ resources })` ou um plugin de backend carrega `locales/{lng}/{ns}.json` em uma instância global; `useTranslation("about")` inscreve o componente nela; `t("title")` busca a chave no momento da renderização. Namespaces, carregamento sob demanda (lazy loading), listas de namespaces por página e segurança de tipos ficam sob sua responsabilidade de configuração e manutenção.
|
|
42
|
+
|
|
43
|
+
Os adaptadores preservam a API e substituem a instância:
|
|
44
|
+
|
|
45
|
+
1. **Aliases de importação.** `createNextI18nPlugin()` do `@intlayer/next-i18next/plugin` (ou `withI18next`) envolve o `withIntlayer` e cria aliases no Webpack / Turbopack para que `next-i18next`, `react-i18next` e `i18next` resolvam para os pacotes `@intlayer/*`. No Vite, o `reactI18nextVitePlugin()` do `@intlayer/react-i18next/plugin` tem o mesmo papel. Nenhuma importação precisa ser renomeada.
|
|
46
|
+
2. **JSON como fonte de verdade.** O plugin `syncJSON` lê seus arquivos existentes `locales/{lng}/{ns}.json` com `format: "i18next"` (garantindo que `{{name}}`, aninhamento `$t()`, `_one` / `_other` e sufixos de contexto sejam interpretados adequadamente) e regrava as traduções quando a CLI ou o CMS as atualizam.
|
|
47
|
+
3. **Vinculação no ponto de chamada.** A etapa de otimização do Intlayer reescreve `useTranslation("about")` em uma chamada que recebe o dicionário `about` diretamente, no idioma ativo. O componente deixa de acessar a store global.
|
|
48
|
+
|
|
49
|
+
```tsx fileName="components/About.tsx"
|
|
50
|
+
// Seu código, inalterado
|
|
51
|
+
import { useTranslation } from "react-i18next";
|
|
52
|
+
|
|
53
|
+
const About = () => {
|
|
54
|
+
const { t } = useTranslation("about");
|
|
55
|
+
return <h1>{t("title")}</h1>;
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```tsx fileName="O que o compilador emite (simplificado)"
|
|
60
|
+
import _dicHash_about from "../.intlayer/dictionaries/about.mjs";
|
|
61
|
+
import { useDictionary as useTranslation } from "@intlayer/react-i18next";
|
|
62
|
+
|
|
63
|
+
const About = () => {
|
|
64
|
+
const { t } = useTranslation(_dicHash_about);
|
|
65
|
+
return <h1>{t("title")}</h1>;
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Essa transformação é a razão pela qual as colunas de tamanho de componente e vazamento de página caem drasticamente nos dados abaixo.
|
|
70
|
+
|
|
71
|
+
## O que os adaptadores mantêm, ignoram e não substituem
|
|
72
|
+
|
|
73
|
+
| API do `i18next` | Com `@intlayer/*` |
|
|
74
|
+
| ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
75
|
+
| `useTranslation("ns")`, `useTranslation("ns", { keyPrefix })` | ✅ Mantido. Vinculado ao dicionário `ns` em tempo de compilação; tipado com seu conteúdo |
|
|
76
|
+
| `t("key", { name })`, `{{interpolation}}`, aninhamento `$t(key)` | ✅ Mantido |
|
|
77
|
+
| Plurais `key_one` / `key_other`, contexto `key_male`, `returnObjects` | ✅ Mantido. Plurais calculados com `Intl.PluralRules` |
|
|
78
|
+
| `<Trans>` com `components`, tags numeradas `<1>...</1>`, `values` | ✅ Mantido |
|
|
79
|
+
| `withTranslation`, `Translation`, `I18nContext` | ✅ Mantido |
|
|
80
|
+
| `i18n.changeLanguage()`, `i18n.language`, `i18n.dir()`, `on("languageChanged")` | ✅ Mantido. `changeLanguage` controla o idioma do Intlayer |
|
|
81
|
+
| `getFixedT(lng, ns, keyPrefix)`, `i18n.exists()`, `hasLoadedNamespace()` | ✅ Mantido |
|
|
82
|
+
| `i18n.use(Backend).use(LanguageDetector).init({...})` | ⚠️ `use()` executa o `init` do plugin e encerra; backends e detectores não têm nada para carregar ou detectar |
|
|
83
|
+
| `init({ resources })`, `addResourceBundle()` | ⚠️ `resources` é **ignorado** com alerta de desenvolvimento; remova imports de JSON para obter ganhos reais de bundle |
|
|
84
|
+
| `I18nextProvider i18n={i18n}` | ⚠️ Renderiza um `IntlayerProvider`; a prop `i18n` é ignorada. No App Router, passe o locale (veja abaixo) |
|
|
85
|
+
| `serverSideTranslations(locale, ["common"])` (next-i18next) | ⚠️ Retorna a estrutura esperada e não carrega nada. Seguro de manter, seguro de remover |
|
|
86
|
+
| `appWithTranslation(App)` (next-i18next) | ✅ Mantido |
|
|
87
|
+
| `next-i18next.config.js` | ⚠️ Não é lido. Os idiomas são configurados no `intlayer.config.ts` |
|
|
88
|
+
| `useTranslation()` sem namespace | ✅ Opera contra o dicionário geral `translation` do arquivo inteiro (`splitKeys: false`) |
|
|
89
|
+
|
|
90
|
+
## O benchmark
|
|
91
|
+
|
|
92
|
+
### O que foi medido
|
|
93
|
+
|
|
94
|
+
A suite [Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom) compila **a mesma aplicação** em cada ambiente: **10 páginas** (home, about, blog, careers, contact, FAQ, pricing, products, settings, team), **10 locales** (`en`, `fr`, `es`, `de`, `it`, `pt`, `zh`, `ja`, `ko`, `ru`), componentes idênticos e conteúdo idêntico. As páginas são avaliadas em `en` e `fr`.
|
|
95
|
+
|
|
96
|
+
O `next-i18next` foi configurado em quatro estratégias de carregamento, desde o JSON de cada idioma importado em `resources` (`static`) até um namespace por rota, carregado de forma diferida via backend (`scoped-dynamic`). O adaptador foi testado sobre **os mesmos componentes do setup inicial**, com alterações limitadas a `next.config.ts`, `intlayer.config.ts` e ao arquivo do provider. Ele não possui variante "scoped" manual: o compilador define o escopo do conteúdo por componente.
|
|
97
|
+
|
|
98
|
+
Para cada compilação, registram-se:
|
|
99
|
+
|
|
100
|
+
- **Tamanho da lib**: tamanho gzip de um componente vazio que apenas importa a biblioteca de i18n.
|
|
101
|
+
- **JS por página**: média de JavaScript gzip transferido por página em todas as rotas e locales.
|
|
102
|
+
- **% de vazamento de locale**: parcela de strings traduzidas no JS que pertence a um idioma que o usuário **não** está visualizando.
|
|
103
|
+
- **% de vazamento de página**: parcela de strings traduzidas no JS que pertence a uma página em que o usuário **não** está navegando.
|
|
104
|
+
- **Média por componente**: tamanho médio gzip de cada componente compilado de forma isolada.
|
|
105
|
+
- **Reatividade E2E**: intervalo de tempo real entre selecionar um novo idioma e a alteração de `html[lang]` no DOM (Playwright, 5 repetições).
|
|
106
|
+
- **Hidratação**: tempo de duração da fase de hidratação do React.
|
|
107
|
+
|
|
108
|
+
> Os dados abaixo resultam da execução de **12/09/2026** com `next-i18next` 16.3.0 (`react-i18next` 17.0.13, `i18next` 26.4.2) e `@intlayer/next-i18next` 9.5.1. A aplicação de teste foi projetada com escopo enxuto propositalmente (algumas dezenas de strings por idioma), portanto os percentuais de vazamento ilustram um **comportamento**: expandem-se proporcionalmente ao crescimento do conteúdo enquanto o custo do runtime permanece estático.
|
|
109
|
+
|
|
110
|
+
### Resultados no Next.js
|
|
111
|
+
|
|
112
|
+
| Setup | Estratégia | Tamanho lib (gz) | Média JS pág (gz) | Vazamento locale | Vazamento pág | Média comp (gz) | Reatividade E2E | Hidratação |
|
|
113
|
+
| ---------------------------- | -------------- | ---------------: | ----------------: | ---------------: | ------------: | --------------: | --------------: | ----------: |
|
|
114
|
+
| **base** (sem i18n) | - | 0.0 KB | 141.0 KB | 0.0% | 0.0% | 0.9 KB | 13.4 ms | 11.8 ms |
|
|
115
|
+
| `next-i18next` | static | 19.7 KB | 218.5 KB | 0.0% | 89.8% | 78.5 KB | 16.4 ms | 15.6 ms |
|
|
116
|
+
| `next-i18next` | dynamic | 19.7 KB | 169.5 KB | 50.0% | 89.8% | 26.1 KB | 15.4 ms | 27.7 ms |
|
|
117
|
+
| `next-i18next` | scoped-static | 19.7 KB | 220.1 KB | 0.0% | 89.8% | 78.9 KB | 16.4 ms | 14.7 ms |
|
|
118
|
+
| `next-i18next` | scoped-dynamic | 19.7 KB | 163.4 KB | 0.0% | 0.0% | 27.1 KB | 15.9 ms | 15.1 ms |
|
|
119
|
+
| **`@intlayer/next-i18next`** | static | **9.4 KB** | **150.7 KB** | **0.0%** | **0.0%** | **9.7 KB** | **10.7 ms** | **11.3 ms** |
|
|
120
|
+
| **`@intlayer/next-i18next`** | dynamic | **9.4 KB** | **150.7 KB** | **0.0%** | **0.0%** | **9.7 KB** | **11.9 ms** | **10.6 ms** |
|
|
121
|
+
| `next-intlayer` (nativo) | static | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 8.5 KB | 15.5 ms | 16.9 ms |
|
|
122
|
+
| `next-intlayer` (nativo) | dynamic | 5.5 KB | 141.3 KB | 0.0% | 0.0% | 6.9 KB | 15.3 ms | 15.9 ms |
|
|
123
|
+
|
|
124
|
+
**Como interpretar os dados**
|
|
125
|
+
|
|
126
|
+
- **68 KB a menos por página em relação ao setup básico.** `resources: { en, fr, ... }` despacha todos os idiomas e namespaces para cada rota: **218.5 KB**. O build com o adaptador cai para **150.7 KB**. Supera também a configuração mais elaborada do `next-i18next` (163.4 KB, namespace único por rota, carregado sob demanda) em 12.7 KB, pois a própria biblioteca `i18next` consome 19.7 KB contra 9.4 KB.
|
|
127
|
+
- **O vazamento atinge 0% sem intervenção em componentes.** Cada configuração do `next-i18next`, à exceção da modularizada manualmente, entrega ~90% de strings de rotas distintas. A linha `dynamic` é pior na prática do que aparenta: preserva o vazamento entre páginas e adiciona **50% de vazamento de idioma**, dado que o backend busca todo o namespace `translation` do locale ativo. O adaptador estabelece 0% / 0% a partir do código original.
|
|
128
|
+
- **Componentes: 8x mais enxutos.** Um componente com `useTranslation()` isolado consome **78.5 KB** com `resources` inlined e **26-27 KB** com backend, já que `t` continua preso à store global. No adaptador, a média cai para **9.7 KB**.
|
|
129
|
+
- **Hidratação e alternância de idioma aceleradas.** A hidratação cai de 15.6 ms para **11.3 ms** (e de 27.7 ms no modo `dynamic`, no qual o carregamento do backend reside no caminho crítico). A troca de idioma cai de 15-16 ms para **11-12 ms**.
|
|
130
|
+
- **O adaptador é diferente do runtime nativo.** O `next-intlayer` crava **141.3 KB**, meros +0.3 KB acima do app sem i18n. O adaptador suporta as particularidades da API do `i18next` (expressões de interpolação, sufixos de plural e contexto, tags `<Trans>`) sobre o núcleo do Intlayer: 9.4 KB e +9.4 KB por página em relação ao nativo. Atua como transição, não como destino final.
|
|
131
|
+
|
|
132
|
+
> O adaptador `react-i18next` no Vite / TanStack Start não constou desta rodada de testes. A medição para `react-i18next` no TanStack Start pode ser verificada em [i18next vs Intlayer](https://intlayer.org/pt/blog/i18next-vs-intlayer): 127-184 KB por página e 123-185 ms na troca de idioma com backend sob demanda.
|
|
133
|
+
|
|
134
|
+
## O motivo da mudança nos indicadores
|
|
135
|
+
|
|
136
|
+
Nenhum arquivo em `components/` foi alterado, logo o ganho advém da entidade à qual `useTranslation` se acopla.
|
|
137
|
+
|
|
138
|
+
**Com o `i18next`**, a ligação é feita na instância global. Qualquer recurso alocado nela (todos os idiomas em `static`, o namespace completo do idioma ativo em `dynamic`) torna-se acessível para qualquer componente chamador de `useTranslation()`. O bundler não consegue fragmentar abaixo do volume contido na instância, e o runtime não é capaz de prever quais chaves serão demandadas em renderização.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
.
|
|
142
|
+
├── next-i18next.config.js
|
|
143
|
+
├── public/locales
|
|
144
|
+
│ ├── en/translation.json # strings de todas as páginas
|
|
145
|
+
│ └── fr/translation.json
|
|
146
|
+
├── i18n/i18n.ts # i18n.use(initReactI18next).init({ resources })
|
|
147
|
+
└── components
|
|
148
|
+
├── AppProviders.tsx # <I18nextProvider i18n={i18n}>
|
|
149
|
+
└── About.tsx # useTranslation(); t("about.title")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Com o `@intlayer/next-i18next`**, a ligação é feita diretamente com o dicionário. O plugin `syncJSON` transforma cada arquivo de namespace em um dicionário; o ciclo de otimização repassa ao componente apenas o dicionário declarado, na forma de import que o empacotador rastreia e separa por página e locale.
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
.
|
|
156
|
+
├── intlayer.config.ts # syncJSON({ format: "i18next", source: ... })
|
|
157
|
+
├── public/locales
|
|
158
|
+
│ ├── en/translation.json # inalterado, continua como fonte da verdade
|
|
159
|
+
│ └── fr/translation.json
|
|
160
|
+
├── .intlayer/ # gerado: um dicionário por namespace, por locale
|
|
161
|
+
└── components
|
|
162
|
+
├── AppProviders.tsx # <IntlayerClientProvider locale={locale}>
|
|
163
|
+
└── About.tsx # useTranslation(); t("about.title") ← inalterado
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
O arquivo `i18n/i18n.ts` e sua importação de `resources` tornam-se código inerte. É daí que procedem os 68 KB de alívio.
|
|
167
|
+
|
|
168
|
+
## Migração em três etapas
|
|
169
|
+
|
|
170
|
+
<Steps>
|
|
171
|
+
<Step number={1} title="Instalação">
|
|
172
|
+
|
|
173
|
+
```bash packageManager="npm"
|
|
174
|
+
npx intlayer init --interactive
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```bash packageManager="pnpm"
|
|
178
|
+
pnpm dlx intlayer init --interactive
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```bash packageManager="yarn"
|
|
182
|
+
yarn dlx intlayer init --interactive
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```bash packageManager="bun"
|
|
186
|
+
bunx intlayer init --interactive
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
O comando identifica `i18next` / `react-i18next` / `next-i18next`, instala o `intlayer`, o pacote do framework (`next-intlayer` ou `react-intlayer`), o respectivo adaptador `@intlayer/*` e o `@intlayer/sync-json-plugin`, além de preencher o `intlayer.config.ts`. Conserve as dependências originais instaladas: elas operam como peer dependencies e entregam as tipagens.
|
|
190
|
+
|
|
191
|
+
</Step>
|
|
192
|
+
<Step number={2} title="Aponte o Intlayer para seus arquivos de tradução">
|
|
193
|
+
|
|
194
|
+
```ts fileName="intlayer.config.ts"
|
|
195
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
196
|
+
import { syncJSON } from "@intlayer/sync-json-plugin";
|
|
197
|
+
|
|
198
|
+
const config: IntlayerConfig = {
|
|
199
|
+
internationalization: {
|
|
200
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
201
|
+
defaultLocale: Locales.ENGLISH,
|
|
202
|
+
},
|
|
203
|
+
dictionary: {
|
|
204
|
+
importMode: "dynamic",
|
|
205
|
+
format: "i18next",
|
|
206
|
+
},
|
|
207
|
+
plugins: [
|
|
208
|
+
syncJSON({
|
|
209
|
+
// dialeto i18next: {{name}}, $t(key), key_one / key_other, key_male
|
|
210
|
+
format: "i18next",
|
|
211
|
+
// Um arquivo por namespace: `useTranslation("about")` → about.json
|
|
212
|
+
source: ({ locale, key }) => `./public/locales/${locale}/${key}.json`,
|
|
213
|
+
location: "public/locales",
|
|
214
|
+
}),
|
|
215
|
+
],
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
export default config;
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Caso você mantenha um único arquivo `translation.json` por locale (o namespace padrão do i18next), configure `splitKeys: false` para que o arquivo integral permaneça como um único dicionário e invocações diretas de `useTranslation()` prossigam sem falhas.
|
|
222
|
+
|
|
223
|
+
</Step>
|
|
224
|
+
<Step number={3} title="Adicione o plugin">
|
|
225
|
+
|
|
226
|
+
<Tabs>
|
|
227
|
+
<Tab label="Next.js">
|
|
228
|
+
|
|
229
|
+
```ts fileName="next.config.ts"
|
|
230
|
+
import type { NextConfig } from "next";
|
|
231
|
+
import { withI18next } from "@intlayer/next-i18next/plugin";
|
|
232
|
+
|
|
233
|
+
const nextConfig: NextConfig = {};
|
|
234
|
+
|
|
235
|
+
export default withI18next(nextConfig);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
No App Router, componentes de cliente identificam o idioma pelo segmento `[locale]`. O `I18nextProvider` do adaptador não aceita locale como propriedade, logo substitua-o uma única vez no arquivo de provider:
|
|
239
|
+
|
|
240
|
+
```tsx fileName="components/AppProviders.tsx"
|
|
241
|
+
"use client";
|
|
242
|
+
|
|
243
|
+
import { IntlayerClientProvider } from "next-intlayer";
|
|
244
|
+
import type { LocalesValues } from "intlayer";
|
|
245
|
+
|
|
246
|
+
export const AppProviders = ({
|
|
247
|
+
locale,
|
|
248
|
+
children,
|
|
249
|
+
}: {
|
|
250
|
+
locale: LocalesValues;
|
|
251
|
+
children: React.ReactNode;
|
|
252
|
+
}) => (
|
|
253
|
+
<IntlayerClientProvider locale={locale}>{children}</IntlayerClientProvider>
|
|
254
|
+
);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Todos os componentes abaixo continuam invocando `useTranslation()`.
|
|
258
|
+
|
|
259
|
+
</Tab>
|
|
260
|
+
<Tab label="Vite / TanStack Start">
|
|
261
|
+
|
|
262
|
+
```ts fileName="vite.config.ts"
|
|
263
|
+
import { defineConfig } from "vite";
|
|
264
|
+
import react from "@vitejs/plugin-react";
|
|
265
|
+
import { reactI18nextVitePlugin } from "@intlayer/react-i18next/plugin";
|
|
266
|
+
|
|
267
|
+
export default defineConfig({
|
|
268
|
+
plugins: [react(), reactI18nextVitePlugin()],
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
O `reactI18nextVitePlugin()` encapsula o `vite-intlayer` e define os aliases para `react-i18next` e `i18next`. Para projetos sem React, `i18nextVitePlugin()` do `@intlayer/i18next/plugin` provê o alias somente para `i18next`.
|
|
273
|
+
|
|
274
|
+
</Tab>
|
|
275
|
+
</Tabs>
|
|
276
|
+
|
|
277
|
+
</Step>
|
|
278
|
+
</Steps>
|
|
279
|
+
|
|
280
|
+
### O que você pode remover em seguida
|
|
281
|
+
|
|
282
|
+
| Arquivo / padrão | Motivo |
|
|
283
|
+
| ------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
|
|
284
|
+
| `resources: { en, fr, ... }` e importações JSON | Ignorados pelo adaptador. Era aqui que se concentravam os 68 KB |
|
|
285
|
+
| `i18next-http-backend`, `i18next-resources-to-backend` | Não há nada a carregar dinamicamente |
|
|
286
|
+
| `i18next-browser-languagedetector` | A identificação é controlada pelo roteamento do Intlayer (prefixo de URL, cookie, cabeçalho) |
|
|
287
|
+
| `serverSideTranslations()` em `getStaticProps` | Devolve um objeto vazio; inofensivo, mas inútil |
|
|
288
|
+
| `next-i18next.config.js` | Não é consultado. Idiomas residem no `intlayer.config.ts` |
|
|
289
|
+
| Listas de `ns: [...]` por página | O compilador detecta os namespaces por componente |
|
|
290
|
+
|
|
291
|
+
### O que você ganha além da redução em bytes
|
|
292
|
+
|
|
293
|
+
- **Tipagem estrita de chaves.** `useTranslation("about")` valida chaves contra o dicionário `about` compilado; `t("does.not.exist")` gera um erro do compilador TypeScript em vez de retornar a string crua.
|
|
294
|
+
- **`npx intlayer test`** bloqueia a integração contínua (CI) se faltar qualquer tradução em qualquer idioma. **`npx intlayer fill`** traduz pendências com sua própria chave de provedor (OpenAI, Anthropic, Mistral, Gemini...) e as salva em `locales/{lng}/{ns}.json`.
|
|
295
|
+
- **Editor Visual e CMS** atuam diretamente no mesmo JSON, permitindo que editores atualizem textos por interface gráfica enquanto os arquivos Git são versionados.
|
|
296
|
+
- **Migração gradual para `.content.ts`.** Cada componente pode migrar de `useTranslation("about")` para `useIntlayer("about")` adotando um arquivo de conteúdo co-localizado. Dicionários JSON e `.content.ts` operam juntos harmonicamente.
|
|
297
|
+
|
|
298
|
+
## Limitações importantes antes de iniciar
|
|
299
|
+
|
|
300
|
+
- **Backends e detectores ficam desativados.** `i18n.use(HttpBackend)` executa o método `init` do plugin e encerra. Se seu projeto dependia de buscar traduções em um CMS em tempo de execução, esse fluxo é descontinuado; use o CMS do Intlayer ou os comandos `intlayer pull` / `push`.
|
|
301
|
+
- **`resources` é descartado, não combinado.** Ao contrário de certos adaptadores, o `@intlayer/i18next` não usa `resources` inline como recurso de segurança. Toda chave precisa existir nos dicionários sincronizados, o que é validado por `intlayer test`.
|
|
302
|
+
- **App Router necessita do ajuste de provider.** Apenas um arquivo, apresentado acima. O Pages Router com `appWithTranslation` opera sem ajustes adicionais.
|
|
303
|
+
- **`next-i18next.config.js` não é aproveitado.** Parâmetros como `localePath`, `fallbackLng` e `reloadOnPrerender` não são lidos; configurações de idioma e fallback residem em `intlayer.config.ts`.
|
|
304
|
+
- **O adaptador possui um custo.** 9.4 KB de runtime e +9.4 KB por página em relação ao `next-intlayer`. Assim que todos os componentes forem convertidos para `useIntlayer`, ele pode ser desinstalado.
|
|
305
|
+
|
|
306
|
+
## Quando utilizar cada alternativa?
|
|
307
|
+
|
|
308
|
+
- **Mantenha-se no `i18next`** se sua infraestrutura depender de backends dinâmicos em tempo de execução (traduções servidas sob demanda por CMS), de plugins exclusivos ou de um ambiente fora do ecossistema React não atendido pelos adaptadores.
|
|
309
|
+
- **Adote `@intlayer/*`** se você já opera com `react-i18next` / `next-i18next` e deseja resgatar 68 KB, atingir componentes 8x menores, eliminar vazamento (0%), obter chaves tipadas e validação na CI sem reescrever seus componentes. É a transição recomendada para bases existentes de `i18next`.
|
|
310
|
+
- **Prefira o modelo nativo (`next-intlayer` / `react-intlayer`)** em projetos novos ou logo após o adaptador consolidar a migração. Trata-se da opção mais rápida (5.5 KB, +0.3 KB por página), liberando Server Components síncronos e arquivos `.content.ts` por componente.
|
|
311
|
+
|
|
312
|
+
## Comparações relacionadas
|
|
313
|
+
|
|
314
|
+
- [i18next vs Intlayer](https://intlayer.org/pt/blog/i18next-vs-intlayer) (comparação das bibliotecas, mesmo benchmark)
|
|
315
|
+
- [next-intl vs @intlayer/next-intl](https://intlayer.org/pt/blog/next-intl-vs-intlayer-next-intl) (mesma série de adaptadores)
|
|
316
|
+
- [Lingui vs @intlayer/lingui](https://intlayer.org/pt/blog/lingui-vs-intlayer-lingui) (mesma série de adaptadores)
|
|
317
|
+
- [vue-i18n vs @intlayer/vue-i18n](https://intlayer.org/pt/blog/vue-i18n-vs-intlayer-vue-i18n) (mesma série de adaptadores)
|
|
318
|
+
- Guias de migração: [i18next](https://intlayer.org/pt/doc/migration/i18next), [react-i18next](https://intlayer.org/pt/doc/migration/react-i18next), [next-i18next](https://intlayer.org/pt/doc/migration/next-i18next)
|
|
319
|
+
- Referência dos adaptadores: [i18next](https://intlayer.org/pt/doc/compatibility/i18next), [react-i18next](https://intlayer.org/pt/doc/compatibility/react-i18next), [next-i18next](https://intlayer.org/pt/doc/compatibility/next-i18next)
|
|
320
|
+
|
|
321
|
+
## Conclusão
|
|
322
|
+
|
|
323
|
+
O `i18next` figura como o runtime mais pesado deste benchmark, e os adaptadores cortam a maior parte dessa carga sem exigir que você abandone sua API habitual. Na mesma aplicação Next.js, isso representa **68 KB a menos por página** comparado à configuração inicial, **12.7 KB a menos** em relação à opção mais otimizada manualmente, **componentes 8x mais leves**, **0% de vazamento** e **4 ms a menos de hidratação**, demandando apenas um arquivo de configuração, uma inclusão de plugin e um ajuste no provider. Backends e detectores tornam-se inócuos, `resources` é descartado ao invés de incorporado, e a implementação nativa do `next-intlayer` preserva outros 9 KB de leveza adicional.
|
|
324
|
+
|
|
325
|
+
A totalidade dos dados brutos, aplicações de teste e scripts encontra-se publicada no [repositório do Benchmark Bloom](https://github.com/intlayer-org/benchmark-bloom).
|
|
326
|
+
|
|
327
|
+
Consulte o documento [Por que Intlayer?](https://intlayer.org/pt/doc/why) para aprofundar.
|