@intlayer/docs 5.7.6 → 5.7.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/dist/cjs/generated/docs.entry.cjs +44 -238
- package/dist/cjs/generated/docs.entry.cjs.map +1 -1
- package/dist/esm/generated/docs.entry.mjs +44 -238
- package/dist/esm/generated/docs.entry.mjs.map +1 -1
- package/dist/types/generated/docs.entry.d.ts +1 -2
- package/dist/types/generated/docs.entry.d.ts.map +1 -1
- package/docs/ar/CI_CD.md +67 -41
- package/docs/ar/intlayer_with_tanstack.md +457 -0
- package/docs/ar/packages/next-intlayer/index.md +0 -1
- package/docs/ar/packages/react-intlayer/index.md +0 -1
- package/docs/de/CI_CD.md +63 -37
- package/docs/de/intlayer_with_tanstack.md +458 -0
- package/docs/de/packages/next-intlayer/index.md +0 -1
- package/docs/de/packages/react-intlayer/index.md +0 -1
- package/docs/en/CI_CD.md +51 -27
- package/docs/en/intlayer_with_tanstack.md +452 -0
- package/docs/en/packages/next-intlayer/index.md +0 -1
- package/docs/en/packages/react-intlayer/index.md +0 -1
- package/docs/en-GB/CI_CD.md +58 -32
- package/docs/en-GB/intlayer_with_tanstack.md +457 -0
- package/docs/en-GB/packages/next-intlayer/index.md +0 -1
- package/docs/en-GB/packages/react-intlayer/index.md +0 -1
- package/docs/es/CI_CD.md +68 -42
- package/docs/es/intlayer_with_tanstack.md +435 -0
- package/docs/es/packages/next-intlayer/index.md +0 -1
- package/docs/es/packages/react-intlayer/index.md +0 -1
- package/docs/fr/intlayer_with_tanstack.md +435 -0
- package/docs/fr/packages/next-intlayer/index.md +0 -1
- package/docs/fr/packages/react-intlayer/index.md +0 -1
- package/docs/hi/CI_CD.md +69 -44
- package/docs/hi/intlayer_with_tanstack.md +438 -0
- package/docs/hi/packages/next-intlayer/index.md +0 -1
- package/docs/hi/packages/react-intlayer/index.md +0 -1
- package/docs/it/CI_CD.md +67 -41
- package/docs/it/intlayer_with_tanstack.md +457 -0
- package/docs/it/packages/next-intlayer/index.md +0 -1
- package/docs/it/packages/react-intlayer/index.md +0 -1
- package/docs/ja/CI_CD.md +67 -41
- package/docs/ja/intlayer_with_tanstack.md +457 -0
- package/docs/ja/packages/next-intlayer/index.md +0 -1
- package/docs/ja/packages/react-intlayer/index.md +0 -1
- package/docs/ko/CI_CD.md +63 -37
- package/docs/ko/intlayer_with_tanstack.md +457 -0
- package/docs/ko/packages/next-intlayer/index.md +0 -1
- package/docs/ko/packages/react-intlayer/index.md +0 -1
- package/docs/pt/CI_CD.md +67 -41
- package/docs/pt/intlayer_with_tanstack.md +457 -0
- package/docs/pt/packages/next-intlayer/index.md +0 -1
- package/docs/pt/packages/react-intlayer/index.md +0 -1
- package/docs/ru/CI_CD.md +70 -44
- package/docs/ru/intlayer_with_tanstack.md +458 -0
- package/docs/ru/packages/next-intlayer/index.md +0 -1
- package/docs/ru/packages/react-intlayer/index.md +0 -1
- package/docs/zh/CI_CD.md +62 -36
- package/docs/zh/intlayer_with_tanstack.md +435 -0
- package/docs/zh/packages/next-intlayer/index.md +0 -1
- package/docs/zh/packages/react-intlayer/index.md +0 -1
- package/package.json +9 -9
- package/src/generated/docs.entry.ts +44 -238
- package/docs/ar/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ar/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/de/packages/next-intlayer/useIntlayerAsync.md +0 -262
- package/docs/de/packages/react-intlayer/useIntlayerAsync.md +0 -256
- package/docs/en/packages/next-intlayer/useIntlayerAsync.md +0 -239
- package/docs/en/packages/react-intlayer/useIntlayerAsync.md +0 -254
- package/docs/en-GB/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/en-GB/packages/react-intlayer/useIntlayerAsync.md +0 -257
- package/docs/es/packages/next-intlayer/useIntlayerAsync.md +0 -240
- package/docs/es/packages/react-intlayer/useIntlayerAsync.md +0 -276
- package/docs/fr/packages/next-intlayer/useIntlayerAsync.md +0 -238
- package/docs/fr/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/hi/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/hi/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/it/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/it/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/ja/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ja/packages/react-intlayer/useIntlayerAsync.md +0 -268
- package/docs/ko/packages/next-intlayer/useIntlayerAsync.md +0 -260
- package/docs/ko/packages/react-intlayer/useIntlayerAsync.md +0 -271
- package/docs/pt/packages/next-intlayer/useIntlayerAsync.md +0 -238
- package/docs/pt/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/ru/packages/next-intlayer/useIntlayerAsync.md +0 -237
- package/docs/ru/packages/react-intlayer/useIntlayerAsync.md +0 -252
- package/docs/zh/packages/next-intlayer/useIntlayerAsync.md +0 -239
- package/docs/zh/packages/react-intlayer/useIntlayerAsync.md +0 -257
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
---
|
|
2
|
+
createdAt: 2025-08-11
|
|
3
|
+
updatedAt: 2025-08-11
|
|
4
|
+
title: Começando com Intlayer no TanStack Start (React)
|
|
5
|
+
description: Adicione i18n ao seu app TanStack Start usando Intlayer—dicionários a nível de componente, URLs localizadas e metadados otimizados para SEO.
|
|
6
|
+
keywords:
|
|
7
|
+
- Internacionalização
|
|
8
|
+
- Documentação
|
|
9
|
+
- Intlayer
|
|
10
|
+
- TanStack Start
|
|
11
|
+
- TanStack Router
|
|
12
|
+
- React
|
|
13
|
+
- i18n
|
|
14
|
+
- JavaScript
|
|
15
|
+
slugs:
|
|
16
|
+
- doc
|
|
17
|
+
- environment
|
|
18
|
+
- tanstack-start
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Começando a Internacionalizar (i18n) com Intlayer e TanStack Start (React)
|
|
22
|
+
|
|
23
|
+
## O que é Intlayer?
|
|
24
|
+
|
|
25
|
+
**Intlayer** é um kit de ferramentas i18n open-source para apps React. Ele oferece:
|
|
26
|
+
|
|
27
|
+
- **Dicionários locais por componente** com segurança em TypeScript.
|
|
28
|
+
- **Metadados e rotas dinâmicas** (prontas para SEO).
|
|
29
|
+
- **Troca de localidade em tempo de execução** (e auxiliares para detectar/persistir localidades).
|
|
30
|
+
- **Plugin Vite** para transformações em tempo de build + experiência de desenvolvimento (DX).
|
|
31
|
+
|
|
32
|
+
Este guia mostra como integrar o Intlayer em um projeto **TanStack Start** (que usa Vite por baixo dos panos e TanStack Router para roteamento/SSR).
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Passo 1: Instalar Dependências
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# npm
|
|
40
|
+
npm i intlayer react-intlayer
|
|
41
|
+
npm i -D vite-intlayer
|
|
42
|
+
|
|
43
|
+
# pnpm
|
|
44
|
+
pnpm add intlayer react-intlayer
|
|
45
|
+
pnpm add -D vite-intlayer
|
|
46
|
+
|
|
47
|
+
# yarn
|
|
48
|
+
yarn add intlayer react-intlayer
|
|
49
|
+
yarn add -D vite-intlayer
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **intlayer**: núcleo (configuração, dicionários, CLI/transformações).
|
|
53
|
+
- **react-intlayer**: `<IntlayerProvider>` + hooks para React.
|
|
54
|
+
- **vite-intlayer**: plugin Vite, além de middleware opcional para detecção/redirecionamento de localidade (funciona em dev e SSR/preview; mover para `dependencies` para SSR em produção).
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Passo 2: Configurar o Intlayer
|
|
59
|
+
|
|
60
|
+
Crie o arquivo `intlayer.config.ts` na raiz do seu projeto:
|
|
61
|
+
|
|
62
|
+
```ts fileName="intlayer.config.ts"
|
|
63
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
64
|
+
|
|
65
|
+
const config: IntlayerConfig = {
|
|
66
|
+
internationalization: {
|
|
67
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
68
|
+
defaultLocale: Locales.ENGLISH,
|
|
69
|
+
},
|
|
70
|
+
// Você também pode ajustar: contentDir, contentFileExtensions, opções de middleware, etc.
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export default config;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
As variantes CommonJS/ESM são idênticas ao seu documento original caso prefira `cjs`/`mjs`.
|
|
77
|
+
|
|
78
|
+
> Referência completa da configuração: veja a documentação de configuração do Intlayer.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Passo 3: Adicionar o Plugin Vite (e middleware opcional)
|
|
83
|
+
|
|
84
|
+
**TanStack Start usa Vite**, então adicione o(s) plugin(s) do Intlayer no seu `vite.config.ts`:
|
|
85
|
+
|
|
86
|
+
```ts fileName="vite.config.ts"
|
|
87
|
+
import { defineConfig } from "vite";
|
|
88
|
+
import react from "@vitejs/plugin-react-swc";
|
|
89
|
+
import { intlayerPlugin, intLayerMiddlewarePlugin } from "vite-intlayer";
|
|
90
|
+
|
|
91
|
+
export default defineConfig({
|
|
92
|
+
plugins: [
|
|
93
|
+
react(),
|
|
94
|
+
intlayerPlugin(),
|
|
95
|
+
// Opcional, mas recomendado para detecção de localidade, cookies e redirecionamentos:
|
|
96
|
+
intLayerMiddlewarePlugin(),
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> Se você fizer deploy SSR, mova `vite-intlayer` para `dependencies` para que o middleware funcione em produção.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Passo 4: Declare Seu Conteúdo
|
|
106
|
+
|
|
107
|
+
Coloque seus dicionários em qualquer lugar dentro de `./src` (padrão `contentDir`). Exemplo:
|
|
108
|
+
|
|
109
|
+
```tsx fileName="src/app.content.tsx"
|
|
110
|
+
import { t, type Dictionary } from "intlayer";
|
|
111
|
+
import type { ReactNode } from "react";
|
|
112
|
+
|
|
113
|
+
const appContent = {
|
|
114
|
+
key: "app",
|
|
115
|
+
content: {
|
|
116
|
+
viteLogo: t({
|
|
117
|
+
pt: "Logo Vite",
|
|
118
|
+
en: "Vite logo",
|
|
119
|
+
fr: "Logo Vite",
|
|
120
|
+
es: "Logo Vite",
|
|
121
|
+
}),
|
|
122
|
+
reactLogo: t({
|
|
123
|
+
pt: "Logo React",
|
|
124
|
+
en: "React logo",
|
|
125
|
+
fr: "Logo React",
|
|
126
|
+
es: "Logo React",
|
|
127
|
+
}),
|
|
128
|
+
title: t({
|
|
129
|
+
pt: "TanStack Start + React",
|
|
130
|
+
en: "TanStack Start + React",
|
|
131
|
+
fr: "TanStack Start + React",
|
|
132
|
+
es: "TanStack Start + React",
|
|
133
|
+
}),
|
|
134
|
+
count: t({
|
|
135
|
+
pt: "a contagem é ",
|
|
136
|
+
en: "count is ",
|
|
137
|
+
fr: "le compte est ",
|
|
138
|
+
es: "el recuento es ",
|
|
139
|
+
}),
|
|
140
|
+
edit: t<ReactNode>({
|
|
141
|
+
pt: (
|
|
142
|
+
<>
|
|
143
|
+
Edite <code>src/routes/index.tsx</code> e salve para testar HMR
|
|
144
|
+
</>
|
|
145
|
+
),
|
|
146
|
+
en: (
|
|
147
|
+
<>
|
|
148
|
+
Edit <code>src/routes/index.tsx</code> and save to test HMR
|
|
149
|
+
</>
|
|
150
|
+
),
|
|
151
|
+
fr: (
|
|
152
|
+
<>
|
|
153
|
+
Éditez <code>src/routes/index.tsx</code> et enregistrez pour tester
|
|
154
|
+
HMR
|
|
155
|
+
</>
|
|
156
|
+
),
|
|
157
|
+
es: (
|
|
158
|
+
<>
|
|
159
|
+
Edita <code>src/routes/index.tsx</code> y guarda para probar HMR
|
|
160
|
+
</>
|
|
161
|
+
),
|
|
162
|
+
}),
|
|
163
|
+
readTheDocs: t({
|
|
164
|
+
pt: "Clique nos logos para saber mais",
|
|
165
|
+
en: "Click the logos to learn more",
|
|
166
|
+
fr: "Cliquez sur les logos pour en savoir plus",
|
|
167
|
+
es: "Haz clic en los logotipos para saber más",
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
} satisfies Dictionary;
|
|
171
|
+
|
|
172
|
+
export default appContent;
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
As variantes JSON/ESM/CJS funcionam da mesma forma que no seu documento original.
|
|
176
|
+
|
|
177
|
+
> Conteúdo TSX? Não esqueça de `import React from "react"` se sua configuração precisar disso.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Passo 5: Envolver TanStack Start com Intlayer
|
|
182
|
+
|
|
183
|
+
Com TanStack Start, sua **rota raiz** é o lugar certo para configurar os providers.
|
|
184
|
+
|
|
185
|
+
```tsx fileName="src/routes/__root.tsx"
|
|
186
|
+
import {
|
|
187
|
+
Outlet,
|
|
188
|
+
createRootRoute,
|
|
189
|
+
Link as RouterLink,
|
|
190
|
+
} from "@tanstack/react-router";
|
|
191
|
+
import { IntlayerProvider, useIntlayer } from "react-intlayer";
|
|
192
|
+
|
|
193
|
+
function AppShell() {
|
|
194
|
+
// Exemplo de uso de um dicionário no nível superior:
|
|
195
|
+
const content = useIntlayer("app");
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<div>
|
|
199
|
+
<nav className="flex gap-3 p-3">
|
|
200
|
+
<RouterLink to="/">Início</RouterLink>
|
|
201
|
+
<RouterLink to="/about">Sobre</RouterLink>
|
|
202
|
+
</nav>
|
|
203
|
+
<main className="p-6">
|
|
204
|
+
<h1>{content.title}</h1>
|
|
205
|
+
<Outlet />
|
|
206
|
+
</main>
|
|
207
|
+
</div>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export const Route = createRootRoute({
|
|
212
|
+
component: () => (
|
|
213
|
+
<IntlayerProvider>
|
|
214
|
+
<AppShell />
|
|
215
|
+
</IntlayerProvider>
|
|
216
|
+
),
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Então use seu conteúdo nas páginas:
|
|
221
|
+
|
|
222
|
+
```tsx fileName="src/routes/index.tsx"
|
|
223
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
224
|
+
import { useIntlayer } from "react-intlayer";
|
|
225
|
+
import reactLogo from "../assets/react.svg";
|
|
226
|
+
|
|
227
|
+
export const Route = createFileRoute("/")({
|
|
228
|
+
component: () => {
|
|
229
|
+
const content = useIntlayer("app");
|
|
230
|
+
return (
|
|
231
|
+
<>
|
|
232
|
+
<button>{content.count}0</button>
|
|
233
|
+
<p>{content.edit}</p>
|
|
234
|
+
<img
|
|
235
|
+
src={reactLogo}
|
|
236
|
+
alt={content.reactLogo.value}
|
|
237
|
+
width={48}
|
|
238
|
+
height={48}
|
|
239
|
+
/>
|
|
240
|
+
<p className="opacity-70">{content.readTheDocs}</p>
|
|
241
|
+
</>
|
|
242
|
+
);
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
> Atributos de string (`alt`, `title`, `aria-label`, …) precisam de `.value`:
|
|
248
|
+
>
|
|
249
|
+
> ```jsx
|
|
250
|
+
> <img alt={c.reactLogo.value} />
|
|
251
|
+
> ```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## (Opcional) Passo 6: Troca de Idioma (Cliente)
|
|
256
|
+
|
|
257
|
+
```tsx fileName="src/components/LocaleSwitcher.tsx"
|
|
258
|
+
import { Locales } from "intlayer";
|
|
259
|
+
import { useLocale } from "react-intlayer";
|
|
260
|
+
|
|
261
|
+
export function LocaleSwitcher() {
|
|
262
|
+
const { setLocale } = useLocale();
|
|
263
|
+
return (
|
|
264
|
+
<div className="flex gap-2">
|
|
265
|
+
<button onClick={() => setLocale(Locales.ENGLISH)}>Inglês</button>
|
|
266
|
+
<button onClick={() => setLocale(Locales.FRENCH)}>Francês</button>
|
|
267
|
+
<button onClick={() => setLocale(Locales.SPANISH)}>Espanhol</button>
|
|
268
|
+
</div>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## (Opcional) Passo 7: Roteamento Localizado (URLs amigáveis para SEO)
|
|
276
|
+
|
|
277
|
+
Você tem **dois bons padrões** com TanStack Start. Escolha um.
|
|
278
|
+
|
|
279
|
+
Crie uma pasta de segmento dinâmico `src/routes/$locale/` para que suas URLs sejam `/:locale/...`. No layout `$locale`, valide o `params.locale`, defina `<IntlayerProvider locale=...>`, e renderize um `<Outlet />`. Essa abordagem é direta, mas você montará o restante das suas rotas abaixo de `$locale`, e precisará de uma árvore extra sem prefixo se você _não_ quiser o prefixo da localidade padrão.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## (Opcional) Passo 8: Atualizar a URL ao trocar de idioma
|
|
284
|
+
|
|
285
|
+
Com o Padrão A (basepath), trocar de idioma significa **navegar para um basepath diferente**:
|
|
286
|
+
|
|
287
|
+
```tsx fileName="src/components/LocaleSwitcherNavigate.tsx"
|
|
288
|
+
import { useRouter } from "@tanstack/react-router";
|
|
289
|
+
import { Locales, getLocalizedUrl } from "intlayer";
|
|
290
|
+
import { useLocale } from "react-intlayer";
|
|
291
|
+
|
|
292
|
+
export function LocaleSwitcherNavigate() {
|
|
293
|
+
const router = useRouter();
|
|
294
|
+
const { locale, setLocale } = useLocale();
|
|
295
|
+
|
|
296
|
+
const change = async (next: Locales) => {
|
|
297
|
+
if (next === locale) return;
|
|
298
|
+
const nextPath = getLocalizedUrl(
|
|
299
|
+
window.location.pathname + window.location.search,
|
|
300
|
+
next
|
|
301
|
+
);
|
|
302
|
+
await router.navigate({ to: nextPath }); // preserva o histórico
|
|
303
|
+
setLocale(next);
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
<div className="flex gap-2">
|
|
308
|
+
<button onClick={() => change(Locales.ENGLISH)}>English</button>
|
|
309
|
+
<button onClick={() => change(Locales.FRENCH)}>Français</button>
|
|
310
|
+
<button onClick={() => change(Locales.SPANISH)}>Español</button>
|
|
311
|
+
</div>
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## (Opcional) Passo 9: `<html lang>` e `dir` (Documento TanStack Start)
|
|
319
|
+
|
|
320
|
+
TanStack Start expõe um **Document** (estrutura raiz HTML) que você pode personalizar. Defina `lang` e `dir` para acessibilidade/SEO:
|
|
321
|
+
|
|
322
|
+
```tsx fileName="src/routes/__root.tsx" {4,15}
|
|
323
|
+
import { Outlet, createRootRoute } from "@tanstack/react-router";
|
|
324
|
+
import { IntlayerProvider } from "react-intlayer";
|
|
325
|
+
import { getHTMLTextDir } from "intlayer";
|
|
326
|
+
|
|
327
|
+
function Document({
|
|
328
|
+
locale,
|
|
329
|
+
children,
|
|
330
|
+
}: {
|
|
331
|
+
locale: string;
|
|
332
|
+
children: React.ReactNode;
|
|
333
|
+
}) {
|
|
334
|
+
return (
|
|
335
|
+
<html lang={locale} dir={getHTMLTextDir(locale)}>
|
|
336
|
+
<head>
|
|
337
|
+
<meta charSet="utf-8" />
|
|
338
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
339
|
+
{/* ... */}
|
|
340
|
+
</head>
|
|
341
|
+
<body>{children}</body>
|
|
342
|
+
</html>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export const Route = createRootRoute({
|
|
347
|
+
component: () => (
|
|
348
|
+
<IntlayerProvider>
|
|
349
|
+
{/* Se você calcular o locale no servidor, passe-o para o Document; caso contrário, o cliente corrigirá após a hidratação */}
|
|
350
|
+
<Document locale={document?.documentElement?.lang || "en"}>
|
|
351
|
+
<Outlet />
|
|
352
|
+
</Document>
|
|
353
|
+
</IntlayerProvider>
|
|
354
|
+
),
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Para correção no lado do cliente, você também pode manter seu pequeno hook:
|
|
359
|
+
|
|
360
|
+
```tsx fileName="src/hooks/useI18nHTMLAttributes.tsx"
|
|
361
|
+
import { useEffect } from "react";
|
|
362
|
+
import { useLocale } from "react-intlayer";
|
|
363
|
+
import { getHTMLTextDir } from "intlayer";
|
|
364
|
+
|
|
365
|
+
export const useI18nHTMLAttributes = () => {
|
|
366
|
+
const { locale } = useLocale();
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
document.documentElement.lang = locale;
|
|
369
|
+
document.documentElement.dir = getHTMLTextDir(locale);
|
|
370
|
+
}, [locale]);
|
|
371
|
+
};
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## (Opcional) Passo 10: Componente Link localizado
|
|
377
|
+
|
|
378
|
+
O TanStack Router fornece um `<Link/>`, mas se você precisar de uma `<a>` simples que prefixe automaticamente URLs internas:
|
|
379
|
+
|
|
380
|
+
```tsx fileName="src/components/Link.tsx"
|
|
381
|
+
import { getLocalizedUrl } from "intlayer";
|
|
382
|
+
import {
|
|
383
|
+
forwardRef,
|
|
384
|
+
type AnchorHTMLAttributes,
|
|
385
|
+
type DetailedHTMLProps,
|
|
386
|
+
} from "react";
|
|
387
|
+
import { useLocale } from "react-intlayer";
|
|
388
|
+
|
|
389
|
+
export interface LinkProps
|
|
390
|
+
extends DetailedHTMLProps<
|
|
391
|
+
AnchorHTMLAttributes<HTMLAnchorElement>,
|
|
392
|
+
HTMLAnchorElement
|
|
393
|
+
> {}
|
|
394
|
+
|
|
395
|
+
const isExternal = (href?: string) => /^https?:\/\//.test(href ?? "");
|
|
396
|
+
|
|
397
|
+
export const Link = forwardRef<HTMLAnchorElement, LinkProps>(
|
|
398
|
+
({ href, children, ...props }, ref) => {
|
|
399
|
+
const { locale } = useLocale();
|
|
400
|
+
const hrefI18n =
|
|
401
|
+
href && !isExternal(href) ? getLocalizedUrl(href, locale) : href;
|
|
402
|
+
return (
|
|
403
|
+
<a href={hrefI18n} ref={ref} {...props}>
|
|
404
|
+
{children}
|
|
405
|
+
</a>
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
Link.displayName = "Link";
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
> Se você usar o Padrão A (basepath), o `<Link to="/about" />` do TanStack já resolve para `/fr/about` via `basepath`, então um link personalizado é opcional.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## TypeScript
|
|
417
|
+
|
|
418
|
+
Inclua os tipos gerados pelo Intlayer:
|
|
419
|
+
|
|
420
|
+
```json5 fileName="tsconfig.json"
|
|
421
|
+
{
|
|
422
|
+
"include": ["src", ".intlayer/**/*.ts"],
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
## Git
|
|
429
|
+
|
|
430
|
+
Ignore os artefatos gerados pelo Intlayer:
|
|
431
|
+
|
|
432
|
+
```gitignore
|
|
433
|
+
.intlayer
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Extensão VS Code
|
|
439
|
+
|
|
440
|
+
- **Extensão Intlayer para VS Code** → autocompletar, erros, pré-visualizações inline, ações rápidas.
|
|
441
|
+
Marketplace: `intlayer.intlayer-vs-code-extension`
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## Ir Além
|
|
446
|
+
|
|
447
|
+
- Editor Visual
|
|
448
|
+
- Modo CMS
|
|
449
|
+
- Detecção de localidade na edge / adaptadores
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Histórico da Documentação
|
|
454
|
+
|
|
455
|
+
| Versão | Data | Alterações |
|
|
456
|
+
| ------ | ---------- | -------------------------------------- |
|
|
457
|
+
| 1.0.0 | 2025-08-11 | Adaptação do TanStack Start adicionada |
|
|
@@ -279,7 +279,6 @@ O pacote `next-intlayer` também fornece algumas funções para ajudar você a i
|
|
|
279
279
|
- [`useIntlayer()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/next-intlayer/useIntlayer.md)
|
|
280
280
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/next-intlayer/useDictionary.md)
|
|
281
281
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/next-intlayer/useLocale.md)
|
|
282
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/next-intlayer/useIntlayerAsync.md)
|
|
283
282
|
|
|
284
283
|
## Histórico da Documentação
|
|
285
284
|
|
|
@@ -273,7 +273,6 @@ O pacote `react-intlayer` também fornece algumas funções para ajudar você a
|
|
|
273
273
|
- [`useIntlayer()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/react-intlayer/useIntlayer.md)
|
|
274
274
|
- [`useDictionary()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/react-intlayer/useDictionary.md)
|
|
275
275
|
- [`useLocale()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/react-intlayer/useLocale.md)
|
|
276
|
-
- [`useIntlayerAsync()`](https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/packages/react-intlayer/useIntlayerAsync.md)
|
|
277
276
|
|
|
278
277
|
## Histórico da Documentação
|
|
279
278
|
|
package/docs/ru/CI_CD.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
createdAt: 2025-05-20
|
|
3
|
-
updatedAt: 2025-
|
|
3
|
+
updatedAt: 2025-08-13
|
|
4
4
|
title: Интеграция CI/CD
|
|
5
|
-
description: Узнайте, как интегрировать Intlayer в ваш CI/CD
|
|
5
|
+
description: Узнайте, как интегрировать Intlayer в ваш CI/CD конвейер для автоматизированного управления контентом и развертывания.
|
|
6
6
|
keywords:
|
|
7
7
|
- CI/CD
|
|
8
8
|
- Непрерывная интеграция
|
|
@@ -17,13 +17,13 @@ slugs:
|
|
|
17
17
|
- ci-cd
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
# Автоматическая генерация переводов в CI/CD
|
|
20
|
+
# Автоматическая генерация переводов в CI/CD конвейере
|
|
21
21
|
|
|
22
22
|
Intlayer позволяет автоматически генерировать переводы для ваших файлов декларации контента. Существует несколько способов достичь этого в зависимости от вашего рабочего процесса.
|
|
23
23
|
|
|
24
24
|
## Использование CMS
|
|
25
25
|
|
|
26
|
-
С Intlayer вы можете использовать рабочий процесс, при котором локально объявляется только
|
|
26
|
+
С Intlayer вы можете использовать рабочий процесс, при котором локально объявляется только одна локаль, а все переводы управляются удаленно через CMS. Это позволяет полностью отделить контент и переводы от кодовой базы, обеспечивая большую гибкость для редакторов контента и позволяя горячую перезагрузку контента (нет необходимости пересобирать приложение для применения изменений).
|
|
27
27
|
|
|
28
28
|
### Пример конфигурации
|
|
29
29
|
|
|
@@ -33,7 +33,7 @@ import { Locales, type IntlayerConfig } from "intlayer";
|
|
|
33
33
|
const config: IntlayerConfig = {
|
|
34
34
|
internationalization: {
|
|
35
35
|
locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
|
|
36
|
-
requiredLocales: [Locales.ENGLISH], // Необязательные
|
|
36
|
+
requiredLocales: [Locales.ENGLISH], // Необязательные локали будут управляться удаленно
|
|
37
37
|
defaultLocale: Locales.ENGLISH,
|
|
38
38
|
},
|
|
39
39
|
editor: {
|
|
@@ -45,7 +45,7 @@ const config: IntlayerConfig = {
|
|
|
45
45
|
clientSecret: process.env.INTLAYER_CLIENT_SECRET,
|
|
46
46
|
},
|
|
47
47
|
ai: {
|
|
48
|
-
applicationContext: "
|
|
48
|
+
applicationContext: "This is a test application", // Помогает обеспечить согласованное создание переводов
|
|
49
49
|
},
|
|
50
50
|
};
|
|
51
51
|
|
|
@@ -66,7 +66,7 @@ import { Locales, type IntlayerConfig } from "intlayer";
|
|
|
66
66
|
const config: IntlayerConfig = {
|
|
67
67
|
internationalization: {
|
|
68
68
|
locales: [Locales.ENGLISH, Locales.SPANISH, Locales.FRENCH],
|
|
69
|
-
requiredLocales: [Locales.ENGLISH], // Необязательные локали обрабатываются
|
|
69
|
+
requiredLocales: [Locales.ENGLISH], // Необязательные локали обрабатываются удалённо
|
|
70
70
|
defaultLocale: Locales.ENGLISH,
|
|
71
71
|
},
|
|
72
72
|
editor: {
|
|
@@ -75,9 +75,9 @@ const config: IntlayerConfig = {
|
|
|
75
75
|
},
|
|
76
76
|
ai: {
|
|
77
77
|
provider: "openai",
|
|
78
|
-
apiKey: process.env.OPENAI_API_KEY, // Используйте свой собственный API
|
|
78
|
+
apiKey: process.env.OPENAI_API_KEY, // Используйте свой собственный API-ключ
|
|
79
79
|
|
|
80
|
-
applicationContext: "
|
|
80
|
+
applicationContext: "This is a test application", // Помогает обеспечить согласованное создание переводов
|
|
81
81
|
},
|
|
82
82
|
};
|
|
83
83
|
|
|
@@ -85,11 +85,11 @@ export default config;
|
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
```bash fileName=".husky/pre-push"
|
|
88
|
-
npx intlayer build # Чтобы
|
|
88
|
+
npx intlayer build # Чтобы словари были актуальными
|
|
89
89
|
npx intlayer fill --unpushed --mode fill # Заполняет только отсутствующий контент, не обновляет существующий
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
> Для получения дополнительной информации о командах Intlayer CLI и их
|
|
92
|
+
> Для получения дополнительной информации о командах Intlayer CLI и их использовании обратитесь к [документации CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_cli.md).
|
|
93
93
|
|
|
94
94
|
> Если у вас несколько приложений в репозитории, использующих отдельные экземпляры intlayer, вы можете использовать аргумент `--base-dir` следующим образом:
|
|
95
95
|
|
|
@@ -108,65 +108,91 @@ npx intlayer fill --base-dir ./app2 --unpushed --mode fill
|
|
|
108
108
|
Intlayer предоставляет команду CLI для автоматического заполнения и проверки содержимого словаря. Это можно интегрировать в ваш CI/CD процесс с использованием GitHub Actions.
|
|
109
109
|
|
|
110
110
|
```yaml fileName=".github/workflows/intlayer-translate.yml"
|
|
111
|
-
name: Intlayer
|
|
111
|
+
name: Intlayer Автозаполнение
|
|
112
|
+
# Условия запуска этого workflow
|
|
112
113
|
on:
|
|
113
|
-
push:
|
|
114
|
-
branches: [ main ]
|
|
115
|
-
paths:
|
|
116
|
-
- 'src/**'
|
|
117
114
|
pull_request:
|
|
118
|
-
branches:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
branches:
|
|
116
|
+
- "main"
|
|
117
|
+
|
|
118
|
+
permissions:
|
|
119
|
+
contents: write
|
|
120
|
+
pull-requests: write
|
|
122
121
|
|
|
123
122
|
concurrency:
|
|
124
|
-
group:
|
|
123
|
+
group: "autofill-${{ github.ref }}"
|
|
125
124
|
cancel-in-progress: true
|
|
126
125
|
|
|
127
126
|
jobs:
|
|
128
127
|
autofill:
|
|
129
128
|
runs-on: ubuntu-latest
|
|
130
129
|
env:
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
130
|
+
# OpenAI
|
|
131
|
+
AI_MODEL: openai
|
|
132
|
+
AI_PROVIDER: gpt-5-mini
|
|
133
|
+
AI_API_KEY: ${{ secrets.AI_API_KEY }}
|
|
134
134
|
|
|
135
135
|
steps:
|
|
136
|
-
|
|
137
|
-
|
|
136
|
+
# Шаг 1: Получить последний код из репозитория
|
|
137
|
+
- name: ⬇️ Проверка репозитория
|
|
138
|
+
uses: actions/checkout@v4
|
|
138
139
|
with:
|
|
139
|
-
persist-credentials: true
|
|
140
|
+
persist-credentials: true # Сохранять учетные данные для создания PR
|
|
141
|
+
fetch-depth: 0 # Получить полную историю git для анализа изменений
|
|
140
142
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
# Шаг 2: Настроить окружение Node.js
|
|
144
|
+
- name: 🟢 Настроить Node.js
|
|
145
|
+
uses: actions/setup-node@v4
|
|
143
146
|
with:
|
|
144
|
-
node-version: 20
|
|
147
|
+
node-version: 20 # Использовать Node.js 20 LTS для стабильности
|
|
145
148
|
|
|
149
|
+
# Шаг 3: Установить зависимости проекта
|
|
146
150
|
- name: 📦 Установить зависимости
|
|
147
|
-
run: npm
|
|
151
|
+
run: npm install
|
|
152
|
+
|
|
153
|
+
# Шаг 4: Глобально установить Intlayer CLI для управления переводами
|
|
154
|
+
- name: 📦 Установить Intlayer
|
|
155
|
+
run: npm install -g intlayer-cli
|
|
148
156
|
|
|
157
|
+
# Шаг 5: Собрать проект Intlayer для генерации файлов перевода
|
|
149
158
|
- name: ⚙️ Собрать проект Intlayer
|
|
150
159
|
run: npx intlayer build
|
|
151
160
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
# Шаг 6: Использовать ИИ для автоматического заполнения отсутствующих переводов
|
|
162
|
+
- name: 🤖 Автоматическое заполнение отсутствующих переводов
|
|
163
|
+
run: npx intlayer fill --git-diff --mode fill --provider $AI_PROVIDER --model $AI_MODEL --api-key $AI_API_KEY
|
|
164
|
+
|
|
165
|
+
# Шаг 7: Проверить наличие изменений и зафиксировать их
|
|
166
|
+
- name: � Проверить изменения
|
|
167
|
+
id: check-changes
|
|
168
|
+
run: |
|
|
169
|
+
if [ -n "$(git status --porcelain)" ]; then
|
|
170
|
+
echo "has-changes=true" >> $GITHUB_OUTPUT
|
|
171
|
+
else
|
|
172
|
+
echo "has-changes=false" >> $GITHUB_OUTPUT
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Шаг 8: Зафиксировать и отправить изменения, если они есть
|
|
176
|
+
- name: 📤 Зафиксировать и отправить изменения
|
|
177
|
+
if: steps.check-changes.outputs.has-changes == 'true'
|
|
178
|
+
run: |
|
|
179
|
+
git config --local user.email "action@github.com"
|
|
180
|
+
git config --local user.name "GitHub Action"
|
|
181
|
+
git add .
|
|
182
|
+
git commit -m "chore: автоматическое заполнение отсутствующих переводов [skip ci]"
|
|
183
|
+
git push origin HEAD:${{ github.head_ref }}
|
|
162
184
|
```
|
|
163
185
|
|
|
186
|
+
Чтобы настроить переменные окружения, перейдите в GitHub → Settings → Secrets and variables → Actions и добавьте секрет .
|
|
187
|
+
|
|
164
188
|
> Аналогично Husky, в случае монорепозитория вы можете использовать аргумент `--base-dir` для последовательной обработки каждого приложения.
|
|
165
189
|
|
|
166
|
-
> По умолчанию аргумент `--git-diff` фильтрует словари, которые
|
|
190
|
+
> По умолчанию аргумент `--git-diff` фильтрует словари, которые содержат изменения от базы (по умолчанию `origin/main`) до текущей ветки (по умолчанию: `HEAD`).
|
|
167
191
|
|
|
168
192
|
> Для получения дополнительной информации о командах Intlayer CLI и их использовании обратитесь к [документации CLI](https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/intlayer_cli.md).
|
|
169
193
|
|
|
170
|
-
## История
|
|
194
|
+
## История документации
|
|
171
195
|
|
|
172
|
-
|
|
196
|
+
| Версия | Дата | Изменения |
|
|
197
|
+
| ------ | ---------- | --------------------- |
|
|
198
|
+
| 5.5.10 | 2025-06-29 | Инициализация истории |
|