@intlayer/docs 9.5.7 → 9.5.8
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/blog/ar/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/de/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/en/is_intlayer_lighter_than_paraglide.md +288 -0
- package/blog/en-GB/is_intlayer_lighter_than_paraglide.md +285 -0
- package/blog/es/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/fr/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/hi/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/id/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/it/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/ja/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/ko/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/pl/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/pt/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/ru/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/tr/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/uk/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/vi/is_intlayer_lighter_than_paraglide.md +284 -0
- package/blog/zh/is_intlayer_lighter_than_paraglide.md +284 -0
- package/dist/cjs/generated/blog.entry.cjs +20 -0
- package/dist/cjs/generated/blog.entry.cjs.map +1 -1
- package/dist/cjs/generated/docs.entry.cjs +20 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/cjs/index.cjs +2 -2
- package/dist/esm/generated/blog.entry.mjs +20 -0
- package/dist/esm/generated/blog.entry.mjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +20 -0
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/esm/index.mjs +2 -2
- package/dist/types/generated/blog.entry.d.ts +1 -0
- package/dist/types/generated/blog.entry.d.ts.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -0
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/benchmark/nextjs.md +6 -3
- package/docs/ar/benchmark/solid.md +21 -4
- package/docs/ar/benchmark/svelte.md +18 -3
- package/docs/ar/benchmark/tanstack.md +6 -3
- package/docs/ar/benchmark/vue.md +14 -5
- package/docs/ar/cli/index.md +6 -1
- package/docs/ar/cli/upgrade.md +125 -0
- package/docs/de/benchmark/nextjs.md +6 -3
- package/docs/de/benchmark/solid.md +21 -4
- package/docs/de/benchmark/svelte.md +18 -3
- package/docs/de/benchmark/tanstack.md +6 -3
- package/docs/de/benchmark/vue.md +14 -5
- package/docs/de/cli/index.md +6 -1
- package/docs/de/cli/upgrade.md +125 -0
- package/docs/en/agent_skills.md +29 -1
- package/docs/en/benchmark/nextjs.md +6 -3
- package/docs/en/benchmark/solid.md +21 -4
- package/docs/en/benchmark/svelte.md +18 -3
- package/docs/en/benchmark/tanstack.md +7 -4
- package/docs/en/benchmark/vue.md +15 -6
- package/docs/en/cli/index.md +6 -1
- package/docs/en/cli/upgrade.md +125 -0
- package/docs/en-GB/benchmark/nextjs.md +6 -3
- package/docs/en-GB/benchmark/solid.md +21 -4
- package/docs/en-GB/benchmark/svelte.md +18 -3
- package/docs/en-GB/benchmark/tanstack.md +6 -3
- package/docs/en-GB/benchmark/vue.md +15 -6
- package/docs/en-GB/cli/index.md +6 -1
- package/docs/en-GB/cli/upgrade.md +125 -0
- package/docs/es/benchmark/nextjs.md +6 -3
- package/docs/es/benchmark/solid.md +21 -4
- package/docs/es/benchmark/svelte.md +18 -3
- package/docs/es/benchmark/tanstack.md +6 -3
- package/docs/es/benchmark/vue.md +14 -5
- package/docs/es/cli/index.md +6 -1
- package/docs/es/cli/upgrade.md +125 -0
- package/docs/fr/benchmark/nextjs.md +6 -3
- package/docs/fr/benchmark/solid.md +21 -4
- package/docs/fr/benchmark/svelte.md +18 -3
- package/docs/fr/benchmark/tanstack.md +6 -3
- package/docs/fr/benchmark/vue.md +15 -6
- package/docs/fr/cli/index.md +6 -1
- package/docs/fr/cli/upgrade.md +125 -0
- package/docs/hi/benchmark/nextjs.md +6 -3
- package/docs/hi/benchmark/solid.md +21 -4
- package/docs/hi/benchmark/svelte.md +18 -3
- package/docs/hi/benchmark/tanstack.md +6 -3
- package/docs/hi/benchmark/vue.md +15 -6
- package/docs/hi/cli/index.md +6 -1
- package/docs/hi/cli/upgrade.md +125 -0
- package/docs/id/benchmark/nextjs.md +6 -3
- package/docs/id/benchmark/solid.md +21 -4
- package/docs/id/benchmark/svelte.md +18 -3
- package/docs/id/benchmark/tanstack.md +6 -3
- package/docs/id/benchmark/vue.md +15 -6
- package/docs/id/cli/index.md +6 -1
- package/docs/id/cli/upgrade.md +125 -0
- package/docs/it/benchmark/nextjs.md +6 -3
- package/docs/it/benchmark/solid.md +21 -4
- package/docs/it/benchmark/svelte.md +18 -3
- package/docs/it/benchmark/tanstack.md +6 -3
- package/docs/it/benchmark/vue.md +14 -5
- package/docs/it/cli/index.md +6 -1
- package/docs/it/cli/upgrade.md +125 -0
- package/docs/ja/benchmark/nextjs.md +6 -3
- package/docs/ja/benchmark/solid.md +21 -4
- package/docs/ja/benchmark/svelte.md +18 -3
- package/docs/ja/benchmark/tanstack.md +5 -2
- package/docs/ja/benchmark/vue.md +14 -5
- package/docs/ja/cli/index.md +6 -1
- package/docs/ja/cli/upgrade.md +125 -0
- package/docs/ko/benchmark/nextjs.md +6 -3
- package/docs/ko/benchmark/solid.md +21 -4
- package/docs/ko/benchmark/svelte.md +18 -3
- package/docs/ko/benchmark/tanstack.md +6 -3
- package/docs/ko/benchmark/vue.md +15 -6
- package/docs/ko/cli/index.md +6 -1
- package/docs/ko/cli/upgrade.md +126 -0
- package/docs/pl/benchmark/nextjs.md +6 -3
- package/docs/pl/benchmark/solid.md +21 -4
- package/docs/pl/benchmark/svelte.md +18 -3
- package/docs/pl/benchmark/tanstack.md +6 -3
- package/docs/pl/benchmark/vue.md +15 -6
- package/docs/pl/cli/index.md +6 -1
- package/docs/pl/cli/upgrade.md +125 -0
- package/docs/pt/benchmark/nextjs.md +6 -3
- package/docs/pt/benchmark/solid.md +21 -4
- package/docs/pt/benchmark/svelte.md +18 -3
- package/docs/pt/benchmark/tanstack.md +6 -3
- package/docs/pt/benchmark/vue.md +14 -5
- package/docs/pt/cli/index.md +6 -1
- package/docs/pt/cli/upgrade.md +125 -0
- package/docs/ru/benchmark/nextjs.md +6 -3
- package/docs/ru/benchmark/solid.md +21 -4
- package/docs/ru/benchmark/svelte.md +18 -3
- package/docs/ru/benchmark/tanstack.md +6 -3
- package/docs/ru/benchmark/vue.md +15 -6
- package/docs/ru/cli/index.md +6 -1
- package/docs/ru/cli/upgrade.md +125 -0
- package/docs/tr/benchmark/nextjs.md +6 -3
- package/docs/tr/benchmark/solid.md +21 -4
- package/docs/tr/benchmark/svelte.md +18 -3
- package/docs/tr/benchmark/tanstack.md +6 -3
- package/docs/tr/benchmark/vue.md +15 -6
- package/docs/tr/cli/index.md +6 -1
- package/docs/tr/cli/upgrade.md +125 -0
- package/docs/uk/benchmark/nextjs.md +6 -3
- package/docs/uk/benchmark/solid.md +21 -4
- package/docs/uk/benchmark/svelte.md +18 -3
- package/docs/uk/benchmark/tanstack.md +6 -3
- package/docs/uk/benchmark/vue.md +15 -6
- package/docs/uk/cli/index.md +6 -1
- package/docs/uk/cli/upgrade.md +125 -0
- package/docs/vi/benchmark/nextjs.md +6 -3
- package/docs/vi/benchmark/solid.md +21 -4
- package/docs/vi/benchmark/svelte.md +18 -3
- package/docs/vi/benchmark/tanstack.md +6 -3
- package/docs/vi/benchmark/vue.md +15 -6
- package/docs/vi/cli/index.md +6 -1
- package/docs/vi/cli/upgrade.md +125 -0
- package/docs/zh/benchmark/nextjs.md +6 -3
- package/docs/zh/benchmark/solid.md +21 -4
- package/docs/zh/benchmark/svelte.md +18 -3
- package/docs/zh/benchmark/tanstack.md +5 -2
- package/docs/zh/benchmark/vue.md +15 -6
- package/docs/zh/cli/index.md +6 -1
- package/docs/zh/cli/upgrade.md +125 -0
- package/package.json +6 -6
- package/src/generated/blog.entry.ts +20 -0
- package/src/generated/docs.entry.ts +20 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-23
|
|
3
|
+
updatedAt: 2026-09-23
|
|
4
|
+
title: O Intlayer é mais leve que o Paraglide?
|
|
5
|
+
description: O Paraglide parece quase gratuito nos benchmarks de i18n porque seu código é gerado diretamente no seu repositório. Veja para onde esse peso realmente vai, por que a resolução de locale por nó consome recursos e como o carregamento dinâmico do Intlayer envia apenas um idioma em vez de todos.
|
|
6
|
+
keywords:
|
|
7
|
+
- Paraglide
|
|
8
|
+
- Intlayer
|
|
9
|
+
- Internacionalização
|
|
10
|
+
- i18n
|
|
11
|
+
- Bundle size
|
|
12
|
+
- Tree shaking
|
|
13
|
+
- Benchmark
|
|
14
|
+
- Blog
|
|
15
|
+
slugs:
|
|
16
|
+
- blog
|
|
17
|
+
- is-intlayer-lighter-than-paraglide
|
|
18
|
+
author: aymericzip
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# O Intlayer é mais leve que o Paraglide?
|
|
22
|
+
|
|
23
|
+
Sim.
|
|
24
|
+
|
|
25
|
+
O `Paraglide` tem uma boa reputação por ser a solução de i18n mais leve disponível, e à primeira vista o [benchmark](https://intlayer.org/pt/doc/benchmark/tanstack) concorda: o tamanho de sua biblioteca é próximo de zero. Mas um tamanho de biblioteca de zero não significa zero bytes enviados. Significa apenas que os bytes residem onde a métrica não olha.
|
|
26
|
+
|
|
27
|
+
<TOC/>
|
|
28
|
+
|
|
29
|
+
## Principais conclusões
|
|
30
|
+
|
|
31
|
+
**O tamanho da biblioteca está oculto, não eliminado:**
|
|
32
|
+
|
|
33
|
+
O Paraglide gera sua runtime e funções de mensagens diretamente na sua codebase. Esse código é enviado ao navegador, mas é contabilizado como _seu_ código, não como o da biblioteca.
|
|
34
|
+
|
|
35
|
+
**Não ter provider não é um ganho gratuito:**
|
|
36
|
+
|
|
37
|
+
Cada chamada a `m.my_key()` resolve o locale por conta própria, lendo o cookie ou o storage para cada nó renderizado, em vez de ler uma única vez a partir de um contexto.
|
|
38
|
+
|
|
39
|
+
**Sem carregamento dinâmico:**
|
|
40
|
+
|
|
41
|
+
O Paraglide importa todos os idiomas de uma mensagem no bundle do seu cliente. O Intlayer com `importMode: 'dynamic'` ou `'fetch'` carrega apenas o idioma que está sendo renderizado.
|
|
42
|
+
|
|
43
|
+
**O tree shaking não é garantido:**
|
|
44
|
+
|
|
45
|
+
Em alguns de nossos benchmarks, o tree shaking divulgado pelo Paraglide não teve efeito. Verifique o seu próprio bundle.
|
|
46
|
+
|
|
47
|
+
## Para onde vai o peso do Paraglide?
|
|
48
|
+
|
|
49
|
+
Nos relatórios de benchmark, a métrica "tamanho da biblioteca" mede o provider e os hooks de cada biblioteca de i18n em um componente vazio, antes de qualquer conteúdo ser adicionado.
|
|
50
|
+
|
|
51
|
+
| Biblioteca (TanStack Start) | Tam lib (gz) | Tam lib (min) |
|
|
52
|
+
| ----------------------------- | ------------ | ------------- |
|
|
53
|
+
| `@inlang/paraglide-js@2.15.1` | 1.8 KB | 4.5 KB |
|
|
54
|
+
| `react-intlayer@9.5.1` | 5.0 KB | 15.2 KB |
|
|
55
|
+
|
|
56
|
+
Analisado isoladamente, o Paraglide vence. Mas o Paraglide é um compilador: ele lê seus arquivos `messages/*.json` e escreve uma pasta `paraglide/` no seu repositório, contendo um arquivo `runtime.js` (detecção de locale, estratégias de cookies e storage, localização de URLs) e uma função JavaScript por mensagem.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
src/paraglide/
|
|
60
|
+
├── runtime.js # detecção de locale, estratégias, helpers de URL
|
|
61
|
+
├── server.js
|
|
62
|
+
├── messages.js # reexporta todas as mensagens
|
|
63
|
+
└── messages/
|
|
64
|
+
├── _index.js
|
|
65
|
+
├── en.js
|
|
66
|
+
└── fr.js
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Como esse código fica na sua pasta `src/` e você o importa através de um caminho relativo, o bundler o atribui à sua aplicação, e não a um pacote em `node_modules`. A coluna de tamanho da biblioteca exibe quase nada, enquanto a mesma lógica continua sendo enviada no bundle da sua página.
|
|
70
|
+
|
|
71
|
+
Gerar código não é uma má ideia em si: a runtime gerada inclui apenas a lógica que sua configuração precisa (estratégia de prefixo, cookie vs. local storage, etc.). O Intlayer alcança o mesmo resultado de maneira diferente, injetando variáveis de ambiente em tempo de build para que o bundler descarte as ramificações que sua configuração não utiliza. Ambas as abordagens acabam sendo de 3 a 10 vezes mais leves do que `i18next` ou `next-intl`.
|
|
72
|
+
|
|
73
|
+
Portanto, a comparação justa não é o tamanho da biblioteca. É **o JavaScript realmente enviado por página**.
|
|
74
|
+
|
|
75
|
+
## Peso por página, medido
|
|
76
|
+
|
|
77
|
+
Aplicação TanStack Start, 10 páginas, medido nas rotas `en` e `fr`, comprimido com gzip:
|
|
78
|
+
|
|
79
|
+
| Configuração | JS pág médio (gz) | Acima da base | Vazamento locale | Vazamento outras págs |
|
|
80
|
+
| ---------------------------------- | ----------------- | ------------- | ---------------- | --------------------- |
|
|
81
|
+
| Base (sem i18n) | 111.0 KB | - | 0.0% | 0.0% |
|
|
82
|
+
| `paraglide` (qualquer estratégia) | 125.1 KB | +14.1 KB | 49.7% | 0.0% |
|
|
83
|
+
| `intlayer` (`importMode: static`) | 125.8 KB | +14.8 KB | 50.0% | 0.0% |
|
|
84
|
+
| `intlayer` (`importMode: dynamic`) | **118.6 KB** | **+7.6 KB** | **0.0%** | **0.0%** |
|
|
85
|
+
|
|
86
|
+
Next.js 16 App Router, mesma aplicação:
|
|
87
|
+
|
|
88
|
+
| Configuração | JS pág médio (gz) | Acima da base |
|
|
89
|
+
| ---------------- | ----------------- | ------------- |
|
|
90
|
+
| Base (sem i18n) | 141.0 KB | - |
|
|
91
|
+
| `paraglide-next` | 155.3 KB | +14.3 KB |
|
|
92
|
+
| `next-intlayer` | **141.3 KB** | **+0.3 KB** |
|
|
93
|
+
|
|
94
|
+
<I18nBenchmark framework="tanstack" vertical/>
|
|
95
|
+
|
|
96
|
+
> Dados completos no [relatório de benchmark TanStack Start](https://intlayer.org/pt/doc/benchmark/tanstack) e no [relatório de benchmark Next.js](https://intlayer.org/pt/doc/benchmark/nextjs). Cada bundle pode ser inspecionado no [repositório do benchmark](https://github.com/intlayer-org/benchmark-i18n).
|
|
97
|
+
|
|
98
|
+
Dois pontos se destacam:
|
|
99
|
+
|
|
100
|
+
- No modo `static`, o Intlayer envia praticamente o mesmo conteúdo que o Paraglide (125.8 KB vs. 125.1 KB). Isso é esperado: ambos incluem todos os idiomas das mensagens que uma página utiliza.
|
|
101
|
+
- O Paraglide permanece em 125.1 KB independentemente da estratégia, pois não possui um modo dinâmico. Cada linha na tabela acima corresponde à opção estática.
|
|
102
|
+
|
|
103
|
+
## Sem Provider: uma ideia que parece boa, mas não é
|
|
104
|
+
|
|
105
|
+
O Paraglide não requer provider. Você importa uma mensagem e a executa:
|
|
106
|
+
|
|
107
|
+
```tsx fileName="Hero.tsx"
|
|
108
|
+
import { m } from "../paraglide/messages.js";
|
|
109
|
+
|
|
110
|
+
export const Hero = () => (
|
|
111
|
+
<section>
|
|
112
|
+
<h1>{m.hero_title()}</h1>
|
|
113
|
+
<p>{m.hero_description()}</p>
|
|
114
|
+
<button>{m.hero_cta()}</button>
|
|
115
|
+
</section>
|
|
116
|
+
);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Sem contexto, sem wrapper, sem hook. Parece mais simples. Porém, o locale ainda precisa vir de algum lugar. Cada função de mensagem gerada se parece com isto (simplificado):
|
|
120
|
+
|
|
121
|
+
```js fileName="paraglide/messages/_index.js"
|
|
122
|
+
export const hero_title = (inputs = {}, options = {}) => {
|
|
123
|
+
const locale = options.locale ?? getLocale(); // resolvido a cada chamada
|
|
124
|
+
|
|
125
|
+
if (locale === "en") return en.hero_title(inputs);
|
|
126
|
+
if (locale === "fr") return fr.hero_title(inputs);
|
|
127
|
+
// ...uma ramificação por locale
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
E `getLocale()` percorre as estratégias configuradas (cookie, local storage, URL, locale padrão) para identificar o locale atual. Assim, cada nó de texto renderizado (`<>{m.my_key()}</>`) executa sua própria resolução de locale, incluindo ler `document.cookie` no navegador. Uma página com 200 strings traduzidas resolve o locale 200 vezes por renderização, e novamente a cada nova renderização.
|
|
132
|
+
|
|
133
|
+
Uma biblioteca baseada em provider lê o locale **uma única vez**, o armazena em um contexto (ou sinal, ou store), e cada nó lê um valor já residente na memória. O provider custa algumas centenas de bytes. Deixar de usá-lo consome ciclos de CPU a cada renderização, o que se reflete no benchmark: os tempos de carregamento de página e troca de idioma do Paraglide ficam sistematicamente atrás dos do Intlayer no TanStack Start (22.1 ms vs. 14.6 ms no carregamento de página, 4.3 ms vs. 3.2 ms na reatividade E2E).
|
|
134
|
+
|
|
135
|
+
## Experiência do Desenvolvedor (DX)
|
|
136
|
+
|
|
137
|
+
A fonte da verdade do Paraglide é o JSON, mas você nunca importa o JSON diretamente. Você importa o arquivo `.js` gerado:
|
|
138
|
+
|
|
139
|
+
<Tabs defaultTab="intlayer" group="techno">
|
|
140
|
+
<Tab label="Paraglide" value="paraglide">
|
|
141
|
+
|
|
142
|
+
```json fileName="messages/en.json"
|
|
143
|
+
{
|
|
144
|
+
"hero_title": "Ship your app in every language"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```json fileName="messages/pt.json"
|
|
149
|
+
{
|
|
150
|
+
"hero_title": "Publique seu app em todos os idiomas"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```tsx fileName="Hero.tsx"
|
|
155
|
+
// Existe apenas após o compilador regenerá-lo a partir do JSON
|
|
156
|
+
import { m } from "../paraglide/messages.js";
|
|
157
|
+
|
|
158
|
+
export const Hero = () => <h1>{m.hero_title()}</h1>;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
</Tab>
|
|
162
|
+
<Tab label="Intlayer" value="intlayer">
|
|
163
|
+
|
|
164
|
+
```ts fileName="Hero.content.ts"
|
|
165
|
+
import { t, type Dictionary } from "intlayer";
|
|
166
|
+
|
|
167
|
+
export default {
|
|
168
|
+
key: "hero",
|
|
169
|
+
content: {
|
|
170
|
+
title: t({
|
|
171
|
+
pt: "Publique seu app em todos os idiomas",
|
|
172
|
+
en: "Ship your app in every language",
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
} satisfies Dictionary;
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```tsx fileName="Hero.tsx"
|
|
179
|
+
import { useIntlayer } from "react-intlayer";
|
|
180
|
+
|
|
181
|
+
export const Hero = () => {
|
|
182
|
+
const { title } = useIntlayer("hero");
|
|
183
|
+
|
|
184
|
+
return <h1>{title}</h1>;
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
</Tab>
|
|
189
|
+
</Tabs>
|
|
190
|
+
|
|
191
|
+
Esse fluxo de desenvolvimento tem um custo:
|
|
192
|
+
|
|
193
|
+
- Cada alteração em um arquivo JSON exige regeneração antes que a importação resolva ou os tipos sejam atualizados.
|
|
194
|
+
- A pasta gerada `paraglide/` deve ser commitada (gerando conflitos de merge em arquivos gerados em cada PR que altere textos) ou ignorada (exigindo uma etapa de geração prévia a cada verificação de tipos, testes e job de CI).
|
|
195
|
+
- Cada string vira uma chamada de função. Constantes tornam-se `m.key()` em todos os lugares, inclusive onde um valor estático bastaria.
|
|
196
|
+
|
|
197
|
+
## Tree Shaking: verifique seu bundle
|
|
198
|
+
|
|
199
|
+
A promessa central do Paraglide é que mensagens não utilizadas sofrem tree shaking, já que cada mensagem é seu próprio export. No benchmark com Svelte + Vite, isso funciona conforme divulgado.
|
|
200
|
+
|
|
201
|
+
Em outros cenários, não funcionou. Em nossos testes no [Next.js](https://intlayer.org/pt/doc/benchmark/nextjs), as páginas do Paraglide pesam 14 KB a mais do que a aplicação base, enquanto o `next-intlayer` adiciona apenas 0.3 KB. Execuções anteriores no TanStack Start também mostraram mensagens de outras páginas indo parar no bundle da rota.
|
|
202
|
+
|
|
203
|
+
O tree shaking depende do seu bundler (Turbopack, Rolldown, Rollup), de como as mensagens são importadas (`import { m }` vs. `import * as m`) e da análise de side effects. Se você optar pelo Paraglide pelo seu tamanho, abra seu visualizador de bundle e comprove se isso se mantém na sua aplicação.
|
|
204
|
+
|
|
205
|
+
## Sem carregamento dinâmico
|
|
206
|
+
|
|
207
|
+
Este é o limite estrutural. O Paraglide não possui uma forma de carregar um idioma por vez: cada função de mensagem importa estaticamente a implementação de cada idioma, portanto todos os idiomas acabam no bundle do seu cliente.
|
|
208
|
+
|
|
209
|
+
Com 2 idiomas, metade da sua carga de traduções é desperdiçada, o que equivale aos ~50% de vazamento de locale medidos acima. Com 10 idiomas, 90%. Com 30 idiomas, 97%.
|
|
210
|
+
|
|
211
|
+
Mudar para o carregamento dinâmico também não resolveria: com uma função por mensagem, carregar cada uma sob demanda resultaria em milhares de requisições.
|
|
212
|
+
|
|
213
|
+
O Intlayer permite que você escolha, globalmente ou por dicionário:
|
|
214
|
+
|
|
215
|
+
```ts fileName="intlayer.config.ts"
|
|
216
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
217
|
+
|
|
218
|
+
const config: IntlayerConfig = {
|
|
219
|
+
internationalization: {
|
|
220
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
221
|
+
defaultLocale: Locales.ENGLISH,
|
|
222
|
+
},
|
|
223
|
+
dictionary: {
|
|
224
|
+
importMode: "dynamic", // 'static' | 'dynamic' | 'fetch'
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export default config;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
| `importMode` | O que é enviado ao cliente | vs. Paraglide |
|
|
232
|
+
| ------------ | ----------------------------------------------------------- | ------------------------------- |
|
|
233
|
+
| `static` | Todos os idiomas dos dicionários usados pela página | Teoricamente o mesmo conteúdo |
|
|
234
|
+
| `dynamic` | Apenas o idioma atual, carregado sob demanda por dicionário | **N vezes menor** com N idiomas |
|
|
235
|
+
| `fetch` | Apenas o idioma atual, buscado através da Live Sync API | **N vezes menor** com N idiomas |
|
|
236
|
+
|
|
237
|
+
Com a [transformação no build](https://intlayer.org/pt/doc/concept/bundle-optimization) e `importMode: 'static'`, o Intlayer carrega, em teoria, exatamente o mesmo conteúdo que o Paraglide. Com `'dynamic'` ou `'fetch'`, ele carrega apenas o que o idioma atual necessita: para um app em N idiomas, a carga de tradução é N vezes menor do que a do Paraglide.
|
|
238
|
+
|
|
239
|
+
## Onde o Paraglide ainda se encaixa
|
|
240
|
+
|
|
241
|
+
<AccordionGroup>
|
|
242
|
+
<Accordion header="Svelte + Vite com poucos idiomas">
|
|
243
|
+
|
|
244
|
+
Se a sua stack é Svelte com Vite e você suporta dois ou três idiomas, o tree shaking funciona como anunciado e o overhead de idiomas permanece pequeno.
|
|
245
|
+
|
|
246
|
+
</Accordion>
|
|
247
|
+
<Accordion header="Fluxo de trabalho inlang existente">
|
|
248
|
+
|
|
249
|
+
Se sua equipe já utiliza o ecossistema inlang (Fink, Sherlock, plugins de formato de mensagens), o Paraglide se integra a ele nativamente.
|
|
250
|
+
|
|
251
|
+
</Accordion>
|
|
252
|
+
</AccordionGroup>
|
|
253
|
+
|
|
254
|
+
## Teste na sua aplicação
|
|
255
|
+
|
|
256
|
+
Avalie o payload e os vazamentos de locale da sua aplicação em produção com o [i18n SEO Scanner](https://intlayer.org/i18n-seo-scanner) gratuito:
|
|
257
|
+
|
|
258
|
+
<ClickToOpenIframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
259
|
+
|
|
260
|
+
Para instalar o Intlayer:
|
|
261
|
+
|
|
262
|
+
```bash packageManager="npm"
|
|
263
|
+
npx intlayer init --interactive
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```bash packageManager="pnpm"
|
|
267
|
+
pnpm dlx intlayer init --interactive
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```bash packageManager="yarn"
|
|
271
|
+
yarn dlx intlayer init --interactive
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```bash packageManager="bun"
|
|
275
|
+
bunx intlayer init --interactive
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Leituras complementares
|
|
279
|
+
|
|
280
|
+
- [Benchmark de i18n TanStack Start](https://intlayer.org/pt/doc/benchmark/tanstack)
|
|
281
|
+
- [Benchmark de i18n Next.js](https://intlayer.org/pt/doc/benchmark/nextjs)
|
|
282
|
+
- [Otimização de bundle e `importMode`](https://intlayer.org/pt/doc/concept/bundle-optimization)
|
|
283
|
+
- [Como escolher uma biblioteca de i18n para React](https://intlayer.org/pt/blog/how-to-pick-react-i18n-library)
|
|
284
|
+
- [Por que escolher internacionalização orientada a compilador](https://intlayer.org/pt/blog/compiler-vs-declarative-i18n)
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-09-23
|
|
3
|
+
updatedAt: 2026-09-23
|
|
4
|
+
title: Intlayer легче, чем Paraglide?
|
|
5
|
+
description: Paraglide кажется практически невесомым в бенчмарках i18n, поскольку его код генерируется прямо в ваш репозиторий. Разбираемся, куда на самом деле уходит этот вес, почему чтение локали для каждого узла обходится дорого и как динамическая загрузка Intlayer отправляет одну локаль вместо всех.
|
|
6
|
+
keywords:
|
|
7
|
+
- Paraglide
|
|
8
|
+
- Intlayer
|
|
9
|
+
- Интернационализация
|
|
10
|
+
- i18n
|
|
11
|
+
- Bundle size
|
|
12
|
+
- Tree shaking
|
|
13
|
+
- Benchmark
|
|
14
|
+
- Blog
|
|
15
|
+
slugs:
|
|
16
|
+
- blog
|
|
17
|
+
- is-intlayer-lighter-than-paraglide
|
|
18
|
+
author: aymericzip
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Intlayer легче, чем Paraglide?
|
|
22
|
+
|
|
23
|
+
Да.
|
|
24
|
+
|
|
25
|
+
У `Paraglide` сложилась отличная репутация самого легкого решения для i18n, и на первый взгляд [бенчмарк](https://intlayer.org/ru/doc/benchmark/tanstack) с этим согласен: размер его библиотеки близок к нулю. Однако нулевой размер библиотеки вовсе не означает нулевое количество отправленных байтов. Это лишь говорит о том, что байты находятся там, куда эта метрика не заглядывает.
|
|
26
|
+
|
|
27
|
+
<TOC/>
|
|
28
|
+
|
|
29
|
+
## Ключевые выводы
|
|
30
|
+
|
|
31
|
+
**Размер библиотеки скрыт, а не устранен:**
|
|
32
|
+
|
|
33
|
+
Paraglide генерирует рантайм и функции сообщений непосредственно в вашу кодовую базу. Этот код отправляется в браузер, но учитывается как _ваш_ код, а не код библиотеки.
|
|
34
|
+
|
|
35
|
+
**Отсутствие провайдера - это не бесплатный выигрыш:**
|
|
36
|
+
|
|
37
|
+
Каждый вызов `m.my_key()` самостоятельно определяет локаль, считывая cookie или хранилище для каждого отрисованного узла, вместо того чтобы прочитать ее один раз из контекста.
|
|
38
|
+
|
|
39
|
+
**Нет динамической загрузки:**
|
|
40
|
+
|
|
41
|
+
Paraglide импортирует все локали сообщения в клиентский бандл. Intlayer с `importMode: 'dynamic'` или `'fetch'` загружает только ту локаль, которая сейчас отображается.
|
|
42
|
+
|
|
43
|
+
**Tree shaking не гарантирован:**
|
|
44
|
+
|
|
45
|
+
В некоторых наших тестах заявленный Paraglide tree shaking не сработал. Обязательно проверьте собственный бандл.
|
|
46
|
+
|
|
47
|
+
## Куда уходит вес Paraglide?
|
|
48
|
+
|
|
49
|
+
В отчетах бенчмарков метрика «размер библиотеки» измеряет провайдер и хуки каждой библиотеки i18n в пустом компоненте, до добавления какого-либо контента.
|
|
50
|
+
|
|
51
|
+
| Библиотека (TanStack Start) | Размер либы (gz) | Размер либы (min) |
|
|
52
|
+
| ----------------------------- | ---------------- | ----------------- |
|
|
53
|
+
| `@inlang/paraglide-js@2.15.1` | 1.8 KB | 4.5 KB |
|
|
54
|
+
| `react-intlayer@9.5.1` | 5.0 KB | 15.2 KB |
|
|
55
|
+
|
|
56
|
+
В отрыве от контекста Paraglide выигрывает. Но Paraglide - это компилятор: он читает ваши файлы `messages/*.json` и записывает папку `paraglide/` в ваш репозиторий. Она содержит `runtime.js` (определение локали, стратегии cookie и storage, локализация URL) и по одной JavaScript-функции на каждое сообщение.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
src/paraglide/
|
|
60
|
+
├── runtime.js # определение локали, стратегии, URL-хелперы
|
|
61
|
+
├── server.js
|
|
62
|
+
├── messages.js # реэкспорт всех сообщений
|
|
63
|
+
└── messages/
|
|
64
|
+
├── _index.js
|
|
65
|
+
├── en.js
|
|
66
|
+
└── fr.js
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Поскольку этот код находится в папке `src/` и вы импортируете его по относительному пути, сборщик приписывает его вашему приложению, а не пакету из `node_modules`. Колонка размера библиотеки почти ничего не показывает, хотя та же самая логика по-прежнему отправляется в бандле вашей страницы.
|
|
70
|
+
|
|
71
|
+
Генерация кода сама по себе неплоха: сгенерированный рантайм содержит только ту логику, которая нужна вашей конфигурации (стратегия префиксов, cookie или local storage и т. д.). Intlayer достигает того же результата иначе, внедряя переменные окружения на этапе сборки, благодаря чему бандлер удаляет ветви кода, не используемые вашей конфигурацией. Оба подхода оказываются в 3–10 раз легче, чем `i18next` или `next-intl`.
|
|
72
|
+
|
|
73
|
+
Поэтому честное сравнение - это не размер библиотеки. Это **JavaScript, фактически отправляемый на каждую страницу**.
|
|
74
|
+
|
|
75
|
+
## Измеренный вес страницы
|
|
76
|
+
|
|
77
|
+
Приложение TanStack Start, 10 страниц, измерения на маршрутах `en` и `fr`, сжатие gzip:
|
|
78
|
+
|
|
79
|
+
| Конфигурация | Средний JS стр (gz) | Выше базы | Утечка локали | Утечка других страниц |
|
|
80
|
+
| ---------------------------------- | ------------------- | ----------- | ------------- | --------------------- |
|
|
81
|
+
| Базовая (без i18n) | 111.0 KB | - | 0.0% | 0.0% |
|
|
82
|
+
| `paraglide` (любая стратегия) | 125.1 KB | +14.1 KB | 49.7% | 0.0% |
|
|
83
|
+
| `intlayer` (`importMode: static`) | 125.8 KB | +14.8 KB | 50.0% | 0.0% |
|
|
84
|
+
| `intlayer` (`importMode: dynamic`) | **118.6 KB** | **+7.6 KB** | **0.0%** | **0.0%** |
|
|
85
|
+
|
|
86
|
+
Next.js 16 App Router, то же приложение:
|
|
87
|
+
|
|
88
|
+
| Конфигурация | Средний JS стр (gz) | Выше базы |
|
|
89
|
+
| ------------------ | ------------------- | ----------- |
|
|
90
|
+
| Базовая (без i18n) | 141.0 KB | - |
|
|
91
|
+
| `paraglide-next` | 155.3 KB | +14.3 KB |
|
|
92
|
+
| `next-intlayer` | **141.3 KB** | **+0.3 KB** |
|
|
93
|
+
|
|
94
|
+
<I18nBenchmark framework="tanstack" vertical/>
|
|
95
|
+
|
|
96
|
+
> Полные данные приведены в [отчете о бенчмарке TanStack Start](https://intlayer.org/ru/doc/benchmark/tanstack) и в [отчете о бенчмарке Next.js](https://intlayer.org/ru/doc/benchmark/nextjs). Каждый бандл можно изучить в [репозитории бенчмарка](https://github.com/intlayer-org/benchmark-i18n).
|
|
97
|
+
|
|
98
|
+
Два момента бросаются в глаза:
|
|
99
|
+
|
|
100
|
+
- В режиме `static` Intlayer отправляет практически тот же объем данных, что и Paraglide (125.8 KB против 125.1 KB). Это ожидаемо: оба включают все локали сообщений, используемых страницей.
|
|
101
|
+
- Paraglide остается на уровне 125.1 KB при любой стратегии, поскольку в нем нет динамического режима. Каждая строка в таблице выше соответствует статической конфигурации.
|
|
102
|
+
|
|
103
|
+
## Отсутствие Provider: идея, кажущаяся хорошей лишь на первый взгляд
|
|
104
|
+
|
|
105
|
+
У Paraglide нет провайдера. Вы импортируете сообщение и вызываете его:
|
|
106
|
+
|
|
107
|
+
```tsx fileName="Hero.tsx"
|
|
108
|
+
import { m } from "../paraglide/messages.js";
|
|
109
|
+
|
|
110
|
+
export const Hero = () => (
|
|
111
|
+
<section>
|
|
112
|
+
<h1>{m.hero_title()}</h1>
|
|
113
|
+
<p>{m.hero_description()}</p>
|
|
114
|
+
<button>{m.hero_cta()}</button>
|
|
115
|
+
</section>
|
|
116
|
+
);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Ни контекста, ни обертки, ни хука. Это кажется проще. Но локаль все равно нужно откуда-то получать. Каждая сгенерированная функция сообщения выглядит приблизительно так (упрощенно):
|
|
120
|
+
|
|
121
|
+
```js fileName="paraglide/messages/_index.js"
|
|
122
|
+
export const hero_title = (inputs = {}, options = {}) => {
|
|
123
|
+
const locale = options.locale ?? getLocale(); // вычисляется при каждом вызове
|
|
124
|
+
|
|
125
|
+
if (locale === "en") return en.hero_title(inputs);
|
|
126
|
+
if (locale === "fr") return fr.hero_title(inputs);
|
|
127
|
+
// ...по одной ветке на каждую локаль
|
|
128
|
+
};
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
А `getLocale()` проходит по всем настроенным стратегиям (cookie, local storage, URL, базовая локаль), чтобы определить текущую локаль. Таким образом, каждый отрисовываемый текстовый узел (`<>{m.my_key()}</>`) выполняет собственное определение локали, включая чтение `document.cookie` в браузере. Страница с 200 переведенными строками вычисляет локаль 200 раз за один рендер, и затем повторно при каждом перерендере.
|
|
132
|
+
|
|
133
|
+
Библиотека с провайдером считывает локаль **один раз**, сохраняет ее в контексте (или сигнале, или сторе), и каждый узел читает значение, уже находящееся в оперативной памяти. Провайдер весит всего несколько сотен байт. Отказ от него нагружает процессор при каждом рендере, что наглядно отражается в бенчмарке: время загрузки страницы и скорость смены языка у Paraglide стабильно уступают Intlayer на TanStack Start (22.1 мс против 14.6 мс при загрузке страницы, 4.3 мс против 3.2 мс при реактивности E2E).
|
|
134
|
+
|
|
135
|
+
## Удобство разработки (DX)
|
|
136
|
+
|
|
137
|
+
Источником истины для Paraglide является JSON, но вы никогда не импортируете сам JSON. Вы импортируете сгенерированный файл `.js`:
|
|
138
|
+
|
|
139
|
+
<Tabs defaultTab="intlayer" group="techno">
|
|
140
|
+
<Tab label="Paraglide" value="paraglide">
|
|
141
|
+
|
|
142
|
+
```json fileName="messages/en.json"
|
|
143
|
+
{
|
|
144
|
+
"hero_title": "Ship your app in every language"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
```json fileName="messages/ru.json"
|
|
149
|
+
{
|
|
150
|
+
"hero_title": "Публикуйте ваше приложение на всех языках"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```tsx fileName="Hero.tsx"
|
|
155
|
+
// Существует только после перегенерации компилятором из JSON
|
|
156
|
+
import { m } from "../paraglide/messages.js";
|
|
157
|
+
|
|
158
|
+
export const Hero = () => <h1>{m.hero_title()}</h1>;
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
</Tab>
|
|
162
|
+
<Tab label="Intlayer" value="intlayer">
|
|
163
|
+
|
|
164
|
+
```ts fileName="Hero.content.ts"
|
|
165
|
+
import { t, type Dictionary } from "intlayer";
|
|
166
|
+
|
|
167
|
+
export default {
|
|
168
|
+
key: "hero",
|
|
169
|
+
content: {
|
|
170
|
+
title: t({
|
|
171
|
+
ru: "Публикуйте ваше приложение на всех языках",
|
|
172
|
+
en: "Ship your app in every language",
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
} satisfies Dictionary;
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
```tsx fileName="Hero.tsx"
|
|
179
|
+
import { useIntlayer } from "react-intlayer";
|
|
180
|
+
|
|
181
|
+
export const Hero = () => {
|
|
182
|
+
const { title } = useIntlayer("hero");
|
|
183
|
+
|
|
184
|
+
return <h1>{title}</h1>;
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
</Tab>
|
|
189
|
+
</Tabs>
|
|
190
|
+
|
|
191
|
+
Такой рабочий процесс влечет за собой издержки:
|
|
192
|
+
|
|
193
|
+
- Любое изменение в файле JSON требует перегенерации, прежде чем импорт заработает или обновятся типы.
|
|
194
|
+
- Сгенерированную папку `paraglide/` приходится либо коммитить в репозиторий (что приводит к конфликтам слияния при каждом PR с правками текста), либо добавлять в игнорируемые файлы (что требует шага генерации перед каждой проверкой типов, тестом и задачей CI).
|
|
195
|
+
- Каждая строка превращается в вызов функции. Константы становятся `m.key()` абсолютно везде, даже там, где подошло бы обычное статическое значение.
|
|
196
|
+
|
|
197
|
+
## Tree Shaking: проверьте свой бандл
|
|
198
|
+
|
|
199
|
+
Главное обещание Paraglide заключается в том, что неиспользуемые сообщения удаляются с помощью tree shaking, поскольку каждое сообщение является отдельным экспортом. В бенчмарке Svelte + Vite это работает именно так, как заявлено.
|
|
200
|
+
|
|
201
|
+
В других окружениях этого не произошло. В нашем тесте на [Next.js](https://intlayer.org/ru/doc/benchmark/nextjs) страницы Paraglide весят на 14 KB больше базового приложения, тогда как `next-intlayer` добавляет лишь 0.3 KB. Предыдущие тесты на TanStack Start также показали, что сообщения с других страниц попадали в бандл текущего маршрута.
|
|
202
|
+
|
|
203
|
+
Tree shaking зависит от вашего сборщика (Turbopack, Rolldown, Rollup), способа импорта сообщений (`import { m }` против `import * as m`) и анализа сайд-эффектов. Если вы выбираете Paraglide из-за размера, откройте анализатор бандла и убедитесь, что это действительно работает в вашем приложении.
|
|
204
|
+
|
|
205
|
+
## Нет динамической загрузки
|
|
206
|
+
|
|
207
|
+
Это фундаментальное структурное ограничение. В Paraglide нет способа загружать по одной локали за раз: каждая функция сообщения статически импортирует реализацию каждого языка, поэтому абсолютно все языки попадают в ваш клиентский бандл.
|
|
208
|
+
|
|
209
|
+
При 2 языках половина трафика на переводы тратится впустую, что соответствует утечке локали около ~50%, измеренной выше. При 10 языках бесполезны 90% объема. При 30 языках - 97%.
|
|
210
|
+
|
|
211
|
+
Переход на динамическую загрузку также не решил бы проблему: при наличии отдельной функции на каждое сообщение ленивая загрузка каждой из них привела бы к тысячам сетевых запросов.
|
|
212
|
+
|
|
213
|
+
Intlayer позволяет выбирать стратегию как глобально, так и для каждого словаря отдельно:
|
|
214
|
+
|
|
215
|
+
```ts fileName="intlayer.config.ts"
|
|
216
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
217
|
+
|
|
218
|
+
const config: IntlayerConfig = {
|
|
219
|
+
internationalization: {
|
|
220
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
221
|
+
defaultLocale: Locales.ENGLISH,
|
|
222
|
+
},
|
|
223
|
+
dictionary: {
|
|
224
|
+
importMode: "dynamic", // 'static' | 'dynamic' | 'fetch'
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
export default config;
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
| `importMode` | Что отправляется клиенту | vs. Paraglide |
|
|
232
|
+
| ------------ | ------------------------------------------------------------ | -------------------------------- |
|
|
233
|
+
| `static` | Все локали словарей, которые использует страница | Теоретически тот же объем |
|
|
234
|
+
| `dynamic` | Только активная локаль, ленивая загрузка для каждого словаря | **В N раз меньше** при N локалях |
|
|
235
|
+
| `fetch` | Только активная локаль, получаемая через Live Sync API | **В N раз меньше** при N локалях |
|
|
236
|
+
|
|
237
|
+
Благодаря [трансформации на этапе сборки](https://intlayer.org/ru/doc/concept/bundle-optimization) и режиму `importMode: 'static'`, Intlayer теоретически загружает ровно тот же объем данных, что и Paraglide. А в режимах `'dynamic'` или `'fetch'` он загружает только то, что требуется текущей локали: для приложения на N языках объем передаваемых переводов оказывается в N раз меньше, чем у Paraglide.
|
|
238
|
+
|
|
239
|
+
## Где Paraglide все еще уместен
|
|
240
|
+
|
|
241
|
+
<AccordionGroup>
|
|
242
|
+
<Accordion header="Svelte + Vite с небольшим количеством языков">
|
|
243
|
+
|
|
244
|
+
Если ваш стек - это Svelte с Vite и вы поддерживаете два или три языка, tree shaking работает как заявлено, а накладные расходы на лишние локали остаются незначительными.
|
|
245
|
+
|
|
246
|
+
</Accordion>
|
|
247
|
+
<Accordion header="Существующий рабочий процесс с inlang">
|
|
248
|
+
|
|
249
|
+
Если ваша команда уже использует экосистему inlang (Fink, Sherlock, плагины форматов сообщений), Paraglide нативно интегрируется в этот процесс.
|
|
250
|
+
|
|
251
|
+
</Accordion>
|
|
252
|
+
</AccordionGroup>
|
|
253
|
+
|
|
254
|
+
## Проверьте на своем приложении
|
|
255
|
+
|
|
256
|
+
Проверьте объем бандла и утечки локалей вашего рабочего приложения с помощью бесплатного инструмента [i18n SEO Scanner](https://intlayer.org/i18n-seo-scanner):
|
|
257
|
+
|
|
258
|
+
<ClickToOpenIframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
259
|
+
|
|
260
|
+
Установка Intlayer:
|
|
261
|
+
|
|
262
|
+
```bash packageManager="npm"
|
|
263
|
+
npx intlayer init --interactive
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```bash packageManager="pnpm"
|
|
267
|
+
pnpm dlx intlayer init --interactive
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```bash packageManager="yarn"
|
|
271
|
+
yarn dlx intlayer init --interactive
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```bash packageManager="bun"
|
|
275
|
+
bunx intlayer init --interactive
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Дополнительные материалы
|
|
279
|
+
|
|
280
|
+
- [Бенчмарк i18n в TanStack Start](https://intlayer.org/ru/doc/benchmark/tanstack)
|
|
281
|
+
- [Бенчмарк i18n в Next.js](https://intlayer.org/ru/doc/benchmark/nextjs)
|
|
282
|
+
- [Оптимизация бандла и `importMode`](https://intlayer.org/ru/doc/concept/bundle-optimization)
|
|
283
|
+
- [Как выбрать библиотеку i18n для React](https://intlayer.org/ru/blog/how-to-pick-react-i18n-library)
|
|
284
|
+
- [Аргументы в пользу компиляторного подхода к интернационализации](https://intlayer.org/ru/blog/compiler-vs-declarative-i18n)
|