@intlayer/docs 8.9.4-canary.0 → 8.9.5
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/dist/cjs/generated/docs.entry.cjs +20 -0
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +20 -0
- package/dist/esm/generated/docs.entry.mjs.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/index.md +0 -3
- package/docs/ar/benchmark/nextjs.md +15 -6
- package/docs/ar/benchmark/solid.md +155 -0
- package/docs/ar/benchmark/svelte.md +148 -0
- package/docs/ar/benchmark/tanstack.md +12 -3
- package/docs/ar/benchmark/vue.md +160 -0
- package/docs/ar/configuration.md +16 -12
- package/docs/ar/dictionary/content_file.md +51 -1
- package/docs/ar/mcp_server.md +30 -17
- package/docs/ar/plugins/sync-po.md +333 -0
- package/docs/bn/configuration.md +16 -12
- package/docs/cs/configuration.md +16 -12
- package/docs/de/benchmark/index.md +0 -3
- package/docs/de/benchmark/nextjs.md +15 -6
- package/docs/de/benchmark/solid.md +155 -0
- package/docs/de/benchmark/svelte.md +148 -0
- package/docs/de/benchmark/tanstack.md +12 -3
- package/docs/de/benchmark/vue.md +160 -0
- package/docs/de/configuration.md +16 -12
- package/docs/de/dictionary/content_file.md +52 -2
- package/docs/de/mcp_server.md +29 -16
- package/docs/de/plugins/sync-po.md +332 -0
- package/docs/en/benchmark/nextjs.md +11 -2
- package/docs/en/benchmark/solid.md +22 -4
- package/docs/en/benchmark/svelte.md +17 -5
- package/docs/en/benchmark/tanstack.md +18 -3
- package/docs/en/benchmark/vue.md +17 -11
- package/docs/en/configuration.md +16 -13
- package/docs/en/dictionary/content_file.md +51 -1
- package/docs/en/mcp_server.md +31 -18
- package/docs/en/plugins/sync-po.md +333 -0
- package/docs/en-GB/benchmark/index.md +0 -3
- package/docs/en-GB/benchmark/nextjs.md +15 -6
- package/docs/en-GB/benchmark/solid.md +155 -0
- package/docs/en-GB/benchmark/svelte.md +148 -0
- package/docs/en-GB/benchmark/tanstack.md +12 -3
- package/docs/en-GB/benchmark/vue.md +160 -0
- package/docs/en-GB/configuration.md +15 -11
- package/docs/en-GB/dictionary/content_file.md +51 -1
- package/docs/en-GB/mcp_server.md +31 -18
- package/docs/en-GB/plugins/sync-po.md +333 -0
- package/docs/es/benchmark/index.md +0 -3
- package/docs/es/benchmark/nextjs.md +15 -6
- package/docs/es/benchmark/solid.md +155 -0
- package/docs/es/benchmark/svelte.md +148 -0
- package/docs/es/benchmark/tanstack.md +12 -3
- package/docs/es/benchmark/vue.md +160 -0
- package/docs/es/configuration.md +16 -12
- package/docs/es/dictionary/content_file.md +51 -1
- package/docs/es/mcp_server.md +30 -17
- package/docs/es/plugins/sync-po.md +333 -0
- package/docs/fr/benchmark/index.md +0 -3
- package/docs/fr/benchmark/nextjs.md +15 -6
- package/docs/fr/benchmark/solid.md +155 -0
- package/docs/fr/benchmark/svelte.md +148 -0
- package/docs/fr/benchmark/tanstack.md +12 -3
- package/docs/fr/benchmark/vue.md +160 -0
- package/docs/fr/configuration.md +16 -12
- package/docs/fr/dictionary/content_file.md +51 -1
- package/docs/fr/mcp_server.md +30 -17
- package/docs/fr/plugins/sync-po.md +333 -0
- package/docs/hi/benchmark/nextjs.md +15 -6
- package/docs/hi/benchmark/solid.md +155 -0
- package/docs/hi/benchmark/svelte.md +148 -0
- package/docs/hi/benchmark/tanstack.md +12 -3
- package/docs/hi/benchmark/vue.md +160 -0
- package/docs/hi/configuration.md +16 -12
- package/docs/hi/dictionary/content_file.md +51 -1
- package/docs/hi/mcp_server.md +31 -18
- package/docs/hi/plugins/sync-po.md +333 -0
- package/docs/id/benchmark/index.md +0 -3
- package/docs/id/benchmark/nextjs.md +15 -6
- package/docs/id/benchmark/solid.md +155 -0
- package/docs/id/benchmark/svelte.md +148 -0
- package/docs/id/benchmark/tanstack.md +12 -3
- package/docs/id/benchmark/vue.md +160 -0
- package/docs/id/configuration.md +16 -12
- package/docs/id/dictionary/content_file.md +51 -1
- package/docs/id/mcp_server.md +30 -17
- package/docs/id/plugins/sync-po.md +333 -0
- package/docs/it/benchmark/index.md +1 -4
- package/docs/it/benchmark/nextjs.md +15 -6
- package/docs/it/benchmark/solid.md +155 -0
- package/docs/it/benchmark/svelte.md +148 -0
- package/docs/it/benchmark/tanstack.md +12 -3
- package/docs/it/benchmark/vue.md +160 -0
- package/docs/it/configuration.md +16 -12
- package/docs/it/dictionary/content_file.md +51 -1
- package/docs/it/mcp_server.md +30 -17
- package/docs/it/plugins/sync-po.md +333 -0
- package/docs/ja/benchmark/index.md +5 -5
- package/docs/ja/benchmark/nextjs.md +15 -6
- package/docs/ja/benchmark/solid.md +155 -0
- package/docs/ja/benchmark/svelte.md +148 -0
- package/docs/ja/benchmark/tanstack.md +12 -3
- package/docs/ja/benchmark/vue.md +160 -0
- package/docs/ja/configuration.md +16 -12
- package/docs/ja/dictionary/content_file.md +50 -2
- package/docs/ja/intlayer_with_nextjs_no_locale_path.md +4 -3
- package/docs/ja/mcp_server.md +29 -16
- package/docs/ja/plugins/sync-po.md +333 -0
- package/docs/ko/benchmark/nextjs.md +15 -6
- package/docs/ko/benchmark/solid.md +155 -0
- package/docs/ko/benchmark/svelte.md +148 -0
- package/docs/ko/benchmark/tanstack.md +12 -3
- package/docs/ko/benchmark/vue.md +160 -0
- package/docs/ko/configuration.md +16 -12
- package/docs/ko/dictionary/content_file.md +51 -1
- package/docs/ko/intlayer_with_nextjs_no_locale_path.md +3 -2
- package/docs/ko/mcp_server.md +31 -18
- package/docs/ko/plugins/sync-po.md +333 -0
- package/docs/nl/configuration.md +16 -12
- package/docs/pl/benchmark/index.md +0 -3
- package/docs/pl/benchmark/nextjs.md +15 -6
- package/docs/pl/benchmark/solid.md +155 -0
- package/docs/pl/benchmark/svelte.md +148 -0
- package/docs/pl/benchmark/tanstack.md +12 -3
- package/docs/pl/benchmark/vue.md +160 -0
- package/docs/pl/configuration.md +16 -12
- package/docs/pl/dictionary/content_file.md +51 -1
- package/docs/pl/mcp_server.md +30 -17
- package/docs/pl/plugins/sync-po.md +333 -0
- package/docs/pt/benchmark/index.md +0 -3
- package/docs/pt/benchmark/nextjs.md +16 -7
- package/docs/pt/benchmark/solid.md +155 -0
- package/docs/pt/benchmark/svelte.md +148 -0
- package/docs/pt/benchmark/tanstack.md +13 -4
- package/docs/pt/benchmark/vue.md +160 -0
- package/docs/pt/configuration.md +16 -12
- package/docs/pt/dictionary/content_file.md +51 -1
- package/docs/pt/mcp_server.md +30 -17
- package/docs/pt/plugins/sync-po.md +333 -0
- package/docs/ru/benchmark/nextjs.md +15 -6
- package/docs/ru/benchmark/solid.md +155 -0
- package/docs/ru/benchmark/svelte.md +148 -0
- package/docs/ru/benchmark/tanstack.md +12 -3
- package/docs/ru/benchmark/vue.md +160 -0
- package/docs/ru/configuration.md +16 -12
- package/docs/ru/dictionary/content_file.md +52 -2
- package/docs/ru/mcp_server.md +30 -17
- package/docs/ru/plugins/sync-po.md +333 -0
- package/docs/tr/benchmark/index.md +0 -3
- package/docs/tr/benchmark/nextjs.md +15 -6
- package/docs/tr/benchmark/solid.md +155 -0
- package/docs/tr/benchmark/svelte.md +148 -0
- package/docs/tr/benchmark/tanstack.md +12 -3
- package/docs/tr/benchmark/vue.md +160 -0
- package/docs/tr/configuration.md +16 -12
- package/docs/tr/dictionary/content_file.md +51 -1
- package/docs/tr/mcp_server.md +31 -18
- package/docs/tr/plugins/sync-po.md +333 -0
- package/docs/uk/benchmark/nextjs.md +15 -6
- package/docs/uk/benchmark/solid.md +155 -0
- package/docs/uk/benchmark/svelte.md +148 -0
- package/docs/uk/benchmark/tanstack.md +12 -3
- package/docs/uk/benchmark/vue.md +160 -0
- package/docs/uk/configuration.md +16 -12
- package/docs/uk/dictionary/content_file.md +51 -1
- package/docs/uk/mcp_server.md +29 -16
- package/docs/uk/plugins/sync-po.md +333 -0
- package/docs/ur/configuration.md +16 -12
- package/docs/vi/benchmark/index.md +0 -3
- package/docs/vi/benchmark/nextjs.md +15 -6
- package/docs/vi/benchmark/solid.md +155 -0
- package/docs/vi/benchmark/svelte.md +148 -0
- package/docs/vi/benchmark/tanstack.md +12 -3
- package/docs/vi/benchmark/vue.md +160 -0
- package/docs/vi/configuration.md +16 -12
- package/docs/vi/dictionary/content_file.md +51 -1
- package/docs/vi/intlayer_with_nextjs_15.md +10 -57
- package/docs/vi/mcp_server.md +30 -17
- package/docs/vi/plugins/sync-po.md +333 -0
- package/docs/zh/benchmark/nextjs.md +15 -6
- package/docs/zh/benchmark/solid.md +155 -0
- package/docs/zh/benchmark/svelte.md +148 -0
- package/docs/zh/benchmark/tanstack.md +12 -3
- package/docs/zh/benchmark/vue.md +160 -0
- package/docs/zh/configuration.md +16 -12
- package/docs/zh/dictionary/content_file.md +51 -3
- package/docs/zh/mcp_server.md +31 -18
- package/docs/zh/plugins/sync-po.md +333 -0
- package/frequent_questions/ar/intlayerNode.md +3 -3
- package/frequent_questions/de/intlayerNode.md +3 -3
- package/frequent_questions/en/intlayerNode.md +3 -3
- package/frequent_questions/en-GB/intlayerNode.md +3 -3
- package/frequent_questions/es/intlayerNode.md +3 -3
- package/frequent_questions/fr/intlayerNode.md +3 -3
- package/frequent_questions/hi/intlayerNode.md +3 -3
- package/frequent_questions/id/intlayerNode.md +3 -3
- package/frequent_questions/it/intlayerNode.md +3 -3
- package/frequent_questions/ja/intlayerNode.md +3 -3
- package/frequent_questions/ko/intlayerNode.md +3 -3
- package/frequent_questions/pl/intlayerNode.md +3 -3
- package/frequent_questions/pt/intlayerNode.md +3 -3
- package/frequent_questions/ru/intlayerNode.md +3 -3
- package/frequent_questions/tr/intlayerNode.md +3 -3
- package/frequent_questions/uk/intlayerNode.md +3 -3
- package/frequent_questions/vi/intlayerNode.md +3 -3
- package/frequent_questions/zh/intlayerNode.md +3 -3
- package/package.json +8 -8
- package/src/generated/docs.entry.ts +20 -0
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-05-10
|
|
3
|
+
updatedAt: 2026-05-10
|
|
4
|
+
title: Plugin Sync PO
|
|
5
|
+
description: Sincronize os dicionários Intlayer com arquivos Gettext PO. Mantenha seu i18n existente enquanto usa o Intlayer para gerenciar, traduzir e testar suas mensagens.
|
|
6
|
+
keywords:
|
|
7
|
+
- Intlayer
|
|
8
|
+
- Sync PO
|
|
9
|
+
- Gettext
|
|
10
|
+
- i18n
|
|
11
|
+
- traduções
|
|
12
|
+
slugs:
|
|
13
|
+
- doc
|
|
14
|
+
- plugin
|
|
15
|
+
- sync-po
|
|
16
|
+
youtubeVideo: https://www.youtube.com/watch?v=MpGMxniDHNg
|
|
17
|
+
history:
|
|
18
|
+
- version: 8.9.4
|
|
19
|
+
date: 2026-05-10
|
|
20
|
+
changes: "Documentação inicial do plugin Sync PO"
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Sync PO (pontes i18n) - Sync PO com suporte a ICU / i18next
|
|
24
|
+
|
|
25
|
+
Use o Intlayer como um complemento à sua stack de i18n existente. Este plugin mantém suas mensagens Gettext PO em sincronia com os dicionários Intlayer para que você possa:
|
|
26
|
+
|
|
27
|
+
- Manter seu fluxo de trabalho de tradução baseado em PO existente.
|
|
28
|
+
- Gerenciar e traduzir suas mensagens com o Intlayer (CLI, CI, provedores, CMS), sem refatorar seu aplicativo.
|
|
29
|
+
- Enviar tutoriais e conteúdo de SEO direcionados a cada ecossistema, sugerindo o Intlayer como a camada de gerenciamento de PO.
|
|
30
|
+
|
|
31
|
+
Notas e escopo atual:
|
|
32
|
+
|
|
33
|
+
- A externalização para o CMS funciona para traduções e texto clássico.
|
|
34
|
+
- Ainda não há suporte para inserções, plurais/ICU ou recursos avançados de tempo de execução de outras bibliotecas dentro das próprias entradas PO.
|
|
35
|
+
- O editor visual ainda não é suportado para saídas i18n de terceiros.
|
|
36
|
+
|
|
37
|
+
### Quando usar este plugin
|
|
38
|
+
|
|
39
|
+
- Você já usa arquivos Gettext PO para suas traduções.
|
|
40
|
+
- Você deseja preenchimento assistido por IA, testes em CI e operações de conteúdo sem alterar seu tempo de execução de renderização.
|
|
41
|
+
|
|
42
|
+
## Instalação
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pnpm add -D @intlayer/sync-po-plugin
|
|
46
|
+
# ou
|
|
47
|
+
npm i -D @intlayer/sync-po-plugin
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Plugins
|
|
51
|
+
|
|
52
|
+
Este pacote fornece dois plugins:
|
|
53
|
+
|
|
54
|
+
- `loadPO`: Carrega arquivos PO nos dicionários Intlayer.
|
|
55
|
+
- Este plugin é usado para carregar arquivos PO de uma fonte e eles serão carregados nos dicionários Intlayer. Ele pode escanear toda a base de código e procurar por arquivos PO específicos.
|
|
56
|
+
Este plugin pode ser usado:
|
|
57
|
+
- se você usa uma biblioteca i18n que impõe um local específico para que seus arquivos PO sejam carregados, mas você deseja colocar sua declaração de conteúdo onde preferir em sua base de código.
|
|
58
|
+
- Também pode ser usado se você desejar buscar suas mensagens de uma fonte remota (ex: um CMS, uma API, etc.) e armazenar suas mensagens em arquivos PO.
|
|
59
|
+
|
|
60
|
+
> Por baixo dos panos, este plugin escaneará toda a base de código e procurará por arquivos PO específicos e os carregará nos dicionários Intlayer.
|
|
61
|
+
> Observe que este plugin não gravará a saída e as traduções de volta nos arquivos PO.
|
|
62
|
+
|
|
63
|
+
- `syncPO`: Sincroniza arquivos PO com dicionários Intlayer.
|
|
64
|
+
- Este plugin é usado para sincronizar arquivos PO com dicionários Intlayer. Ele pode escanear o local fornecido e carregar o PO que corresponde ao padrão para arquivos PO específicos. Este plugin é útil se você deseja obter os benefícios do Intlayer enquanto usa outra biblioteca i18n.
|
|
65
|
+
|
|
66
|
+
## Usando ambos os plugins
|
|
67
|
+
|
|
68
|
+
```ts fileName="intlayer.config.ts"
|
|
69
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
70
|
+
import { loadPO, syncPO } from "@intlayer/sync-po-plugin";
|
|
71
|
+
|
|
72
|
+
const config: IntlayerConfig = {
|
|
73
|
+
internationalization: {
|
|
74
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
75
|
+
defaultLocale: Locales.ENGLISH,
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Mantenha seus arquivos PO atuais em sincronia com os dicionários Intlayer
|
|
79
|
+
plugins: [
|
|
80
|
+
/**
|
|
81
|
+
* Carregará todos os arquivos PO no src que correspondem ao padrão {key}.i18n.po
|
|
82
|
+
*/
|
|
83
|
+
loadPO({
|
|
84
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
85
|
+
locale: Locales.ENGLISH,
|
|
86
|
+
priority: 1, // Garante que esses arquivos PO tenham precedência sobre os arquivos em `./locales/en/${key}.po`
|
|
87
|
+
}),
|
|
88
|
+
/**
|
|
89
|
+
* Carregará e gravará a saída e as traduções de volta nos arquivos PO no diretório locales
|
|
90
|
+
*/
|
|
91
|
+
syncPO({
|
|
92
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
93
|
+
priority: 0,
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export default config;
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Plugin `syncPO`
|
|
102
|
+
|
|
103
|
+
### Início rápido
|
|
104
|
+
|
|
105
|
+
Adicione o plugin ao seu `intlayer.config.ts` e aponte-o para sua estrutura PO existente.
|
|
106
|
+
|
|
107
|
+
```ts fileName="intlayer.config.ts"
|
|
108
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
109
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
110
|
+
|
|
111
|
+
const config: IntlayerConfig = {
|
|
112
|
+
internationalization: {
|
|
113
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
114
|
+
defaultLocale: Locales.ENGLISH,
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
// Mantenha seus arquivos PO atuais em sincronia com os dicionários Intlayer
|
|
118
|
+
plugins: [
|
|
119
|
+
syncPO({
|
|
120
|
+
// Layout por idioma, por namespace
|
|
121
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
122
|
+
}),
|
|
123
|
+
],
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default config;
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Alternativa: arquivo único por idioma:
|
|
130
|
+
|
|
131
|
+
```ts fileName="intlayer.config.ts"
|
|
132
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
133
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
134
|
+
|
|
135
|
+
const config: IntlayerConfig = {
|
|
136
|
+
internationalization: {
|
|
137
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
138
|
+
defaultLocale: Locales.ENGLISH,
|
|
139
|
+
},
|
|
140
|
+
plugins: [
|
|
141
|
+
syncPO({
|
|
142
|
+
source: ({ locale }) => `./locales/${locale}.po`,
|
|
143
|
+
}),
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default config;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### Como funciona
|
|
151
|
+
|
|
152
|
+
- Leitura: o plugin descobre arquivos PO a partir do seu construtor `source` e os carrega como dicionários Intlayer.
|
|
153
|
+
- Gravação: após compilações e preenchimentos, ele grava o PO localizado de volta nos mesmos caminhos (com cabeçalhos Gettext apropriados).
|
|
154
|
+
- Preenchimento automático: o plugin declara um caminho `autoFill` para cada dicionário. Executar `intlayer fill` atualiza apenas as traduções ausentes em seus arquivos PO por padrão.
|
|
155
|
+
|
|
156
|
+
API:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
syncPO({
|
|
160
|
+
source: ({ key, locale }) => string, // obrigatório
|
|
161
|
+
location?: string, // rótulo opcional, padrão: "sync-po::path/to/source"
|
|
162
|
+
priority?: number, // prioridade opcional para resolução de conflitos, padrão: 0
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Múltiplas fontes PO e prioridade
|
|
167
|
+
|
|
168
|
+
Você pode adicionar vários plugins `syncPO` para sincronizar diferentes fontes PO. Isso é útil quando você tem várias fontes de tradução ou estruturas PO diferentes em seu projeto.
|
|
169
|
+
|
|
170
|
+
#### Sistema de prioridade
|
|
171
|
+
|
|
172
|
+
Quando vários plugins visam a mesma chave de dicionário, o parâmetro `priority` determina qual plugin tem precedência:
|
|
173
|
+
|
|
174
|
+
- Números de prioridade mais altos vencem os mais baixos
|
|
175
|
+
- A prioridade padrão dos arquivos `.content` é `0`
|
|
176
|
+
- A prioridade padrão dos plugins é `0`
|
|
177
|
+
- Plugins com a mesma prioridade são processados na ordem em que aparecem na configuração
|
|
178
|
+
|
|
179
|
+
```ts fileName="intlayer.config.ts"
|
|
180
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
181
|
+
import { syncPO } from "@intlayer/sync-po-plugin";
|
|
182
|
+
|
|
183
|
+
const config: IntlayerConfig = {
|
|
184
|
+
internationalization: {
|
|
185
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
186
|
+
defaultLocale: Locales.ENGLISH,
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
plugins: [
|
|
190
|
+
// Fonte PO primária (maior prioridade)
|
|
191
|
+
syncPO({
|
|
192
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
193
|
+
location: "main-translations",
|
|
194
|
+
priority: 10,
|
|
195
|
+
}),
|
|
196
|
+
|
|
197
|
+
// Fonte PO de fallback (prioridade mais baixa)
|
|
198
|
+
syncPO({
|
|
199
|
+
source: ({ locale }) => `./fallback-locales/${locale}.po`,
|
|
200
|
+
location: "fallback-translations",
|
|
201
|
+
priority: 5,
|
|
202
|
+
}),
|
|
203
|
+
|
|
204
|
+
// Fonte PO legada (prioridade mínima)
|
|
205
|
+
syncPO({
|
|
206
|
+
source: ({ locale }) => `/my/other/app/legacy/${locale}/messages.po`,
|
|
207
|
+
location: "legacy-translations",
|
|
208
|
+
priority: 1,
|
|
209
|
+
}),
|
|
210
|
+
],
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
export default config;
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Plugin Load PO
|
|
217
|
+
|
|
218
|
+
### Início rápido
|
|
219
|
+
|
|
220
|
+
Adicione o plugin ao seu `intlayer.config.ts` para ingerir arquivos PO existentes como dicionários Intlayer. Este plugin é apenas para leitura (sem gravações no disco):
|
|
221
|
+
|
|
222
|
+
```ts fileName="intlayer.config.ts"
|
|
223
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
224
|
+
import { loadPO } from "@intlayer/sync-po-plugin";
|
|
225
|
+
|
|
226
|
+
const config: IntlayerConfig = {
|
|
227
|
+
internationalization: {
|
|
228
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
229
|
+
defaultLocale: Locales.ENGLISH,
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
plugins: [
|
|
233
|
+
// Ingerir mensagens PO localizadas em qualquer lugar em sua árvore de fontes
|
|
234
|
+
loadPO({
|
|
235
|
+
source: ({ key }) => `./src/**/${key}.i18n.po`,
|
|
236
|
+
// Carregar um único idioma por instância de plugin (o padrão é o defaultLocale da configuração)
|
|
237
|
+
locale: Locales.ENGLISH,
|
|
238
|
+
priority: 0,
|
|
239
|
+
}),
|
|
240
|
+
],
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
export default config;
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Alternativa: layout por idioma, ainda apenas leitura (apenas o idioma selecionado é carregado):
|
|
247
|
+
|
|
248
|
+
```ts fileName="intlayer.config.ts"
|
|
249
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
250
|
+
import { loadPO } from "@intlayer/sync-po-plugin";
|
|
251
|
+
|
|
252
|
+
const config: IntlayerConfig = {
|
|
253
|
+
internationalization: {
|
|
254
|
+
locales: [Locales.ENGLISH, Locales.FRENCH],
|
|
255
|
+
defaultLocale: Locales.ENGLISH,
|
|
256
|
+
},
|
|
257
|
+
plugins: [
|
|
258
|
+
loadPO({
|
|
259
|
+
// Apenas arquivos para Locales.FRENCH serão carregados a partir deste padrão
|
|
260
|
+
source: ({ key, locale }) => `./locales/${locale}/${key}.po`,
|
|
261
|
+
locale: Locales.FRENCH,
|
|
262
|
+
}),
|
|
263
|
+
],
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
export default config;
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Como funciona
|
|
270
|
+
|
|
271
|
+
- Descoberta: constrói um glob a partir do seu construtor `source` e coleta arquivos PO correspondentes.
|
|
272
|
+
- Ingestão: carrega cada arquivo PO como um dicionário Intlayer com o `locale` fornecido.
|
|
273
|
+
- Apenas leitura: não grava nem formata arquivos de saída; use `syncPO` se precisar de sincronização de ida e volta.
|
|
274
|
+
- Pronto para preenchimento automático: define um caminho `fill` para que o `intlayer content fill` possa preencher as chaves ausentes.
|
|
275
|
+
|
|
276
|
+
### API
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
loadPO({
|
|
280
|
+
// Construir caminhos para seus POs. `locale` é opcional se sua estrutura não tiver segmento de idioma
|
|
281
|
+
source: ({ key, locale }) => string,
|
|
282
|
+
|
|
283
|
+
// Idioma de destino para os dicionários carregados por esta instância de plugin
|
|
284
|
+
// O padrão é configuration.internationalization.defaultLocale
|
|
285
|
+
locale?: Locale,
|
|
286
|
+
|
|
287
|
+
// Rótulo opcional para identificar a fonte
|
|
288
|
+
location?: string, // padrão: "plugin"
|
|
289
|
+
|
|
290
|
+
// Prioridade usada para resolução de conflitos com outras fontes
|
|
291
|
+
priority?: number, // padrão: 0
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Comportamento e convenções
|
|
296
|
+
|
|
297
|
+
- Se sua máscara `source` incluir um marcador de posição de idioma, apenas arquivos para o `locale` selecionado serão ingeridos.
|
|
298
|
+
- Se não houver um segmento `{key}` em sua máscara, a chave do dicionário será "index".
|
|
299
|
+
- As chaves são derivadas dos caminhos dos arquivos substituindo o marcador de posição `{key}` em seu construtor `source`.
|
|
300
|
+
- O plugin usa apenas arquivos descobertos e não fabrica idiomas ou chaves ausentes.
|
|
301
|
+
- O caminho `fill` é inferido a partir da sua `source` e usado para atualizar valores ausentes via CLI quando você aceita.
|
|
302
|
+
|
|
303
|
+
## Resolução de conflitos
|
|
304
|
+
|
|
305
|
+
Quando a mesma chave de tradução existe em várias fontes PO:
|
|
306
|
+
|
|
307
|
+
1. O plugin com a maior prioridade determina o valor final
|
|
308
|
+
2. Fontes de menor prioridade são usadas como fallback para chaves ausentes
|
|
309
|
+
3. Isso permite que você mantenha traduções legadas enquanto migra gradualmente para novas estruturas
|
|
310
|
+
|
|
311
|
+
## CLI
|
|
312
|
+
|
|
313
|
+
Os arquivos PO sincronizados serão considerados como outros arquivos `.content`. Isso significa que todos os comandos do intlayer estarão disponíveis para os arquivos PO sincronizados. Incluindo:
|
|
314
|
+
|
|
315
|
+
- `intlayer content test` para testar se há traduções ausentes
|
|
316
|
+
- `intlayer content list` para listar os arquivos PO sincronizados
|
|
317
|
+
- `intlayer content fill` para preencher as traduções ausentes
|
|
318
|
+
- `intlayer content push` para enviar os arquivos PO sincronizados
|
|
319
|
+
- `intlayer content pull` para baixar os arquivos PO sincronizados
|
|
320
|
+
|
|
321
|
+
Consulte o [Intlayer CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/cli/index.md) para mais detalhes.
|
|
322
|
+
|
|
323
|
+
## Limitações (atuais)
|
|
324
|
+
|
|
325
|
+
- Sem suporte para inserções ou plurais/ICU ao visar bibliotecas de terceiros.
|
|
326
|
+
- O editor visual ainda não está disponível para tempos de execução que não sejam Intlayer.
|
|
327
|
+
- Sincronização PO apenas; formatos de catálogo não-PO não são suportados.
|
|
328
|
+
|
|
329
|
+
## Por que isso importa
|
|
330
|
+
|
|
331
|
+
- Podemos recomendar soluções de i18n estabelecidas e posicionar o Intlayer como um complemento.
|
|
332
|
+
- Aproveitamos seu SEO/palavras-chave com tutoriais que terminam sugerindo o Intlayer para gerenciar PO.
|
|
333
|
+
- Expande o público endereçável de “novos projetos” para “qualquer equipe que já use i18n”.
|
|
@@ -61,6 +61,13 @@ history:
|
|
|
61
61
|
|
|
62
62
|
Intlayer пытается оптимизировать все эти аспекты.
|
|
63
63
|
|
|
64
|
+
## TL;DR
|
|
65
|
+
|
|
66
|
+
- **Intlayer** и **next-translate**: Лучшие варианты для производительности Next.js, предлагающие минимальный размер и лучшую поддержку статического рендеринга.
|
|
67
|
+
- **next-intl**: Самый модный вариант, но тяжелый и сложный в оптимизации для больших приложений.
|
|
68
|
+
- **next-i18next**: Популярный и богатый плагинами, но имеет значительный вес бандла (~3× Intlayer).
|
|
69
|
+
- **Избегайте**: **gt-next** и **lingo.dev** из-за серьезных проблем с производительностью, привязки к вендору и багов, ломающих сборку.
|
|
70
|
+
|
|
64
71
|
## Проверьте свое приложение
|
|
65
72
|
|
|
66
73
|
Чтобы выявить эти проблемы, я создал бесплатный сканер, который вы можете попробовать [здесь](https://intlayer.org/i18n-seo-scanner).
|
|
@@ -99,14 +106,14 @@ Intlayer пытается оптимизировать все эти аспек
|
|
|
99
106
|
Для этого бенчмарка мы сравнили следующие библиотеки:
|
|
100
107
|
|
|
101
108
|
- `Base App` (Без библиотеки i18n)
|
|
102
|
-
- `next-intlayer` (v8.7.
|
|
109
|
+
- `next-intlayer` (v8.7.12)
|
|
103
110
|
- `next-i18next` (v16.0.5)
|
|
104
111
|
- `next-intl` (v4.9.1)
|
|
105
112
|
- `@lingui/core` (v5.3.0)
|
|
106
113
|
- `next-translate` (v3.1.2)
|
|
107
114
|
- `next-international` (v1.3.1)
|
|
108
115
|
- `@inlang/paraglide-js` (v2.15.1)
|
|
109
|
-
-
|
|
116
|
+
- `@tolgee/react` (v7.0.0)
|
|
110
117
|
- `@lingo.dev/compiler` (v0.4.0)
|
|
111
118
|
- `wuchale` (v0.22.11)
|
|
112
119
|
- `gt-next` (v6.16.5)
|
|
@@ -161,10 +168,10 @@ Intlayer пытается оптимизировать все эти аспек
|
|
|
161
168
|
|
|
162
169
|
**(General Translation)** (`gt-next@6.16.5`):
|
|
163
170
|
|
|
164
|
-
- Для приложения весом 110 КБ `gt-
|
|
171
|
+
- Для приложения весом 110 КБ `gt-next` добавляет более 440 КБ сверху.
|
|
165
172
|
- `Quota Exceeded, please upgrade your plan` (Квота превышена, пожалуйста, обновите тарифный план) при самой первой сборке с General Translation.
|
|
166
173
|
- Переводы не отображаются; я получаю ошибку `Error: <T> used on the client-side outside of <GTProvider>`, что кажется багом библиотеки.
|
|
167
|
-
- При внедрении **gt-
|
|
174
|
+
- При внедрении **gt-next** я также столкнулся с [проблемой](https://github.com/generaltranslation/gt/issues/1210#event-24510646961) в библиотеке: `does not provide an export named 'printAST' - @formatjs/icu-messageformat-parser`, которая приводила к поломке приложения. После сообщения об этой проблеме сопровождающий исправил ее в течение 24 часов.
|
|
168
175
|
- Библиотека блокирует статический рендеринг страниц Next.js.
|
|
169
176
|
|
|
170
177
|
**(Lingo.dev)** (`@lingo.dev/compiler@0.4.0`):
|
|
@@ -186,9 +193,11 @@ Intlayer пытается оптимизировать все эти аспек
|
|
|
186
193
|
Лично мне не нравится необходимость перегенерировать JS-файлы перед каждым пушем, что создает постоянный риск конфликтов слияния в PR. Инструмент также кажется более ориентированным на Vite, чем на Next.js.
|
|
187
194
|
Наконец, по сравнению с другими решениями, Paraglide не использует хранилище (например, React context) для получения текущей локали для рендеринга контента. Для каждого обрабатываемого узла он запрашивает локаль из localStorage / куки и т.д. Это приводит к выполнению ненужной логики, которая влияет на реактивность компонентов.
|
|
188
195
|
|
|
196
|
+
> Примечание по paraglide: решение внедряет код в вашу кодовую базу для импорта, в результате показатель 'размер библиотеки' в отчете о бенчмарке практически равен 0. Генерация кода — это хорошо, так как используемая функция будет включать только необходимую логику (все префиксы против отсутствия префиксов, куки против хранилища и т.д.). В сравнении с этим, Intlayer выполняет фильтрацию с помощью внедрения переменных окружения в сборку, чтобы заставить сборщик исключить контент в зависимости от логики. Благодаря этому paraglide и intlayer оказываются в 6-10 раз легче, чем i18next или next-intl.
|
|
197
|
+
|
|
189
198
|
### 3 — Приемлемые решения
|
|
190
199
|
|
|
191
|
-
**(Tolgee)** (
|
|
200
|
+
**(Tolgee)** (`@tolgee/react@7.0.0`):
|
|
192
201
|
|
|
193
202
|
`Tolgee` решает многие из упомянутых ранее проблем. Мне показалось, что его сложнее внедрить, чем аналогичные инструменты. Он не обеспечивает типобезопасность, что также затрудняет отлов отсутствующих ключей на этапе компиляции. Мне пришлось обернуть функции Tolgee своими собственными, чтобы добавить обнаружение отсутствующих ключей.
|
|
194
203
|
|
|
@@ -216,7 +225,7 @@ Intlayer пытается оптимизировать все эти аспек
|
|
|
216
225
|
|
|
217
226
|
`next-translate` — моя основная рекомендация, если вам нравится API в стиле `t()`. Он элегантен благодаря `next-translate-plugin`, загружая пространства имен через `getStaticProps` с помощью загрузчика Webpack / Turbopack. Это также самый легкий вариант (~2.5 КБ). Что касается пространств имен, их определение для каждой страницы или маршрута в конфиге хорошо продумано и проще в обслуживании, чем основные альтернативы, такие как **next-intl** или **next-i18next**. В версии `3.1.2` я заметил, что статический рендеринг не работал; Next.js откатывался к динамическому рендерингу.
|
|
218
227
|
|
|
219
|
-
**(Intlayer)** (`next-intlayer@8.7.
|
|
228
|
+
**(Intlayer)** (`next-intlayer@8.7.12`):
|
|
220
229
|
|
|
221
230
|
Я не буду лично судить о `next-intlayer` ради объективности, так как это мое собственное решение.
|
|
222
231
|
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2026-04-20
|
|
3
|
+
updatedAt: 2026-04-21
|
|
4
|
+
title: Лучшее i18n решение для Solid в 2026 году - Отчет о бенчмарке
|
|
5
|
+
description: Сравните библиотеки интернационализации (i18n) для Solid, такие как solid-primitives, solid-i18next и Intlayer. Подробный отчет о производительности, размере бандла, утечках и реактивности.
|
|
6
|
+
keywords:
|
|
7
|
+
- benchmark
|
|
8
|
+
- i18n
|
|
9
|
+
- intl
|
|
10
|
+
- solid
|
|
11
|
+
- производительность
|
|
12
|
+
- intlayer
|
|
13
|
+
slugs:
|
|
14
|
+
- doc
|
|
15
|
+
- benchmark
|
|
16
|
+
- solid
|
|
17
|
+
author: Aymeric PINEAU
|
|
18
|
+
applicationTemplate: https://github.com/intlayer-org/benchmark-i18n-solid-template
|
|
19
|
+
history:
|
|
20
|
+
- version: 8.7.12
|
|
21
|
+
date: 2026-01-06
|
|
22
|
+
changes: "Инициализация бенчмарка"
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Библиотеки i18n для Solid — Отчет о бенчмарке 2026
|
|
26
|
+
|
|
27
|
+
Эта страница представляет собой отчет о бенчмарке i18n-решений для Solid.
|
|
28
|
+
|
|
29
|
+
## Содержание
|
|
30
|
+
|
|
31
|
+
<Toc/>
|
|
32
|
+
|
|
33
|
+
## Интерактивный бенчмарк
|
|
34
|
+
|
|
35
|
+
<I18nBenchmark framework="vite-solid" vertical/>
|
|
36
|
+
|
|
37
|
+
## Ссылка на результаты:
|
|
38
|
+
|
|
39
|
+
<iframe
|
|
40
|
+
src="https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-vite_solid.md"
|
|
41
|
+
width="100%"
|
|
42
|
+
height="600px"
|
|
43
|
+
style="border:none;">
|
|
44
|
+
</iframe>
|
|
45
|
+
|
|
46
|
+
> https://intlayer.org/markdown?url=https%3A%2F%2Fraw.githubusercontent.com%2Fintlayer-org%2Fbenchmark-i18n%2Fmain%2Freport%2Fscripts%2Fsummarize-vite_solid.md
|
|
47
|
+
|
|
48
|
+
Полный репозиторий бенчмарка можно найти [здесь](https://github.com/intlayer-org/benchmark-i18n/tree/main).
|
|
49
|
+
|
|
50
|
+
## Введение
|
|
51
|
+
|
|
52
|
+
Решения для интернационализации являются одними из самых тяжелых зависимостей в Solid-приложении. Основной риск заключается в передаче ненужного контента: переводов для других страниц и других локалей в бандле одного маршрута.
|
|
53
|
+
|
|
54
|
+
По мере роста вашего приложения эта проблема может быстро привести к раздуванию JavaScript, отправляемого клиенту, и замедлению навигации.
|
|
55
|
+
|
|
56
|
+
На практике в наименее оптимизированных реализациях интернационализированная страница может оказаться в несколько раз тяжелее версии без i18n.
|
|
57
|
+
|
|
58
|
+
Другой аспект — это опыт разработчика: то, как вы объявляете контент, типы, организацию пространств имен, динамическую загрузку и реактивность при смене локали.
|
|
59
|
+
|
|
60
|
+
## TL;DR
|
|
61
|
+
|
|
62
|
+
- **Intlayer**: Рекомендуемый выбор для профессиональных Solid-приложений, требующих расширенных функций и оптимизации (v8.7.12).
|
|
63
|
+
- **@solid-primitives/i18n**: Отличная легкая альтернатива для простых проектов, хотя ей не хватает расширенных функций, таких как ленивая загрузка.
|
|
64
|
+
- **solid-i18next**: Стандартный, но тяжелый вариант (~4.7 раза больше Intlayer) с теми же недостатками, что и React i18next.
|
|
65
|
+
- **Paraglide**: Инновационный подход, но сложный DX и проблемы с tree-shaking в некоторых конфигурациях.
|
|
66
|
+
|
|
67
|
+
## Проверьте свое приложение
|
|
68
|
+
|
|
69
|
+
Чтобы быстро выявить проблемы с утечкой i18n, я настроил бесплатный сканер, доступный [здесь](https://intlayer.org/i18n-seo-scanner).
|
|
70
|
+
|
|
71
|
+
<iframe src="https://intlayer.org/i18n-seo-scanner" width="100%" height="600px" style="border:none;"/>
|
|
72
|
+
|
|
73
|
+
## Проблема
|
|
74
|
+
|
|
75
|
+
Два рычага необходимы для ограничения стоимости мультиязычного приложения:
|
|
76
|
+
|
|
77
|
+
- Разделение контента по страницам / пространствам имен, чтобы не загружать целые словари, когда они вам не нужны.
|
|
78
|
+
- Динамическая загрузка нужной локали только тогда, когда она требуется.
|
|
79
|
+
|
|
80
|
+
Понимание технических ограничений этих подходов:
|
|
81
|
+
|
|
82
|
+
**Динамическая загрузка**
|
|
83
|
+
|
|
84
|
+
Без динамической загрузки большинство решений хранят сообщения в памяти с первого рендеринга, что создает значительные накладные расходы для приложений с множеством маршрутов и локалей.
|
|
85
|
+
|
|
86
|
+
При использовании динамической загрузки вы идете на компромисс: меньше начального JS, но иногда дополнительный запрос при переключении языка.
|
|
87
|
+
|
|
88
|
+
**Разделение контента**
|
|
89
|
+
|
|
90
|
+
Синтаксис, построенный вокруг `t('a.b.c')`, очень удобен, но часто способствует хранению больших JSON-объектов во время выполнения. Эта модель затрудняет tree-shaking, если библиотека не предлагает реальную стратегию разделения контента для каждой страницы.
|
|
91
|
+
|
|
92
|
+
## Методология
|
|
93
|
+
|
|
94
|
+
Для этого бенчмарка мы сравнили следующие библиотеки:
|
|
95
|
+
|
|
96
|
+
- `Base App` (Без библиотеки i18n)
|
|
97
|
+
- `solid-intlayer` (v8.7.12)
|
|
98
|
+
- `@solid-primitives/i18n` (v2.2.1)
|
|
99
|
+
- `solid-i18next` (v17.0.2)
|
|
100
|
+
- `@inlang/paraglide-js` (v2.17.0)
|
|
101
|
+
|
|
102
|
+
Фреймворк — `Solid` с мультиязычным приложением из **10 страниц** и **10 языков**.
|
|
103
|
+
|
|
104
|
+
Мы сравнили **четыре стратегии загрузки**:
|
|
105
|
+
|
|
106
|
+
| Стратегия | Без пространств имен (глобальная) | С пространствами имен (локальная/scoped) |
|
|
107
|
+
| :------------------------ | :---------------------------------------------- | :------------------------------------------------------------------------------- |
|
|
108
|
+
| **Статическая загрузка** | **Static**: Все в памяти при запуске. | **Scoped static**: Разделено по пространствам имен; все загружается при запуске. |
|
|
109
|
+
| **Динамическая загрузка** | **Dynamic**: Загрузка по требованию для локали. | **Scoped dynamic**: Гранулярная загрузка по пространствам имен и локалям. |
|
|
110
|
+
|
|
111
|
+
## Резюме стратегий
|
|
112
|
+
|
|
113
|
+
- **Статическая (Static)**: Простота; отсутствие задержек сети после начальной загрузки. Минус: большой размер бандла.
|
|
114
|
+
- **Динамическая (Dynamic)**: Уменьшает начальный вес (ленивая загрузка). Идеально при наличии множества локалей.
|
|
115
|
+
- **Локальная статическая (Scoped static)**: Позволяет организовать код (логическое разделение) без сложных дополнительных сетевых запросов.
|
|
116
|
+
- **Локальная динамическая (Scoped dynamic)**: Лучший подход для _разделения кода_ и производительности. Минимизирует использование памяти, загружая только то, что нужно для текущего представления и активной локали.
|
|
117
|
+
|
|
118
|
+
## Результаты в деталях
|
|
119
|
+
|
|
120
|
+
### 1 — Решения, которых следует избегать
|
|
121
|
+
|
|
122
|
+
> В экосистеме Solid нет однозначных решений, которых следует избегать.
|
|
123
|
+
|
|
124
|
+
### 2 — Приемлемые решения
|
|
125
|
+
|
|
126
|
+
**(solid-i18next)** (`solid-i18next@17.0.2`):
|
|
127
|
+
|
|
128
|
+
`solid-i18next`, вероятно, является самым популярным вариантом, так как был одним из первых решений для нужд i18n в JavaScript-приложениях. У него также есть широкий набор плагинов от сообщества для конкретных задач.
|
|
129
|
+
|
|
130
|
+
Пакет тяжелый (~14.6 КБ, что примерно в 4.7 раза больше `solid-intlayer`).
|
|
131
|
+
|
|
132
|
+
Тем не менее, у него те же основные недостатки, что и у стеков, построенных на `t('a.b.c')`: оптимизация возможна, но отнимает очень много времени, а большие проекты рискуют столкнуться с плохими практиками (пространства имен + динамическая загрузка + типы).
|
|
133
|
+
|
|
134
|
+
**(@solid-primitives/i18n)** (`@solid-primitives/i18n@2.2.1`):
|
|
135
|
+
|
|
136
|
+
Solid primitive чрезвычайно легкий и эффективный. Я рекомендую это решение для небольших проектов, но ему может быстро перестать хватать функций для профессиональных решений, включая управление куки, перенаправление прокси, форматировщики и т. д.
|
|
137
|
+
В нем также отсутствует ленивая загрузка и разделение пространств имен для оптимизации размера страницы.
|
|
138
|
+
|
|
139
|
+
**(Paraglide)** (`@inlang/paraglide-js@2.17.0`):
|
|
140
|
+
|
|
141
|
+
`Paraglide` предлагает инновационный, хорошо продуманный подход. Тем не менее, в этом бенчмарке рекламируемый ими tree-shaking не сработал для моей реализации. Процесс работы и DX также сложнее, чем у других вариантов.
|
|
142
|
+
Лично мне не нравится необходимость регенерировать JS-файлы перед каждым пушем, что создает постоянный риск конфликтов при слиянии в PR.
|
|
143
|
+
Наконец, по сравнению с другими решениями, Paraglide не использует стор (например, Solid signal) для получения текущей локали для рендеринга. Для каждого обработанного узла он запрашивает локаль из localStorage / куки и т.д. Это приводит к выполнению ненужной логики, что влияет на реактивность компонентов.
|
|
144
|
+
|
|
145
|
+
### 3 — Рекомендации
|
|
146
|
+
|
|
147
|
+
**(Intlayer)** (`solid-intlayer@8.7.12`):
|
|
148
|
+
|
|
149
|
+
Я не буду лично оценивать `solid-intlayer` ради объективности, так как это мое собственное решение.
|
|
150
|
+
|
|
151
|
+
### Личное примечание
|
|
152
|
+
|
|
153
|
+
Это примечание является личным и не влияет на результаты бенчмарка. Тем не менее, в мире i18n часто можно встретить консенсус вокруг паттерна типа `const t = useTranslation('xx')` + `<>{t('xx.xx')}</>` для переведенного контента.
|
|
154
|
+
|
|
155
|
+
В Solid-приложениях внедрение функции в качестве `JSX.Element` является, на мой взгляд, антипаттерном. Это также добавляет лишнюю сложность и накладные расходы на выполнение JavaScript (даже если это почти незаметно).
|