@intlayer/docs 6.1.4 → 6.1.6-canary.0

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.
Files changed (75) hide show
  1. package/blog/ar/next-i18next_vs_next-intl_vs_intlayer.md +1366 -75
  2. package/blog/ar/nextjs-multilingual-seo-comparison.md +364 -0
  3. package/blog/de/next-i18next_vs_next-intl_vs_intlayer.md +1288 -72
  4. package/blog/de/nextjs-multilingual-seo-comparison.md +362 -0
  5. package/blog/en/intlayer_with_next-i18next.mdx +431 -0
  6. package/blog/en/intlayer_with_next-intl.mdx +335 -0
  7. package/blog/en/next-i18next_vs_next-intl_vs_intlayer.md +583 -336
  8. package/blog/en/nextjs-multilingual-seo-comparison.md +360 -0
  9. package/blog/en-GB/next-i18next_vs_next-intl_vs_intlayer.md +1144 -37
  10. package/blog/en-GB/nextjs-multilingual-seo-comparison.md +360 -0
  11. package/blog/es/next-i18next_vs_next-intl_vs_intlayer.md +1236 -64
  12. package/blog/es/nextjs-multilingual-seo-comparison.md +363 -0
  13. package/blog/fr/next-i18next_vs_next-intl_vs_intlayer.md +1142 -75
  14. package/blog/fr/nextjs-multilingual-seo-comparison.md +362 -0
  15. package/blog/hi/nextjs-multilingual-seo-comparison.md +363 -0
  16. package/blog/it/next-i18next_vs_next-intl_vs_intlayer.md +1130 -55
  17. package/blog/it/nextjs-multilingual-seo-comparison.md +363 -0
  18. package/blog/ja/next-i18next_vs_next-intl_vs_intlayer.md +1150 -76
  19. package/blog/ja/nextjs-multilingual-seo-comparison.md +362 -0
  20. package/blog/ko/next-i18next_vs_next-intl_vs_intlayer.md +1139 -73
  21. package/blog/ko/nextjs-multilingual-seo-comparison.md +362 -0
  22. package/blog/pt/next-i18next_vs_next-intl_vs_intlayer.md +1143 -76
  23. package/blog/pt/nextjs-multilingual-seo-comparison.md +362 -0
  24. package/blog/ru/next-i18next_vs_next-intl_vs_intlayer.md +1150 -74
  25. package/blog/ru/nextjs-multilingual-seo-comparison.md +370 -0
  26. package/blog/tr/next-i18next_vs_next-intl_vs_intlayer.md +2 -0
  27. package/blog/tr/nextjs-multilingual-seo-comparison.md +362 -0
  28. package/blog/zh/next-i18next_vs_next-intl_vs_intlayer.md +1152 -75
  29. package/blog/zh/nextjs-multilingual-seo-comparison.md +394 -0
  30. package/dist/cjs/generated/blog.entry.cjs +16 -0
  31. package/dist/cjs/generated/blog.entry.cjs.map +1 -1
  32. package/dist/cjs/generated/docs.entry.cjs +16 -0
  33. package/dist/cjs/generated/docs.entry.cjs.map +1 -1
  34. package/dist/esm/generated/blog.entry.mjs +16 -0
  35. package/dist/esm/generated/blog.entry.mjs.map +1 -1
  36. package/dist/esm/generated/docs.entry.mjs +16 -0
  37. package/dist/esm/generated/docs.entry.mjs.map +1 -1
  38. package/dist/types/generated/blog.entry.d.ts +1 -0
  39. package/dist/types/generated/blog.entry.d.ts.map +1 -1
  40. package/dist/types/generated/docs.entry.d.ts +1 -0
  41. package/dist/types/generated/docs.entry.d.ts.map +1 -1
  42. package/docs/ar/component_i18n.md +186 -0
  43. package/docs/ar/vs_code_extension.md +48 -109
  44. package/docs/de/component_i18n.md +186 -0
  45. package/docs/de/vs_code_extension.md +46 -107
  46. package/docs/en/component_i18n.md +186 -0
  47. package/docs/en/interest_of_intlayer.md +2 -2
  48. package/docs/en/intlayer_with_nextjs_14.md +18 -1
  49. package/docs/en/intlayer_with_nextjs_15.md +18 -1
  50. package/docs/en/vs_code_extension.md +24 -114
  51. package/docs/en-GB/component_i18n.md +186 -0
  52. package/docs/en-GB/vs_code_extension.md +42 -103
  53. package/docs/es/component_i18n.md +182 -0
  54. package/docs/es/vs_code_extension.md +53 -114
  55. package/docs/fr/component_i18n.md +186 -0
  56. package/docs/fr/vs_code_extension.md +50 -111
  57. package/docs/hi/component_i18n.md +186 -0
  58. package/docs/hi/vs_code_extension.md +49 -110
  59. package/docs/it/component_i18n.md +186 -0
  60. package/docs/it/vs_code_extension.md +50 -111
  61. package/docs/ja/component_i18n.md +186 -0
  62. package/docs/ja/vs_code_extension.md +50 -111
  63. package/docs/ko/component_i18n.md +186 -0
  64. package/docs/ko/vs_code_extension.md +48 -109
  65. package/docs/pt/component_i18n.md +186 -0
  66. package/docs/pt/vs_code_extension.md +46 -107
  67. package/docs/ru/component_i18n.md +186 -0
  68. package/docs/ru/vs_code_extension.md +48 -109
  69. package/docs/tr/component_i18n.md +186 -0
  70. package/docs/tr/vs_code_extension.md +54 -115
  71. package/docs/zh/component_i18n.md +186 -0
  72. package/docs/zh/vs_code_extension.md +51 -105
  73. package/package.json +11 -11
  74. package/src/generated/blog.entry.ts +16 -0
  75. package/src/generated/docs.entry.ts +16 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  createdAt: 2025-08-23
3
- updatedAt: 2025-08-23
3
+ updatedAt: 2025-09-29
4
4
  title: next-i18next vs next-intl vs Intlayer
5
5
  description: Comparar next-i18next com next-intl e Intlayer para a internacionalização (i18n) de uma aplicação Next.js
6
6
  keywords:
@@ -19,144 +19,1211 @@ slugs:
19
19
 
20
20
  # next-i18next VS next-intl VS intlayer | Internacionalização (i18n) no Next.js
21
21
 
22
- Este guia compara três opções amplamente usadas de i18n para **Next.js**: **next-intl**, **next-i18next** e **Intlayer**.
22
+ ![next-i18next VS next-intl VS intlayer](https://github.com/aymericzip/intlayer/blob/main/docs/assets/i18next-next-intl-intlayer.png?raw=true)
23
+
24
+ Vamos analisar as semelhanças e diferenças entre três opções de i18n para Next.js: next-i18next, next-intl e Intlayer.
25
+
26
+ Este não é um tutorial completo. É uma comparação para ajudar você a escolher.
27
+
23
28
  Focamos no **Next.js 13+ App Router** (com **React Server Components**) e avaliamos:
24
29
 
25
30
  1. **Arquitetura e organização de conteúdo**
26
31
  2. **TypeScript e segurança**
27
- 3. **Tratamento de traduções faltantes**
32
+ 3. **Tratamento de traduções ausentes**
28
33
  4. **Roteamento e middleware**
29
34
  5. **Desempenho e comportamento de carregamento**
30
35
  6. **Experiência do desenvolvedor (DX), ferramentas e manutenção**
31
- 7. **SEO e escalabilidade para projetos grandes**
36
+ 7. **SEO e escalabilidade para grandes projetos**
32
37
 
33
- > **resumo**: Todos os três podem localizar uma aplicação Next.js. Se você deseja **conteúdo com escopo por componente**, **tipos TypeScript rigorosos**, **verificações de chaves ausentes em tempo de build**, **dicionários otimizados por tree-shaking** e **helpers de App Router + SEO de primeira classe**, **Intlayer** é a escolha mais completa e moderna.
38
+ > **resumo**: Todos os três podem localizar uma aplicação Next.js. Se você deseja **conteúdo com escopo por componente**, **tipos TypeScript rigorosos**, **verificações de chaves ausentes em tempo de build**, **dicionários otimizados por tree-shaking** e **suporte nativo ao App Router + helpers de SEO**, **Intlayer** é a escolha mais completa e moderna.
39
+
40
+ > Uma confusão comum feita por desenvolvedores é pensar que `next-intl` é a versão Next.js do `react-intl`. Não é — `next-intl` é mantido por [Amann](https://github.com/amannn), enquanto `react-intl` é mantido por [FormatJS](https://github.com/formatjs/formatjs).
34
41
 
35
42
  ---
36
43
 
37
- ## Posicionamento em alto nível
44
+ ## Em resumo
38
45
 
39
- - **next-intl** - Formatação de mensagens leve e direta com suporte sólido para Next.js. Catálogos centralizados são comuns; a experiência do desenvolvedor (DX) é simples, mas a segurança e a manutenção em larga escala permanecem principalmente sob sua responsabilidade.
40
- - **next-i18next** - i18next com roupagem Next.js. Ecossistema maduro e recursos via plugins (por exemplo, ICU), mas a configuração pode ser verbosa e os catálogos tendem a se centralizar conforme os projetos crescem.
46
+ - **next-intl** - Formatação de mensagens leve e direta com suporte sólido ao Next.js. Catálogos centralizados são comuns; a experiência do desenvolvedor (DX) é simples, mas a segurança e a manutenção em larga escala permanecem principalmente sob sua responsabilidade.
47
+ - **next-i18next** - i18next com aparência de Next.js. Ecossistema maduro e recursos via plugins (por exemplo, ICU), mas a configuração pode ser verbosa e os catálogos tendem a se centralizar conforme os projetos crescem.
41
48
  - **Intlayer** - Modelo de conteúdo centrado em componentes para Next.js, **tipagem TS rigorosa**, **verificações em tempo de build**, **tree-shaking**, **middleware e helpers de SEO integrados**, **Editor Visual/CMS** opcional e **traduções assistidas por IA**.
42
49
 
43
50
  ---
44
51
 
52
+ | Library | GitHub Stars | Total Commits | Last Commit | First Version | NPM Version | NPM Downloads |
53
+ | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
54
+ | `aymericzip/intlayer` | [![GitHub Repo stars](https://img.shields.io/github/stars/aymericzip/intlayer?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/aymericzip/intlayer/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/aymericzip/intlayer?style=for-the-badge&label=commits)](https://github.com/aymericzip/intlayer/commits) | [![Last Commit](https://img.shields.io/github/last-commit/aymericzip/intlayer?style=for-the-badge)](https://github.com/aymericzip/intlayer/commits) | April 2024 | [![npm](https://img.shields.io/npm/v/intlayer?style=for-the-badge)](https://www.npmjs.com/package/intlayer) | [![npm downloads](https://img.shields.io/npm/dm/intlayer?style=for-the-badge)](https://www.npmjs.com/package/intlayer) |
55
+ | `amannn/next-intl` | [![GitHub Repo stars](https://img.shields.io/github/stars/amannn/next-intl?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/amannn/next-intl/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/amannn/next-intl?style=for-the-badge&label=commits)](https://github.com/amannn/next-intl/commits) | [![Last Commit](https://img.shields.io/github/last-commit/amannn/next-intl?style=for-the-badge)](https://github.com/amannn/next-intl/commits) | Nov 2020 | [![npm](https://img.shields.io/npm/v/next-intl?style=for-the-badge)](https://www.npmjs.com/package/next-intl) | [![npm downloads](https://img.shields.io/npm/dm/next-intl?style=for-the-badge)](https://www.npmjs.com/package/next-intl) |
56
+ | `i18next/i18next` | [![GitHub Repo stars](https://img.shields.io/github/stars/i18next/i18next?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/i18next/i18next/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/i18next/i18next?style=for-the-badge&label=commits)](https://github.com/i18next/i18next/commits) | [![Last Commit](https://img.shields.io/github/last-commit/i18next/i18next?style=for-the-badge)](https://github.com/i18next/i18next/commits) | Jan 2012 | [![npm](https://img.shields.io/npm/v/i18next?style=for-the-badge)](https://www.npmjs.com/package/i18next) | [![npm downloads](https://img.shields.io/npm/dm/i18next?style=for-the-badge)](https://www.npmjs.com/package/i18next) |
57
+ | `i18next/next-i18next` | [![GitHub Repo stars](https://img.shields.io/github/stars/i18next/next-i18next?style=for-the-badge&label=%E2%AD%90%20stars)](https://github.com/i18next/next-i18next/stargazers) | [![GitHub commit activity](https://img.shields.io/github/commit-activity/t/i18next/next-i18next?style=for-the-badge&label=commits)](https://github.com/i18next/next-i18next/commits) | [![Last Commit](https://img.shields.io/github/last-commit/i18next/next-i18next?style=for-the-badge)](https://github.com/i18next/next-i18next/commits) | Nov 2018 | [![npm](https://img.shields.io/npm/v/next-i18next?style=for-the-badge)](https://www.npmjs.com/package/next-i18next) | [![npm downloads](https://img.shields.io/npm/dm/next-i18next?style=for-the-badge)](https://www.npmjs.com/package/next-i18next) |
58
+
59
+ > Os distintivos são atualizados automaticamente. As capturas de tela podem variar ao longo do tempo.
60
+
61
+ ---
62
+
45
63
  ## Comparação de Recursos Lado a Lado (focado em Next.js)
46
64
 
47
- | Recurso | `next-intlayer` (Intlayer) | `next-intl` | `next-i18next` |
48
- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
49
- | **Traduções Próximas aos Componentes** | ✅ Sim, conteúdo localizado junto a cada componente | ❌ Não | ❌ Não |
50
- | **Integração com TypeScript** | ✅ Avançada, tipos estritos gerados automaticamente | ✅ Boa | ⚠️ Básica |
51
- | **Detecção de Tradução Ausente** | ✅ Destaque de erro no TypeScript e erro/aviso em tempo de compilação | ⚠️ Recurso de fallback em tempo de execução | ⚠️ Recurso de fallback em tempo de execução |
52
- | **Conteúdo Rico (JSX/Markdown/componentes)** | ✅ Suporte direto | ❌ Não projetado para nós ricos | ⚠️ Limitado |
53
- | **Tradução com IA** | ✅ Sim, suporta múltiplos provedores de IA. Usável com suas próprias chaves de API. Considera o contexto da sua aplicação e o escopo do conteúdo | ❌ Não | ❌ Não |
54
- | **Editor Visual** | ✅ Sim, Editor Visual local + CMS opcional; pode externalizar conteúdo da base de código; incorporável | ❌ Não / disponível via plataformas externas de localização | ❌ Não / disponível via plataformas externas de localização |
55
- | **Roteamento Localizado** | ✅ Sim, suporta caminhos localizados nativamente (funciona com Next.js & Vite) | ✅ Integrado, App Router suporta o segmento `[locale]` | ✅ Integrado |
56
- | **Geração Dinâmica de Rotas** | ✅ Sim | ✅ Sim | ✅ Sim |
57
- | **Pluralização** | ✅ Padrões baseados em enumeração | ✅ Bom | ✅ Bom |
58
- | **Formatação (datas, números, moedas)** | ✅ Formatadores otimizados (Intl por trás dos panos) | ✅ Bom (helpers Intl) | ✅ Bom (helpers Intl) |
59
- | **Formato de Conteúdo** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml em desenvolvimento) | ✅ .json, .js, .ts | ⚠️ .json |
60
- | **Suporte ICU** | ⚠️ Em desenvolvimento | ✅ Sim | ⚠️ Via plugin (`i18next-icu`) |
61
- | **Auxiliares de SEO (hreflang, sitemap)** | ✅ Ferramentas integradas: auxiliares para sitemap, robots.txt, metadados | ✅ Bom | ✅ Bom |
62
- | **Ecossistema / Comunidade** | ⚠️ Menor, mas crescendo rápido e reativa | ✅ Médio porte, focado em Next.js | ✅ Médio porte, focado em Next.js |
63
- | **Renderização no lado do servidor & Componentes de Servidor** | ✅ Sim, otimizado para SSR / Componentes de Servidor React | ⚠️ Suportado a nível de página, mas é necessário passar funções t na árvore de componentes para componentes filhos de servidor | ⚠️ Suportado a nível de página, mas é necessário passar funções t na árvore de componentes para componentes filhos de servidor |
64
- | **Tree-shaking (carregar apenas conteúdo usado)** | ✅ Sim, por componente em tempo de build via plugins Babel/SWC | ⚠️ Parcial | ⚠️ Parcial |
65
- | **Carregamento preguiçoso (Lazy loading)** | ✅ Sim, por localidade / por dicionário | ✅ Sim (por rota/por localidade), necessita de gestão de namespace | ✅ Sim (por rota/por localidade), necessita de gestão de namespace |
66
- | **Remoção de conteúdo não utilizado** | ✅ Sim, por dicionário em tempo de build | ❌ Não, pode ser gerenciado manualmente com gestão de namespace | ❌ Não, pode ser gerenciado manualmente com gestão de namespace |
67
- | **Gestão de Grandes Projetos** | ✅ Incentiva modularidade, adequado para sistemas de design | ✅ Modular com configuração | ✅ Modular com configuração |
68
-
69
- ---
70
-
71
- ## Comparação detalhada
72
-
73
- ### 1) Arquitetura e escalabilidade
74
-
75
- - **next-intl / next-i18next**: Por padrão, utiliza **catálogos centralizados** por localidade (além de **namespaces** no i18next). Funciona bem no início, mas frequentemente se torna uma grande área compartilhada com aumento do acoplamento e da rotatividade de chaves.
76
- - **Intlayer**: Incentiva dicionários **por componente** (ou por funcionalidade) **co-localizados** com o código que eles atendem. Isso reduz a carga cognitiva, facilita a duplicação/migração de partes da interface e diminui conflitos entre equipes. Conteúdo não utilizado é naturalmente mais fácil de identificar e eliminar.
65
+ | Recurso | `next-intlayer` (Intlayer) | `next-intl` | `next-i18next` |
66
+ | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
67
+ | **Traduções Próximas aos Componentes** | ✅ Sim, conteúdo localizado junto a cada componente | ❌ Não | ❌ Não |
68
+ | **Integração com TypeScript** | ✅ Avançada, tipos estritos gerados automaticamente | ✅ Boa | ⚠️ Básica |
69
+ | **Detecção de Tradução Ausente** | ✅ Destaque de erro no TypeScript e erro/aviso em tempo de compilação | ⚠️ Retorno em tempo de execução | ⚠️ Retorno em tempo de execução |
70
+ | **Conteúdo Rico (JSX/Markdown/componentes)** | ✅ Suporte direto | ❌ Não projetado para nós ricos | ⚠️ Limitado |
71
+ | **Tradução com IA** | ✅ Sim, suporta múltiplos provedores de IA. Usável com suas próprias chaves de API. Considera o contexto da sua aplicação e o escopo do conteúdo | ❌ Não | ❌ Não |
72
+ | **Editor Visual** | ✅ Sim, Editor Visual local + CMS opcional; pode externalizar conteúdo da base de código; incorporável | ❌ Não / disponível via plataformas externas de localização | ❌ Não / disponível via plataformas externas de localização |
73
+ | **Roteamento Localizado** | ✅ Sim, suporta caminhos localizados nativamente (funciona com Next.js & Vite) | ✅ Integrado, App Router suporta segmento `[locale]` | ✅ Integrado |
74
+ | **Geração Dinâmica de Rotas** | ✅ Sim | ✅ Sim | ✅ Sim |
75
+ | **Pluralização** | ✅ Padrões baseados em enumeração | ✅ Bom | ✅ Bom |
76
+ | **Formatação (datas, números, moedas)** | ✅ Formatadores otimizados (Intl por trás dos panos) | ✅ Bom (helpers do Intl) | ✅ Bom (helpers do Intl) |
77
+ | **Formato do Conteúdo** | ✅ .tsx, .ts, .js, .json, .md, .txt, (.yaml em desenvolvimento) | ✅ .json, .js, .ts | ⚠️ .json |
78
+ | **Suporte ICU** | ⚠️ Em desenvolvimento | ✅ Sim | ⚠️ Via plugin (`i18next-icu`) |
79
+ | **Auxiliares de SEO (hreflang, sitemap)** | ✅ Ferramentas integradas: auxiliares para sitemap, robots.txt, metadados | ✅ Bom | ✅ Bom |
80
+ | **Ecossistema / Comunidade** | ⚠️ Menor, mas crescendo rápido e reativo | ✅ Bom | ✅ Bom |
81
+ | **Renderização do lado servidor & Componentes de Servidor** | ✅ Sim, otimizado para SSR / Componentes de Servidor React | ⚠️ Suportado a nível de página, mas é necessário passar funções t na árvore de componentes para componentes filhos de servidor | ⚠️ Suportado a nível de página, mas é necessário passar funções t na árvore de componentes para componentes filhos de servidor |
82
+ | **Tree-shaking (carregar apenas o conteúdo usado)** | ✅ Sim, por componente no momento da build via plugins Babel/SWC | ⚠️ Parcial | ⚠️ Parcial |
83
+ | **Carregamento preguiçoso (Lazy loading)** | ✅ Sim, por localidade / por dicionário | ✅ Sim (por rota/por localidade), necessita gerenciamento de namespace | ✅ Sim (por rota/por localidade), necessita gerenciamento de namespace |
84
+ | **Remover conteúdo não utilizado** | ✅ Sim, por dicionário em tempo de build | ❌ Não, pode ser gerenciado manualmente com gerenciamento de namespace | ❌ Não, pode ser gerenciado manualmente com gerenciamento de namespace |
85
+ | **Gerenciamento de Grandes Projetos** | ✅ Incentiva modularidade, adequado para design-system | ✅ Modular com configuração | ✅ Modular com configuração |
86
+ | **Testando Traduções Ausentes (CLI/CI)** | ✅ CLI: `npx intlayer content test` (auditoria amigável para CI) | ⚠️ Não embutido; a documentação sugere `npx @lingual/i18n-check` | ⚠️ Não embutido; depende das ferramentas do i18next / runtime `saveMissing` |
87
+
88
+ ---
89
+
90
+ ## Introdução
91
+
92
+ Next.js oferece suporte embutido para roteamento internacionalizado (ex.: segmentos de localidade). Mas essa funcionalidade não realiza traduções por si só. Você ainda precisa de uma biblioteca para renderizar conteúdo localizado para seus usuários.
93
+
94
+ Existem muitas bibliotecas i18n, mas no universo Next.js hoje, três estão ganhando destaque: next-i18next, next-intl e Intlayer.
95
+
96
+ ---
97
+
98
+ ## Arquitetura & escalabilidade
99
+
100
+ - **next-intl / next-i18next**: Por padrão, utilizam **catálogos centralizados** por localidade (além de **namespaces** no i18next). Funciona bem no início, mas frequentemente se torna uma grande área compartilhada com aumento do acoplamento e da rotatividade de chaves.
101
+ - **Intlayer**: Incentiva dicionários **por componente** (ou por funcionalidade) **co-localizados** com o código que atendem. Isso reduz a carga cognitiva, facilita a duplicação/migração de partes da interface e diminui conflitos entre equipes. Conteúdo não utilizado é naturalmente mais fácil de identificar e eliminar.
77
102
 
78
103
  **Por que isso importa:** Em grandes bases de código ou configurações de sistemas de design, **conteúdo modular** escala melhor do que catálogos monolíticos.
79
104
 
80
105
  ---
81
106
 
82
- ### 2) TypeScript & segurança
107
+ ## Tamanhos de bundle e dependências
108
+
109
+ Após a construção da aplicação, o bundle é o JavaScript que o navegador irá carregar para renderizar a página. Portanto, o tamanho do bundle é importante para o desempenho da aplicação.
110
+
111
+ Dois componentes são importantes no contexto de um bundle de aplicação multilíngue:
112
+
113
+ - O código da aplicação
114
+ - O conteúdo carregado pelo navegador
115
+
116
+ ## Código da Aplicação
117
+
118
+ A importância do código da aplicação é mínima neste caso. As três soluções são tree-shakable, o que significa que as partes não utilizadas do código não são incluídas no bundle.
119
+
120
+ Aqui está uma comparação do tamanho do bundle JavaScript carregado pelo navegador para uma aplicação multilíngue com as três soluções.
121
+
122
+ Se não precisarmos de nenhum formatador na aplicação, a lista de funções exportadas após o tree-shaking será:
123
+
124
+ - **next-intlayer**: `useIntlayer`, `useLocale`, `NextIntlClientProvider`, (O tamanho do bundle é 180,6 kB -> 78,6 kB (gzip))
125
+ - **next-intl**: `useTranslations`, `useLocale`, `NextIntlClientProvider`, (O tamanho do bundle é 101,3 kB -> 31,4 kB (gzip))
126
+ - **next-i18next**: `useTranslation`, `useI18n`, `I18nextProvider`, (O tamanho do bundle é 80,7 kB -> 25,5 kB (gzip))
127
+
128
+ Estas funções são apenas wrappers em torno do contexto/estado do React, portanto o impacto total da biblioteca i18n no tamanho do bundle é mínimo.
129
+
130
+ > Intlayer é ligeiramente maior que `next-intl` e `next-i18next` porque inclui mais lógica na função `useIntlayer`. Isso está relacionado à integração com markdown e `intlayer-editor`.
131
+
132
+ ## Conteúdo e Traduções
133
+
134
+ Esta parte é frequentemente ignorada pelos desenvolvedores, mas vamos considerar o caso de uma aplicação composta por 10 páginas em 10 idiomas. Vamos supor que cada página integre 100% de conteúdo único para simplificar o cálculo (na realidade, muito conteúdo é redundante entre páginas, por exemplo, título da página, cabeçalho, rodapé, etc.).
135
+
136
+ Um usuário que deseja visitar a página `/fr/about` carregará o conteúdo de uma página em um determinado idioma. Ignorar a otimização do conteúdo significaria carregar 8.200% `((1 + (((10 páginas - 1) × (10 idiomas - 1)))) × 100)` do conteúdo da aplicação desnecessariamente. Você vê o problema? Mesmo que esse conteúdo permaneça texto, e enquanto você provavelmente prefere pensar em otimizar as imagens do seu site, você está enviando conteúdo inútil pelo mundo todo e fazendo os computadores dos usuários processarem isso sem necessidade.
137
+
138
+ Dois problemas importantes:
139
+
140
+ - **Divisão por rota:**
141
+
142
+ > Se eu estiver na página `/about`, não quero carregar o conteúdo da página `/home`
143
+
144
+ - **Divisão por localidade:**
145
+
146
+ > Se eu estiver na página `/fr/about`, não quero carregar o conteúdo da página `/en/about`
83
147
 
84
- - **next-intl**: Suporte sólido ao TypeScript, mas **as chaves não são estritamente tipadas por padrão**; você precisará manter padrões de segurança manualmente.
85
- - **next-i18next**: Tipagens básicas para hooks; **tipagem estrita das chaves requer ferramentas/configurações adicionais**.
86
- - **Intlayer**: **Gera tipos estritos** a partir do seu conteúdo. A **autocompletação no IDE** e os **erros em tempo de compilação** capturam erros de digitação e chaves ausentes antes do deploy.
148
+ Novamente, as três soluções estão cientes desses problemas e permitem gerenciar essas otimizações. A diferença entre as três soluções é a DX (Experiência do Desenvolvedor).
87
149
 
88
- **Por que isso importa:** A tipagem forte desloca falhas para a **esquerda** (CI/build) em vez de para a **direita** (tempo de execução).
150
+ `next-intl` e `next-i18next` usam uma abordagem centralizada para gerenciar traduções, permitindo dividir o JSON por localidade e por sub-arquivos. No `next-i18next`, chamamos os arquivos JSON de 'namespaces'; o `next-intl` permite declarar mensagens. No `intlayer`, chamamos os arquivos JSON de 'dicionários'.
151
+
152
+ - No caso do `next-intl`, assim como no `next-i18next`, o conteúdo é carregado no nível da página/layout, e então esse conteúdo é carregado em um provedor de contexto. Isso significa que o desenvolvedor deve gerenciar manualmente os arquivos JSON que serão carregados para cada página.
153
+
154
+ > Na prática, isso implica que os desenvolvedores frequentemente pulam essa otimização, preferindo carregar todo o conteúdo no provedor de contexto da página para simplificar.
155
+
156
+ - No caso do `intlayer`, todo o conteúdo é carregado na aplicação. Depois, um plugin (`@intlayer/babel` / `@intlayer/swc`) cuida de otimizar o bundle carregando apenas o conteúdo usado na página. Portanto, o desenvolvedor não precisa gerenciar manualmente os dicionários que serão carregados. Isso permite uma melhor otimização, melhor manutenção e reduz o tempo de desenvolvimento.
157
+
158
+ À medida que a aplicação cresce (especialmente quando vários desenvolvedores trabalham na aplicação), é comum esquecer de remover conteúdo que não é mais utilizado dos arquivos JSON.
159
+
160
+ > Note que todos os JSON são carregados em todos os casos (next-intl, next-i18next, intlayer).
161
+
162
+ É por isso que a abordagem do Intlayer é mais performática: se um componente não é mais utilizado, seu dicionário não é carregado no bundle.
163
+
164
+ Como a biblioteca lida com os fallbacks também é importante. Vamos considerar que a aplicação está em inglês por padrão, e o usuário visita a página `/fr/about`. Se as traduções estiverem faltando em francês, consideraremos o fallback para o inglês.
165
+
166
+ No caso do `next-intl` e do `next-i18next`, a biblioteca exige o carregamento do JSON relacionado ao idioma atual, mas também ao idioma de fallback. Assim, considerando que todo o conteúdo foi traduzido, cada página carregará 100% de conteúdo desnecessário. **Em comparação, o `intlayer` processa o fallback no momento da construção do dicionário. Portanto, cada página carregará apenas o conteúdo utilizado.**
167
+
168
+ Aqui está um exemplo do impacto da otimização do tamanho do bundle usando `intlayer` em uma aplicação vite + react:
169
+
170
+ | Bundle otimizado | Bundle não otimizado |
171
+ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
172
+ | ![pacote otimizado](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true) | ![pacote não otimizado](https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle_no_optimization.png?raw=true) |
89
173
 
90
174
  ---
91
175
 
92
- ### 3) Tratamento de traduções ausentes
176
+ ## TypeScript e segurança
177
+
178
+ <Columns>
179
+ <Column>
180
+
181
+ **next-intl**
182
+
183
+ - Suporte sólido ao TypeScript, mas **as chaves não são estritamente tipadas por padrão**; você precisará manter os padrões de segurança manualmente.
184
+
185
+ </Column>
186
+ <Column>
187
+
188
+ **next-i18next**
189
+
190
+ - Tipagens básicas para hooks; **tipagem estrita das chaves requer ferramentas/configurações extras**.
191
+
192
+ </Column>
193
+ <Column>
194
+
195
+ **intlayer**
93
196
 
94
- - **next-intl / next-i18next**: Dependem de **fallbacks em tempo de execução** (ex.: mostrar a chave ou o idioma padrão). A build não falha.
95
- - **Intlayer**: **Detecção em tempo de build** com **avisos/erros** para locais ou chaves ausentes.
197
+ - **Gera tipos estritos** a partir do seu conteúdo. **Autocompletação na IDE** e **erros em tempo de compilação** detectam erros de digitação e chaves ausentes antes do deploy.
96
198
 
97
- **Por que isso importa:** Detectar lacunas durante a build evita “strings misteriosas” em produção e está alinhado com gates rigorosos de lançamento.
199
+ </Column>
200
+ </Columns>
201
+
202
+ **Por que isso importa:** Tipagem forte desloca falhas para a **esquerda** (CI/build) em vez da **direita** (tempo de execução).
98
203
 
99
204
  ---
100
205
 
101
- ### 4) Roteamento, middleware e estratégia de URL
206
+ ## Tratamento de traduções ausentes
207
+
208
+ **next-intl**
209
+
210
+ - Depende de **fallbacks em tempo de execução** (ex.: mostrar a chave ou o locale padrão). A build não falha.
211
+
212
+ **next-i18next**
213
+
214
+ - Depende de **fallbacks em tempo de execução** (ex.: mostrar a chave ou o locale padrão). A build não falha.
102
215
 
103
- - Todos os três funcionam com **roteamento localizado do Next.js** no App Router.
104
- - **Intlayer** vai além com **middleware i18n** (detecção de localidade via headers/cookies) e **helpers** para gerar URLs localizadas e tags `<link rel="alternate" hreflang="…">`.
216
+ **intlayer**
105
217
 
106
- **Por que isso importa:** Menos camadas personalizadas; **UX consistente** e **SEO limpo** entre as localidades.
218
+ - **Detecção em tempo de build** com **avisos/erros** para locais ou chaves ausentes.
219
+
220
+ **Por que isso importa:** Detectar lacunas durante a build evita “strings misteriosas” em produção e está alinhado com gates rigorosos de release.
107
221
 
108
222
  ---
109
223
 
110
- ### 5) Alinhamento com Server Components (RSC)
224
+ ## Roteamento, middleware e estratégia de URL
111
225
 
112
- - **Todos** suportam Next.js 13+.
113
- - **Intlayer** suaviza a **fronteira servidor/cliente** com uma API consistente e providers projetados para RSC, para que você não precise passar formatadores ou funções t através das árvores de componentes.
226
+ <Columns>
227
+ <Column>
114
228
 
115
- **Por que isso importa:** Modelo mental mais limpo e menos casos extremos em árvores híbridas.
229
+ **next-intl**
230
+
231
+ - Funciona com **roteamento localizado do Next.js** no App Router.
232
+
233
+ </Column>
234
+ <Column>
235
+
236
+ **next-i18next**
237
+
238
+ - Funciona com **roteamento localizado do Next.js** no App Router.
239
+
240
+ </Column>
241
+ <Column>
242
+
243
+ **intlayer**
244
+
245
+ - Tudo o que foi mencionado acima, além de **middleware i18n** (detecção de local via headers/cookies) e **helpers** para gerar URLs localizadas e tags `<link rel="alternate" hreflang="…">`.
246
+
247
+ </Column>
248
+ </Columns>
249
+
250
+ **Por que isso importa:** Menos camadas de integração personalizadas; **UX consistente** e **SEO limpo** entre os locais.
116
251
 
117
252
  ---
118
253
 
119
- ### 6) Performance e comportamento de carregamento
254
+ ## Alinhamento com Server Components (RSC)
255
+
256
+ <Columns>
257
+ <Column>
120
258
 
121
- - **next-intl / next-i18next**: Controle parcial via **namespaces** e **divisões por rota**; risco de incluir strings não usadas se a disciplina falhar.
122
- - **Intlayer**: **Elimina código morto** na build e **carrega de forma preguiçosa por dicionário/locale**. Conteúdo não usado não é enviado.
259
+ **next-intl**
123
260
 
124
- **Por que isso importa:** Pacotes menores e inicialização mais rápida, especialmente em sites multilíngues.
261
+ - Suporta Next.js 13+. Frequentemente requer passar funções t/formatadores através das árvores de componentes em configurações híbridas.
262
+
263
+ </Column>
264
+ <Column>
265
+
266
+ **next-i18next**
267
+
268
+ - Suporta Next.js 13+. Restrições semelhantes ao passar utilitários de tradução através de fronteiras.
269
+
270
+ </Column>
271
+ <Column>
272
+
273
+ **intlayer**
274
+
275
+ - Suporta Next.js 13+ e suaviza a **fronteira servidor/cliente** com uma API consistente e provedores orientados para RSC, evitando o transporte de formatadores ou funções t.
276
+
277
+ </Column>
278
+ </Columns>
279
+
280
+ **Por que isso importa:** Modelo mental mais limpo e menos casos extremos em árvores híbridas.
125
281
 
126
282
  ---
127
283
 
128
- ### 7) DX, ferramentas e manutenção
284
+ ## DX, ferramentas e manutenção
285
+
286
+ <Columns>
287
+ <Column>
288
+
289
+ **next-intl**
290
+
291
+ - Comumente emparelhado com plataformas externas de localização e fluxos editoriais.
292
+
293
+ </Column>
294
+ <Column>
295
+
296
+ **next-i18next**
297
+
298
+ - Comumente emparelhado com plataformas externas de localização e fluxos editoriais.
299
+
300
+ </Column>
301
+ <Column>
302
+
303
+ **intlayer**
304
+
305
+ - Fornece um **Editor Visual gratuito** e um **CMS opcional** (compatível com Git ou externalizado), além de uma **extensão para VSCode** e **traduções assistidas por IA** usando suas próprias chaves de provedor.
306
+
307
+ </Column>
308
+ </Columns>
309
+
310
+ **Por que isso importa:** Reduz o custo operacional e encurta o ciclo entre desenvolvedores e autores de conteúdo.
311
+
312
+ ## Integração com plataformas de localização (TMS)
313
+
314
+ Grandes organizações frequentemente dependem de Sistemas de Gerenciamento de Tradução (TMS) como **Crowdin**, **Phrase**, **Lokalise**, **Localizely** ou **Localazy**.
315
+
316
+ - **Por que as empresas se importam**
317
+ - **Colaboração e papéis**: Vários atores estão envolvidos: desenvolvedores, gerentes de produto, tradutores, revisores, equipes de marketing.
318
+ - **Escala e eficiência**: localização contínua, revisão em contexto.
319
+
320
+ - **next-intl / next-i18next**
321
+ - Normalmente usam **catálogos JSON centralizados**, portanto a exportação/importação com TMS é direta.
322
+ - Ecossistemas maduros e exemplos/integrações para as plataformas mencionadas.
323
+
324
+ - **Intlayer**
325
+ - Incentiva **dicionários descentralizados por componente** e suporta conteúdo em **TypeScript/TSX/JS/JSON/MD**.
326
+ - Isso melhora a modularidade no código, mas pode dificultar a integração plug-and-play com TMS quando a ferramenta espera arquivos JSON centralizados e planos.
327
+ - O Intlayer oferece alternativas: **traduções assistidas por IA** (usando suas próprias chaves de provedor), um **Editor Visual/CMS** e fluxos de trabalho **CLI/CI** para detectar e preencher lacunas.
328
+
329
+ > Nota: `next-intl` e `i18next` também aceitam catálogos em TypeScript. Se sua equipe armazena mensagens em arquivos `.ts` ou as descentraliza por funcionalidade, você pode enfrentar atritos semelhantes com TMS. No entanto, muitas configurações do `next-intl` permanecem centralizadas em uma pasta `locales/`, o que facilita um pouco a refatoração para JSON para TMS.
330
+
331
+ ## Experiência do Desenvolvedor
332
+
333
+ Esta parte faz uma comparação profunda entre as três soluções. Em vez de considerar casos simples, como descrito na documentação de 'primeiros passos' para cada solução, consideraremos um caso de uso real, mais semelhante a um projeto real.
334
+
335
+ ### Estrutura do aplicativo
336
+
337
+ A estrutura do aplicativo é importante para garantir uma boa manutenção da sua base de código.
338
+
339
+ <Tab defaultTab="next-intl" group='techno'>
340
+
341
+ <TabItem label="next-i18next" value="next-i18next">
342
+
343
+ ```bash
344
+ .
345
+ ├── i18n.config.ts
346
+ └── src
347
+ ├── locales
348
+ │ ├── en
349
+ │ │ ├── common.json
350
+ │ │ └── about.json
351
+ │ └── fr
352
+ │ ├── common.json
353
+ │ └── about.json
354
+ ├── app
355
+ │ ├── i18n
356
+ │ │ └── server.ts
357
+ │ └── [locale]
358
+ │ ├── layout.tsx
359
+ │ └── about.tsx
360
+ └── components
361
+ ├── I18nProvider.tsx
362
+ ├── ClientComponent.tsx
363
+ └── ServerComponent.tsx
364
+ ```
365
+
366
+ </TabItem>
367
+ <TabItem label="next-intl" value="next-intl">
368
+
369
+ ```bash
370
+ .
371
+ ├── i18n.ts
372
+ ├── locales
373
+ │ ├── en
374
+ │ │ ├── home.json
375
+ │ │ └── navbar.json
376
+ │ ├── fr
377
+ │ │ ├── home.json
378
+ │ │ └── navbar.json
379
+ │ └── es
380
+ │ ├── home.json
381
+ │ └── navbar.json
382
+ └── src
383
+ ├── middleware.ts
384
+ ├── app
385
+ │ ├── i18n
386
+ │ │ └── server.ts
387
+ │ └── [locale]
388
+ │ └── home.tsx
389
+ └── components
390
+ └── Navbar
391
+ └── index.tsx
392
+ ```
393
+
394
+ </TabItem>
395
+ <TabItem label="intlayer" value="intlayer">
396
+
397
+ ```bash
398
+ .
399
+ ├── intlayer.config.ts
400
+ └── src
401
+ ├── middleware.ts
402
+ ├── app
403
+ │ └── [locale]
404
+ │ ├── layout.tsx
405
+ │ └── home
406
+ │ ├── index.tsx
407
+ │ └── index.content.ts
408
+ └── components
409
+ └── Navbar
410
+ ├── index.tsx
411
+ └── index.content.ts
412
+ ```
413
+
414
+ </TabItem>
415
+ </Tab>
416
+
417
+ #### Comparação
418
+
419
+ - **next-intl / next-i18next**: Catálogos centralizados (JSON; namespaces/mensagens). Estrutura clara, integra-se bem com plataformas de tradução, mas pode levar a mais edições entre arquivos conforme as aplicações crescem.
420
+ - **Intlayer**: Dicionários `.content.{ts|js|json}` por componente, localizados junto aos componentes. Facilita o reuso de componentes e o raciocínio local; adiciona arquivos e depende de ferramentas em tempo de build.
421
+
422
+ #### Configuração e Carregamento de Conteúdo
423
+
424
+ Como mencionado anteriormente, você deve otimizar a forma como cada arquivo JSON é importado no seu código.
425
+ A forma como a biblioteca lida com o carregamento de conteúdo é importante.
426
+
427
+ <Tab defaultTab="next-intl" group='techno'>
428
+ <TabItem label="next-i18next" value="next-i18next">
429
+
430
+ ```tsx fileName="next-i18next.config.js"
431
+ module.exports = {
432
+ i18n: {
433
+ locales: ["en", "fr", "es"],
434
+ defaultLocale: "en",
435
+ },
436
+ };
437
+ ```
438
+
439
+ ```tsx fileName="src/app/_app.tsx"
440
+ import { appWithTranslation } from "next-i18next";
441
+
442
+ const MyApp = ({ Component, pageProps }) => <Component {...pageProps} />;
443
+
444
+ export default appWithTranslation(MyApp);
445
+ ```
446
+
447
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
448
+ import type { GetStaticProps } from "next";
449
+ import { serverSideTranslations } from "next-i18next/serverSideTranslations";
450
+ import { useTranslation } from "next-i18next";
451
+ import { I18nextProvider, initReactI18next } from "react-i18next";
452
+ import { createInstance } from "i18next";
453
+ import { ClientComponent, ServerComponent } from "@components";
454
+
455
+ export default function HomePage({ locale }: { locale: string }) {
456
+ // Declare explicitamente o namespace usado por este componente
457
+ const resources = await loadMessagesFor(locale); // seu carregador (JSON, etc.)
458
+
459
+ const i18n = createInstance();
460
+ i18n.use(initReactI18next).init({
461
+ lng: locale,
462
+ fallbackLng: "en",
463
+ resources,
464
+ ns: ["common", "about"],
465
+ defaultNS: "common",
466
+ interpolation: { escapeValue: false },
467
+ });
468
+
469
+ const { t } = useTranslation("about");
470
+
471
+ return (
472
+ <I18nextProvider i18n={i18n}>
473
+ <main>
474
+ <h1>{t("title")}</h1>
475
+ <ClientComponent />
476
+ <ServerComponent />
477
+ </main>
478
+ </I18nextProvider>
479
+ );
480
+ }
481
+
482
+ export const getStaticProps: GetStaticProps = async ({ locale }) => {
483
+ // Pré-carregue apenas os namespaces necessários para ESTA página
484
+ return {
485
+ props: {
486
+ ...(await serverSideTranslations(locale ?? "en", ["common", "about"])),
487
+ },
488
+ };
489
+ };
490
+ ```
491
+
492
+ </TabItem>
493
+ <TabItem label="next-intl" value="next-intl">
494
+
495
+ ```tsx fileName="i18n.ts"
496
+ import { getRequestConfig } from "next-intl/server";
497
+ import { notFound } from "next/navigation";
498
+
499
+ // Pode ser importado de uma configuração compartilhada
500
+ const locales = ["en", "fr", "es"];
501
+
502
+ export default getRequestConfig(async ({ locale }) => {
503
+ // Valida se o parâmetro `locale` recebido é válido
504
+ if (!locales.includes(locale as any)) notFound();
505
+
506
+ return {
507
+ messages: (await import(`../messages/${locale}.json`)).default,
508
+ };
509
+ });
510
+ ```
511
+
512
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
513
+ import { NextIntlClientProvider } from "next-intl";
514
+ import { getMessages, unstable_setRequestLocale } from "next-intl/server";
515
+ import pick from "lodash/pick";
516
+
517
+ export default async function LocaleLayout({
518
+ children,
519
+ params,
520
+ }: {
521
+ children: React.ReactNode;
522
+ params: { locale: string };
523
+ }) {
524
+ const { locale } = params;
525
+
526
+ // Define o locale ativo da requisição para esta renderização no servidor (RSC)
527
+ unstable_setRequestLocale(locale);
528
+
529
+ // As mensagens são carregadas no servidor via src/i18n/request.ts
530
+ // (veja a documentação do next-intl). Aqui, enviamos apenas um subconjunto para o cliente
531
+ // que é necessário para os componentes cliente (otimização do payload).
532
+ const messages = await getMessages();
533
+ const clientMessages = pick(messages, ["common", "about"]);
534
+
535
+ const rtlLocales = ["ar", "he", "fa", "ur"];
536
+
537
+ return (
538
+ <html lang={locale} dir={rtlLocales.includes(locale) ? "rtl" : "ltr"}>
539
+ <body>
540
+ <NextIntlClientProvider locale={locale} messages={clientMessages}>
541
+ {children}
542
+ </NextIntlClientProvider>
543
+ </body>
544
+ </html>
545
+ );
546
+ }
547
+ ```
548
+
549
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
550
+ import { getTranslations } from "next-intl/server";
551
+ import { ClientComponent, ServerComponent } from "@components";
552
+
553
+ export default async function LandingPage({
554
+ params,
555
+ }: {
556
+ params: { locale: string };
557
+ }) {
558
+ // Carregamento estritamente do lado do servidor (não hidratado no cliente)
559
+ const t = await getTranslations("about");
560
+
561
+ return (
562
+ <main>
563
+ <h1>{t("title")}</h1>
564
+ <ClientComponent />
565
+ <ServerComponent />
566
+ </main>
567
+ );
568
+ }
569
+ ```
570
+
571
+ </TabItem>
572
+ <TabItem label="intlayer" value="intlayer">
573
+
574
+ ```tsx fileName="intlayer.config.ts"
575
+ export default {
576
+ internationalization: {
577
+ locales: ["en", "fr", "es"],
578
+ defaultLocale: "en",
579
+ },
580
+ };
581
+ ```
129
582
 
130
- - **next-intl / next-i18next**: Normalmente você integra plataformas externas para traduções e fluxos editoriais.
131
- - **Intlayer**: Inclui um **Editor Visual gratuito** e **CMS opcional** (compatível com Git ou externalizado). Além disso, **extensão para VSCode** para autoria de conteúdo e **traduções assistidas por IA** usando suas próprias chaves de provedores.
583
+ ```tsx fileName="src/app/[locale]/layout.tsx"
584
+ import { getHTMLTextDir } from "intlayer";
585
+ import {
586
+ IntlayerClientProvider,
587
+ generateStaticParams,
588
+ type NextLayoutIntlayer,
589
+ } from "next-intlayer";
132
590
 
133
- **Por que isso importa:** Reduz os custos operacionais e encurta o ciclo entre desenvolvedores e autores de conteúdo.
591
+ export const dynamic = "force-static";
592
+
593
+ const LandingLayout: NextLayoutIntlayer = async ({ children, params }) => {
594
+ const { locale } = await params;
595
+
596
+ return (
597
+ <html lang={locale} dir={getHTMLTextDir(locale)}>
598
+ <IntlayerClientProvider locale={locale}>
599
+ {children}
600
+ </IntlayerClientProvider>
601
+ </html>
602
+ );
603
+ };
604
+
605
+ export default LandingLayout;
606
+ ```
607
+
608
+ ```tsx fileName="src/app/[locale]/about/page.tsx"
609
+ import { PageContent } from "@components/PageContent";
610
+ import type { NextPageIntlayer } from "next-intlayer";
611
+ import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server";
612
+ import { ClientComponent, ServerComponent } from "@components";
613
+
614
+ const LandingPage: NextPageIntlayer = async ({ params }) => {
615
+ const { locale } = await params;
616
+ const { title } = useIntlayer("about", locale);
617
+
618
+ return (
619
+ <IntlayerServerProvider locale={locale}>
620
+ <main>
621
+ <h1>{title}</h1>
622
+ <ClientComponent />
623
+ <ServerComponent />
624
+ </main>
625
+ </IntlayerServerProvider>
626
+ );
627
+ };
628
+
629
+ export default LandingPage;
630
+ ```
631
+
632
+ </TabItem>
633
+ </Tab>
634
+
635
+ #### Comparação
636
+
637
+ Todos os três suportam carregamento de conteúdo e provedores por localidade.
638
+
639
+ - Com **next-intl/next-i18next**, normalmente você carrega mensagens/namespaces selecionados por rota e coloca os providers onde necessário.
640
+
641
+ - Com **Intlayer**, adiciona uma análise em tempo de build para inferir o uso, o que pode reduzir a configuração manual e permitir um único provider raiz.
642
+
643
+ Escolha entre controle explícito e automação com base na preferência da equipe.
644
+
645
+ ### Uso em um componente cliente
646
+
647
+ Vamos pegar um exemplo de um componente cliente que renderiza um contador.
648
+
649
+ <Tab defaultTab="next-intl" group='techno'>
650
+ <TabItem label="next-i18next" value="next-i18next">
651
+
652
+ **Traduções (devem ser JSON reais em `public/locales/...`)**
653
+
654
+ ```json fileName="public/locales/en/about.json"
655
+ {
656
+ "counter": {
657
+ "label": "Counter",
658
+ "increment": "Increment"
659
+ }
660
+ }
661
+ ```
662
+
663
+ ```json fileName="public/locales/fr/about.json"
664
+ {
665
+ "counter": {
666
+ "label": "Contador",
667
+ "increment": "Incrementar"
668
+ }
669
+ }
670
+ ```
671
+
672
+ **Componente cliente**
673
+
674
+ ```tsx fileName="src/components/ClientComponentExample.tsx"
675
+ "use client";
676
+
677
+ import React, { useMemo, useState } from "react";
678
+ import { useTranslation } from "next-i18next";
679
+
680
+ const ClientComponentExample = () => {
681
+ const { t, i18n } = useTranslation("about");
682
+ const [count, setCount] = useState(0);
683
+
684
+ // next-i18next não expõe useNumber; use Intl.NumberFormat
685
+ const numberFormat = new Intl.NumberFormat(i18n.language);
686
+
687
+ return (
688
+ <div>
689
+ <p>{numberFormat.format(count)}</p>
690
+ <button
691
+ aria-label={t("counter.label")}
692
+ onClick={() => setCount((count) => count + 1)}
693
+ >
694
+ {t("counter.increment")}
695
+ </button>
696
+ </div>
697
+ );
698
+ };
699
+ ```
700
+
701
+ > Não se esqueça de adicionar o namespace "about" na função serverSideTranslations da página
702
+ > Aqui usamos a versão do React 19.x.x, mas para versões inferiores, será necessário usar useMemo para armazenar a instância do formatador, pois é uma função pesada
703
+
704
+ </TabItem>
705
+ <TabItem label="next-intl" value="next-intl">
706
+
707
+ **Traduções (mesma estrutura; carregue-as nas mensagens do next-intl conforme preferir)**
708
+
709
+ ```json fileName="locales/en/about.json"
710
+ {
711
+ "counter": {
712
+ "label": "Counter",
713
+ "increment": "Increment"
714
+ }
715
+ }
716
+ ```
717
+
718
+ ```json fileName="locales/fr/about.json"
719
+ {
720
+ "counter": {
721
+ "label": "Compteur",
722
+ "increment": "Incrémenter"
723
+ }
724
+ }
725
+ ```
726
+
727
+ **Componente cliente**
728
+
729
+ ```tsx fileName="src/components/ClientComponentExample.tsx"
730
+ "use client";
731
+
732
+ import React, { useState } from "react";
733
+ import { useTranslations, useFormatter } from "next-intl";
734
+
735
+ const ClientComponentExample = () => {
736
+ // Escopo diretamente para o objeto aninhado
737
+ const t = useTranslations("about.counter");
738
+ const format = useFormatter();
739
+ const [count, setCount] = useState(0);
740
+
741
+ return (
742
+ <div>
743
+ <p>{format.number(count)}</p>
744
+ <button
745
+ aria-label={t("label")}
746
+ onClick={() => setCount((count) => count + 1)}
747
+ >
748
+ {t("increment")}
749
+ </button>
750
+ </div>
751
+ );
752
+ };
753
+ ```
754
+
755
+ > Não esqueça de adicionar a mensagem "about" na mensagem do cliente da página
756
+
757
+ </TabItem>
758
+ <TabItem label="intlayer" value="intlayer">
759
+
760
+ **Conteúdo**
761
+
762
+ ```ts fileName="src/components/ClientComponentExample/index.content.ts"
763
+ import { t, type Dictionary } from "intlayer";
764
+
765
+ const counterContent = {
766
+ key: "counter",
767
+ content: {
768
+ label: t({ pt: "Contador", en: "Counter", fr: "Compteur" }),
769
+ increment: t({ pt: "Incrementar", en: "Increment", fr: "Incrémenter" }),
770
+ },
771
+ } satisfies Dictionary;
772
+
773
+ export default counterContent;
774
+ ```
775
+
776
+ **Componente cliente**
777
+
778
+ ```tsx fileName="src/components/ClientComponentExample/index.tsx"
779
+ "use client";
780
+
781
+ import React, { useState } from "react";
782
+ import { useNumber, useIntlayer } from "next-intlayer";
783
+
784
+ const ClientComponentExample = () => {
785
+ const [count, setCount] = useState(0);
786
+ const { label, increment } = useIntlayer("counter"); // retorna strings
787
+ const { number } = useNumber();
788
+
789
+ return (
790
+ <div>
791
+ <p>{number(count)}</p>
792
+ <button aria-label={label} onClick={() => setCount((count) => count + 1)}>
793
+ {increment}
794
+ </button>
795
+ </div>
796
+ );
797
+ };
798
+ ```
799
+
800
+ </TabItem>
801
+ </Tab>
802
+
803
+ #### Comparação
804
+
805
+ - **Formatação de números**
806
+ - **next-i18next**: não possui `useNumber`; usa `Intl.NumberFormat` (ou i18next-icu).
807
+ - **next-intl**: `useFormatter().number(value)`.
808
+ - **Intlayer**: `useNumber()` embutido.
809
+
810
+ - **Chaves**
811
+ - Mantenha uma estrutura aninhada (`about.counter.label`) e escopo seu hook de acordo (`useTranslation("about")` + `t("counter.label")` ou `useTranslations("about.counter")` + `t("label")`).
812
+
813
+ - **Localização dos arquivos**
814
+ - **next-i18next** espera JSON em `public/locales/{lng}/{ns}.json`.
815
+ - **next-intl** é flexível; carrega mensagens conforme sua configuração.
816
+ - **Intlayer** armazena conteúdo em dicionários TS/JS e resolve por chave.
134
817
 
135
818
  ---
136
819
 
137
- ## Quando escolher qual?
820
+ ### Uso em um componente servidor
821
+
822
+ Vamos considerar o caso de um componente de interface do usuário (UI). Este componente é um componente de servidor e deve ser capaz de ser inserido como filho de um componente cliente. (página (componente de servidor) -> componente cliente -> componente de servidor). Como este componente pode ser inserido como filho de um componente cliente, ele não pode ser assíncrono.
823
+
824
+ <Tab defaultTab="next-intl" group='techno'>
825
+ <TabItem label="next-i18next" value="next-i18next">
826
+
827
+ ```tsx fileName="src/pages/about.tsx"
828
+ import type { GetStaticProps } from "next";
829
+ import { useTranslation } from "next-i18next";
830
+
831
+ type ServerComponentProps = {
832
+ count: number;
833
+ };
834
+
835
+ const ServerComponent = ({ count }: ServerComponentProps) => {
836
+ const { t, i18n } = useTranslation("about");
837
+ const formatted = new Intl.NumberFormat(i18n.language).format(count);
838
+
839
+ return (
840
+ <div>
841
+ <p>{formatted}</p>
842
+ <button aria-label={t("counter.label")}>{t("counter.increment")}</button>
843
+ </div>
844
+ );
845
+ };
846
+ ```
847
+
848
+ </TabItem>
849
+ <TabItem label="next-intl" value="next-intl">
850
+
851
+ ```tsx fileName="src/components/ServerComponent.tsx"
852
+ type ServerComponentProps = {
853
+ count: number;
854
+ t: (key: string) => string;
855
+ formatter: Intl.NumberFormat;
856
+ };
857
+
858
+ const ServerComponent = ({ t, count, formatter }: ServerComponentProps) => {
859
+ const formatted = formatter.format(count);
860
+
861
+ return (
862
+ <div>
863
+ <p>{formatted}</p>
864
+ <button aria-label={t("label")}>{t("increment")}</button>
865
+ </div>
866
+ );
867
+ };
868
+ ```
869
+
870
+ > Como o componente do servidor não pode ser assíncrono, você precisa passar as traduções e a função formatadora como props.
871
+ >
872
+ > - `const t = await getTranslations("about.counter");`
873
+ > - `const formatter = await getFormatter().then((formatter) => formatter.number());`
874
+
875
+ </TabItem>
876
+ <TabItem label="intlayer" value="intlayer">
877
+
878
+ ```tsx fileName="src/components/ServerComponent.tsx"
879
+ import { useIntlayer, useNumber } from "next-intlayer/server";
880
+
881
+ const ServerComponent = ({ count }: { count: number }) => {
882
+ const { label, increment } = useIntlayer("counter");
883
+ const { number } = useNumber();
884
+
885
+ return (
886
+ <div>
887
+ <p>{number(count)}</p>
888
+ <button aria-label={label}>{increment}</button>
889
+ </div>
890
+ );
891
+ };
892
+ ```
893
+
894
+ </TabItem>
895
+ </Tab>
896
+
897
+ > O Intlayer expõe hooks **seguros para o servidor** via `next-intlayer/server`. Para funcionar, `useIntlayer` e `useNumber` usam uma sintaxe semelhante a hooks, parecida com os hooks do cliente, mas dependem, nos bastidores, do contexto do servidor (`IntlayerServerProvider`).
898
+
899
+ ### Metadados / Sitemap / Robots
138
900
 
139
- - **Escolha next-intl** se você quer uma solução **minimalista**, está confortável com catálogos centralizados e seu aplicativo é de **pequeno a médio porte**.
140
- - **Escolha next-i18next** se você precisa do **ecossistema de plugins do i18next** (por exemplo, regras avançadas ICU via plugins) e sua equipe já conhece o i18next, aceitando **mais configuração** para maior flexibilidade.
141
- - **Escolha Intlayer** se você valoriza **conteúdo com escopo por componente**, **TypeScript rigoroso**, **garantias em tempo de build**, **tree-shaking** e ferramentas completas de roteamento/SEO/edição - especialmente para **Next.js App Router** e **bases de código grandes e modulares**.
901
+ Traduzir conteúdo é ótimo. Mas as pessoas geralmente esquecem que o principal objetivo da internacionalização é tornar seu site mais visível para o mundo. I18n é uma alavanca incrível para melhorar a visibilidade do seu site.
902
+
903
+ Aqui está uma lista de boas práticas relacionadas ao SEO multilíngue.
904
+
905
+ - definir meta tags hreflang na tag `<head>`
906
+ > Isso ajuda os motores de busca a entender quais idiomas estão disponíveis na página
907
+ - liste todas as traduções das páginas no sitemap.xml usando o esquema XML `http://www.w3.org/1999/xhtml`
908
+ >
909
+ - não esqueça de excluir as páginas prefixadas do robots.txt (ex.: `/dashboard`, e `/fr/dashboard`, `/es/dashboard`)
910
+ >
911
+ - use um componente Link personalizado para redirecionar para a página mais localizada (ex.: em francês `<a href="/fr/about">A propos</a>`)
912
+ >
913
+
914
+ Os desenvolvedores frequentemente esquecem de referenciar corretamente suas páginas entre os diferentes locais.
915
+
916
+ <Tab defaultTab="next-intl" group='techno'>
917
+
918
+ <TabItem label="next-i18next" value="next-i18next">
919
+
920
+ ```ts fileName="i18n.config.ts"
921
+ export const locales = ["en", "fr"] as const;
922
+ export type Locale = (typeof locales)[number];
923
+ export const defaultLocale: Locale = "en";
924
+
925
+ export function localizedPath(locale: string, path: string) {
926
+ return locale === defaultLocale ? path : "/" + locale + path;
927
+ }
928
+
929
+ const ORIGIN = "https://example.com";
930
+ export function abs(locale: string, path: string) {
931
+ return ORIGIN + localizedPath(locale, path);
932
+ }
933
+ ```
934
+
935
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
936
+ import type { Metadata } from "next";
937
+ import { locales, defaultLocale, localizedPath } from "@/i18n.config";
938
+
939
+ export async function generateMetadata({
940
+ params,
941
+ }: {
942
+ params: { locale: string };
943
+ }): Promise<Metadata> {
944
+ const { locale } = params;
945
+
946
+ // Importa dinamicamente o arquivo JSON correto
947
+ const messages = (
948
+ await import("@/../public/locales/" + locale + "/about.json")
949
+ ).default;
950
+
951
+ const languages = Object.fromEntries(
952
+ locales.map((locale) => [locale, localizedPath(locale, "/about")])
953
+ );
954
+
955
+ return {
956
+ title: messages.title,
957
+ description: messages.description,
958
+ alternates: {
959
+ canonical: localizedPath(locale, "/about"),
960
+ languages: { ...languages, "x-default": "/about" },
961
+ },
962
+ };
963
+ }
964
+
965
+ export default async function AboutPage() {
966
+ return <h1>Sobre</h1>;
967
+ }
968
+ ```
969
+
970
+ ```ts fileName="src/app/sitemap.ts"
971
+ import type { MetadataRoute } from "next";
972
+ import { locales, defaultLocale, abs } from "@/i18n.config";
973
+
974
+ export default function sitemap(): MetadataRoute.Sitemap {
975
+ const languages = Object.fromEntries(
976
+ locales.map((locale) => [locale, abs(locale, "/about")])
977
+ );
978
+ return [
979
+ {
980
+ url: abs(defaultLocale, "/about"),
981
+ lastModified: new Date(),
982
+ changeFrequency: "monthly",
983
+ priority: 0.7,
984
+ alternates: { languages },
985
+ },
986
+ ];
987
+ }
988
+ ```
989
+
990
+ ```ts fileName="src/app/robots.ts"
991
+ import type { MetadataRoute } from "next";
992
+ import { locales, defaultLocale, localizedPath } from "@/i18n.config";
993
+
994
+ const ORIGIN = "https://example.com";
995
+
996
+ const expandAllLocales = (path: string) => [
997
+ localizedPath(defaultLocale, path),
998
+ ...locales
999
+ .filter((locale) => locale !== defaultLocale)
1000
+ .map((locale) => localizedPath(locale, path)),
1001
+ ];
1002
+
1003
+ export default function robots(): MetadataRoute.Robots {
1004
+ const disallow = [
1005
+ ...expandAllLocales("/dashboard"),
1006
+ ...expandAllLocales("/admin"),
1007
+ ];
1008
+
1009
+ return {
1010
+ rules: { userAgent: "*", allow: ["/"], disallow },
1011
+ host: ORIGIN,
1012
+ sitemap: ORIGIN + "/sitemap.xml",
1013
+ };
1014
+ }
1015
+ ```
1016
+
1017
+ </TabItem>
1018
+ <TabItem label="next-intl" value="next-intl">
1019
+
1020
+ ```tsx fileName="src/app/[locale]/about/layout.tsx"
1021
+ import type { Metadata } from "next";
1022
+ import { locales, defaultLocale } from "@/i18n";
1023
+ import { getTranslations } from "next-intl/server";
1024
+
1025
+ function localizedPath(locale: string, path: string) {
1026
+ return locale === defaultLocale ? path : "/" + locale + path;
1027
+ }
1028
+
1029
+ export async function generateMetadata({
1030
+ params,
1031
+ }: {
1032
+ params: { locale: string };
1033
+ }): Promise<Metadata> {
1034
+ const { locale } = params;
1035
+ const t = await getTranslations({ locale, namespace: "about" });
1036
+
1037
+ const url = "/about";
1038
+ const languages = Object.fromEntries(
1039
+ locales.map((locale) => [locale, localizedPath(locale, url)])
1040
+ );
1041
+
1042
+ return {
1043
+ title: t("title"),
1044
+ description: t("description"),
1045
+ alternates: {
1046
+ canonical: localizedPath(locale, url),
1047
+ languages: { ...languages, "x-default": url },
1048
+ },
1049
+ };
1050
+ }
1051
+
1052
+ // ... Resto do código da página
1053
+ ```
1054
+
1055
+ ```tsx fileName="src/app/sitemap.ts"
1056
+ import type { MetadataRoute } from "next";
1057
+ import { locales, defaultLocale } from "@/i18n";
1058
+
1059
+ const origin = "https://example.com";
1060
+
1061
+ const formatterLocalizedPath = (locale: string, path: string) =>
1062
+ locale === defaultLocale ? origin + path : origin + "/" + locale + path;
1063
+
1064
+ export default function sitemap(): MetadataRoute.Sitemap {
1065
+ const aboutLanguages = Object.fromEntries(
1066
+ locales.map((l) => [l, formatterLocalizedPath(l, "/about")])
1067
+ );
1068
+
1069
+ return [
1070
+ {
1071
+ url: formatterLocalizedPath(defaultLocale, "/about"),
1072
+ lastModified: new Date(),
1073
+ changeFrequency: "monthly",
1074
+ priority: 0.7,
1075
+ alternates: { languages: aboutLanguages },
1076
+ },
1077
+ ];
1078
+ }
1079
+ ```
1080
+
1081
+ ```tsx fileName="src/app/robots.ts"
1082
+ import type { MetadataRoute } from "next";
1083
+ import { locales, defaultLocale } from "@/i18n";
1084
+
1085
+ const origin = "https://example.com";
1086
+ const withAllLocales = (path: string) => [
1087
+ path,
1088
+ ...locales
1089
+ .filter((locale) => locale !== defaultLocale)
1090
+ .map((locale) => "/" + locale + path),
1091
+ ];
1092
+
1093
+ export default function robots(): MetadataRoute.Robots {
1094
+ const disallow = [
1095
+ ...withAllLocales("/dashboard"),
1096
+ ...withAllLocales("/admin"),
1097
+ ];
1098
+
1099
+ return {
1100
+ rules: { userAgent: "*", allow: ["/"], disallow },
1101
+ host: origin,
1102
+ sitemap: origin + "/sitemap.xml",
1103
+ };
1104
+ }
1105
+ ```
1106
+
1107
+ </TabItem>
1108
+ <TabItem label="intlayer" value="intlayer">
1109
+
1110
+ ```typescript fileName="src/app/[locale]/about/layout.tsx"
1111
+ import { getIntlayer, getMultilingualUrls } from "intlayer";
1112
+ import type { Metadata } from "next";
1113
+ import type { LocalPromiseParams } from "next-intlayer";
1114
+
1115
+ export const generateMetadata = async ({
1116
+ params,
1117
+ }: LocalPromiseParams): Promise<Metadata> => {
1118
+ const { locale } = await params;
1119
+
1120
+ const metadata = getIntlayer("page-metadata", locale);
1121
+
1122
+ const multilingualUrls = getMultilingualUrls("/about");
1123
+
1124
+ return {
1125
+ ...metadata,
1126
+ alternates: {
1127
+ canonical: multilingualUrls[locale as keyof typeof multilingualUrls],
1128
+ languages: { ...multilingualUrls, "x-default": "/about" },
1129
+ },
1130
+ };
1131
+ };
1132
+
1133
+ // ... Resto do código da página
1134
+ ```
1135
+
1136
+ ```tsx fileName="src/app/sitemap.ts"
1137
+ import { getMultilingualUrls } from "intlayer";
1138
+ import type { MetadataRoute } from "next";
1139
+
1140
+ const sitemap = (): MetadataRoute.Sitemap => [
1141
+ {
1142
+ url: "https://example.com/about",
1143
+ alternates: {
1144
+ languages: { ...getMultilingualUrls("https://example.com/about") },
1145
+ },
1146
+ },
1147
+ ];
1148
+ ```
1149
+
1150
+ ```tsx fileName="src/app/robots.ts"
1151
+ import { getMultilingualUrls } from "intlayer";
1152
+ import type { MetadataRoute } from "next";
1153
+
1154
+ const getAllMultilingualUrls = (urls: string[]) =>
1155
+ urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]);
1156
+
1157
+ // Configuração do arquivo robots.txt para controlar o acesso dos robôs de busca
1158
+ const robots = (): MetadataRoute.Robots => ({
1159
+ rules: {
1160
+ userAgent: "*",
1161
+ allow: ["/"],
1162
+ disallow: getAllMultilingualUrls(["/dashboard"]), // Bloqueia URLs multilíngues do dashboard
1163
+ },
1164
+ host: "https://example.com",
1165
+ sitemap: "https://example.com/sitemap.xml",
1166
+ });
1167
+
1168
+ export default robots;
1169
+ ```
1170
+
1171
+ </TabItem>
1172
+ </Tab>
1173
+
1174
+ > Intlayer fornece uma função `getMultilingualUrls` para gerar URLs multilíngues para seu sitemap.
1175
+
1176
+ ---
142
1177
 
143
1178
  ---
144
1179
 
145
- ## Notas práticas de migração (next-intl / next-i18next → Intlayer)
1180
+ ## E o vencedor é…
1181
+
1182
+ Não é simples. Cada opção tem seus prós e contras. Aqui está como eu vejo:
1183
+
1184
+ <Columns>
1185
+ <Column>
1186
+
1187
+ **next-intl**
1188
+
1189
+ - a mais simples, leve, com menos decisões impostas a você. Se você quer uma solução **mínima**, está confortável com catálogos centralizados, e seu app é **pequeno a médio porte**.
1190
+
1191
+ </Column>
1192
+ <Column>
1193
+
1194
+ **next-i18next**
1195
+
1196
+ - madura, cheia de recursos, muitos plugins da comunidade, mas com custo de configuração mais alto. Se você precisa do **ecossistema de plugins do i18next** (por exemplo, regras avançadas ICU via plugins) e sua equipe já conhece o i18next, aceitando **mais configuração** para flexibilidade.
1197
+
1198
+ </Column>
1199
+ <Column>
1200
+
1201
+ **Intlayer**
1202
+
1203
+ - construído para o Next.js moderno, com conteúdo modular, segurança de tipos, ferramentas e menos código repetitivo. Se você valoriza **conteúdo com escopo de componente**, **TypeScript rigoroso**, **garantias em tempo de build**, **tree-shaking** e ferramentas de roteamento/SEO/editor **com tudo incluído** - especialmente para **Next.js App Router**, sistemas de design e **bases de código grandes e modulares**.
1204
+
1205
+ </Column>
1206
+ </Columns>
1207
+
1208
+ Se você prefere uma configuração mínima e aceita algum trabalho manual, next-intl é uma boa escolha. Se você precisa de todos os recursos e não se importa com a complexidade, next-i18next funciona. Mas se você quer uma solução moderna, escalável e modular com ferramentas integradas, Intlayer pretende oferecer isso pronto para uso.
1209
+
1210
+ > **Alternativa para equipes empresariais**: Se você precisa de uma solução comprovada que funcione perfeitamente com plataformas de localização estabelecidas como **Crowdin**, **Phrase** ou outros sistemas profissionais de gerenciamento de tradução, considere **next-intl** ou **next-i18next** pelo seu ecossistema maduro e integrações comprovadas.
1211
+
1212
+ > **Roteiro futuro**: O Intlayer também planeja desenvolver plugins que funcionem sobre as soluções **i18next** e **next-intl**. Isso lhe dará as vantagens do Intlayer para automação, sintaxe e gerenciamento de conteúdo, mantendo a segurança e estabilidade fornecidas por essas soluções consolidadas no código da sua aplicação.
1213
+
1214
+ ## Estrelas no GitHub (GitHub STARs)
1215
+
1216
+ As estrelas no GitHub são um forte indicador da popularidade de um projeto, da confiança da comunidade e da relevância a longo prazo. Embora não sejam uma medida direta da qualidade técnica, refletem quantos desenvolvedores consideram o projeto útil, acompanham seu progresso e provavelmente o adotam. Para estimar o valor de um projeto, as estrelas ajudam a comparar a tração entre alternativas e fornecem insights sobre o crescimento do ecossistema.
146
1217
 
147
- - **Comece por funcionalidade**: Mova uma rota ou componente de cada vez para **dicionários locais**.
148
- - **Mantenha os catálogos antigos em paralelo**: Faça a ponte durante a migração; evite um grande corte abrupto.
149
- - **Ative verificações rigorosas**: Permita que a detecção em tempo de build identifique lacunas cedo.
150
- - **Adote middleware e helpers**: Padronize a detecção de localidade e as tags de SEO em todo o site.
151
- - **Meça os bundles**: Espere **reduções no tamanho do bundle** à medida que o conteúdo não utilizado é descartado.
1218
+ [![Gráfico do Histórico de Estrelas](https://api.star-history.com/svg?repos=i18next/next-i18next&repos=amannn/next-intl&repos=aymericzip/intlayer&type=Date)](https://www.star-history.com/#i18next/next-i18next&amannn/next-intl&aymericzip/intlayer)
152
1219
 
153
1220
  ---
154
1221
 
155
1222
  ## Conclusão
156
1223
 
157
- As três bibliotecas têm sucesso na localização básica. A diferença está em **quanto trabalho você precisa fazer** para alcançar uma configuração robusta e escalável no **Next.js moderno**:
1224
+ Todas as três bibliotecas têm sucesso na localização principal. A diferença é **quanto trabalho você deve fazer** para alcançar uma configuração robusta e escalável no **Next.js moderno**:
158
1225
 
159
- - Com **Intlayer**, **conteúdo modular**, **TS rigoroso**, **segurança em tempo de build**, **bundles otimizados por tree-shaking** e **ferramentas de App Router + SEO de primeira classe** são **padrões**, não tarefas.
160
- - Se sua equipe valoriza **manutenibilidade e velocidade** em um app multi-idioma orientado a componentes, o Intlayer oferece a experiência **mais completa** atualmente.
1226
+ - Com o **Intlayer**, **conteúdo modular**, **TS rigoroso**, **segurança em tempo de compilação**, **pacotes otimizados por tree-shaking** e **App Router de primeira classe + ferramentas de SEO** são **padrões**, não tarefas.
1227
+ - Se sua equipe valoriza **manutenibilidade e velocidade** em um aplicativo multi-idioma orientado a componentes, o Intlayer oferece a experiência **mais completa** atualmente.
161
1228
 
162
1229
  Consulte o documento ['Por que Intlayer?'](https://intlayer.org/doc/why) para mais detalhes.