Começando com Internacionalização (i18n) usando Intlayer e Next.js com Page Router
O que é o Intlayer?
Intlayer é uma biblioteca de internacionalização (i18n) inovadora e de código aberto, projetada para simplificar o suporte multilíngue em aplicações web modernas. O Intlayer se integra perfeitamente com o mais recente framework Next.js, incluindo seu tradicional Page Router.
Com o Intlayer, você pode:
- Gerenciar traduções facilmente usando dicionários declarativos no nível do componente.
- Localizar dinamicamente metadados, rotas e conteúdo.
- Garantir suporte ao TypeScript com tipos autogerados, melhorando a autocompletação e a detecção de erros.
- Aproveitar recursos avançados, como detecção e troca dinâmica de localidade.
O Intlayer é compatível com Next.js 12, 13, 14 e 15. Se você estiver usando o Next.js App Router, consulte o guia do App Router. Para o Next.js 15, siga este guia.
Guia Passo a Passo para Configurar o Intlayer em uma Aplicação Next.js Usando Page Router
Passo 1: Instale as Dependências
Instale os pacotes necessários usando seu gerenciador de pacotes preferido:
npm install intlayer next-intlayer
intlayer
O pacote principal que fornece ferramentas de internacionalização para gerenciamento de configuração, tradução, declaração de conteúdo, transpiração e comandos CLI.
next-intlayer
O pacote que integra o Intlayer com o Next.js. Ele fornece provedores de contexto e hooks para internacionalização no Next.js. Além disso, inclui o plugin Next.js para integrar o Intlayer com Webpack ou Turbopack, bem como middleware para detectar a localidade preferida do usuário, gerenciar cookies e lidar com redirecionamento de URLs.
Passo 2: Configure Seu Projeto
Crie um arquivo de configuração para definir os idiomas suportados pela sua aplicação:
// Configuração do Intlayerimport { Locales, type IntlayerConfig } from "intlayer";const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // Adicione outras localidades aqui ], defaultLocale: Locales.ENGLISH, },};export default config;
Por meio deste arquivo de configuração, você pode configurar URLs localizados, redirecionamento de middleware, nomes de cookies, a localização e extensão de suas declarações de conteúdo, desativar logs do Intlayer no console e muito mais. Para uma lista completa de parâmetros disponíveis, consulte a documentação de configuração.
Passo 3: Integre o Intlayer com a Configuração do Next.js
Modifique sua configuração do Next.js para incorporar o Intlayer:
// Integração do Intlayer com Next.jsimport { withIntlayer } from "next-intlayer/server";/** @type {import('next').NextConfig} */const nextConfig = { // Sua configuração existente do Next.js};export default withIntlayer(nextConfig);
O plugin withIntlayer() do Next.js é usado para integrar o Intlayer com o Next.js. Ele garante a construção de arquivos de declaração de conteúdo e os monitora no modo de desenvolvimento. Define variáveis de ambiente do Intlayer nos ambientes Webpack ou Turbopack. Além disso, fornece aliases para otimizar o desempenho e garante compatibilidade com componentes do servidor.
Passo 4: Configure Middleware para Detecção de Localidade
Configure o middleware para detectar e lidar automaticamente com a localidade preferida do usuário:
// Middleware para detecção de localidadeexport { intlayerMiddleware as middleware } from "next-intlayer/middleware";export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\..*|_next).*)",};
Adapte o parâmetro matcher para corresponder às rotas da sua aplicação. Para mais detalhes, consulte a documentação do Next.js sobre configuração do matcher.
Passo 5: Defina Rotas Dinâmicas de Localidade
Implemente roteamento dinâmico para servir conteúdo localizado com base na localidade do usuário.
Crie Páginas Específicas para Localidades:
Renomeie o arquivo da sua página principal para incluir o segmento dinâmico [locale].
bashmv src/pages/index.tsx src/pages/[locale]/index.tsx
Atualize _app.tsx para Lidar com Localização:
Modifique seu `_app.tsx` para incluir provedores do Intlayer. ```tsx fileName="src/pages/_app.tsx" codeFormat="typescript"// Configuração do App com Intlayer import type { FC } from "react"; import type { AppProps } from "next/app"; import { IntlayerClientProvider } from "next-intlayer";
const App = FC<AppProps>({ Component, pageProps }) => { const { locale } = pageProps; return ( <IntlayerClientProvider locale={locale}> <Component {...pageProps} /> </IntlayerClientProvider> ); } export default MyApp; ``` ```jsx fileName="src/pages/_app.mjx" codeFormat="esm"// Configuração do App com Intlayer import { IntlayerClientProvider } from "next-intlayer";
const App = ({ Component, pageProps }) => ( <IntlayerClientProvider locale={locale}> <Component {...pageProps} /> </IntlayerClientProvider> ); export default App; ``` ```jsx fileName="src/pages/_app.csx" codeFormat="commonjs"// Configuração do App com Intlayer const { IntlayerClientProvider } = require("next-intlayer");
const App = ({ Component, pageProps }) => ( <IntlayerClientProvider locale={locale}> <Component {...pageProps} /> </IntlayerClientProvider> ); module.exports = App; ```Configure getStaticPaths e getStaticProps:
No seu `[locale]/index.tsx`, defina os caminhos e as propriedades para lidar com diferentes localidades. ```tsx fileName="src/pages/[locale]/index.tsx" codeFormat="typescript"// Configuração de rotas dinâmicas import type { FC } from "react"; import type { GetStaticPaths, GetStaticProps } from "next"; import { type Locales, getConfiguration } from "intlayer";
const HomePage: FC = () =>
getStaticPaths e getStaticProps garantem que sua aplicação pré-construa as páginas necessárias para todos os idiomas no Next.js Page Router. Essa abordagem reduz o cálculo em tempo de execução e melhora a experiência do usuário. Para mais detalhes, consulte a documentação do Next.js sobre getStaticPaths e getStaticProps.
Passo 6: Declare Seu Conteúdo
Crie e gerencie suas declarações de conteúdo para armazenar traduções.
import { t, type Dictionary } from "intlayer";const homeContent = { key: "home", content: { title: t({ pt: "Bem-vindo ao Meu Site", en: "Welcome to My Website", fr: "Bienvenue sur mon site Web", es: "Bienvenido a mi sitio web", }), description: t({ pt: "Comece editando esta página.", en: "Get started by editing this page.", fr: "Commencez par éditer cette page.", es: "Comience por editar esta página.", }), },} satisfies Dictionary;export default homeContent;
Para mais informações sobre como declarar conteúdo, consulte o guia de declaração de conteúdo.
Passo 7: Utilize o Conteúdo no Seu Código
Acesse seus dicionários de conteúdo em toda a aplicação para exibir o conteúdo traduzido.
import type { FC } from "react";import { useIntlayer } from "next-intlayer";import { ComponentExample } from "@components/ComponentExample";const HomePage: FC = () => { const content = useIntlayer("home"); return ( <div> <h1>{content.title}</h1> <p>{content.description}</p> <ComponentExample /> {/* Componentes adicionais */} </div> );};// ... Resto do código, incluindo getStaticPaths e getStaticPropsexport default HomePage;
import type { FC } from "react";import { useIntlayer } from "next-intlayer";export const ComponentExample: FC = () => { const content = useIntlayer("component-example"); // Certifique-se de ter uma declaração de conteúdo correspondente return ( <div> <h2>{content.title}</h2> <p>{content.content}</p> </div> );};
Ao usar traduções em atributos string (por exemplo, alt, title, href, aria-label), chame o valor da função da seguinte forma:
jsx<img src={content.image.src.value} alt={content.image.value} />
Para saber mais sobre o hook useIntlayer, consulte a documentação.
(Opcional) Etapa 8: Internacionalizar Seus Metadados
Para internacionalizar metadados como títulos e descrições de páginas, use a função getStaticProps em conjunto com a função getTranslation do Intlayer.
import { GetStaticPaths, GetStaticProps } from "next";import { type IConfigLocales, getTranslation, Locales } from "intlayer";import { useIntlayer } from "next-intlayer";interface HomePageProps { locale: string; metadata: Metadata;}const HomePage = ({ metadata }: HomePageProps) => { // Os metadados podem ser usados no head ou em outros componentes conforme necessário return ( <div> <Head> <title>{metadata.title}</title> <meta name="description" content={metadata.description} /> </Head> {/* Conteúdo adicional */} </div> );};export const getStaticProps: GetStaticProps = async ({ params }) => { const locale = params?.locale as string; const t = <T,>(content: IConfigLocales<T>) => getTranslation(content, locale); const metadata = { title: t({ pt: "Meu Site", en: "My Website", fr: "Mon Site Web", es: "Mi Sitio Web", }), description: t({ pt: "Bem-vindo ao meu site.", en: "Welcome to my website.", fr: "Bienvenue sur mon site Web.", es: "Bienvenido a mi sitio web.", }), }; return { props: { locale, metadata, }, };};export default HomePage;// ... Resto do código incluindo getStaticPaths
(Opcional) Etapa 9: Alterar o Idioma do Seu Conteúdo
Para permitir que os usuários alterem o idioma dinamicamente, use a função setLocale fornecida pelo hook useLocale.
import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl,} from "intlayer";import { useLocalePageRouter } from "next-intlayer";import { type FC } from "react";import Link from "next/link";const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocalePageRouter(); return ( <div> <button popoverTarget="localePopover">{getLocaleName(locale)}</button> <div id="localePopover" popover="auto"> {availableLocales.map((localeItem) => ( <Link href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} key={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={(e) => { e.preventDefault(); setLocale(localeItem); }} > <span> {/* Locale - ex.: FR */} {localeItem} </span> <span> {/* Idioma no próprio Locale - ex.: Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* Idioma no Locale atual - ex.: Francés com o locale atual definido como Locales.SPANISH */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* Idioma em Inglês - ex.: French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> </Link> ))} </div> </div> );};
A API useLocalePageRouter é a mesma que useLocale. Para saber mais sobre o hook useLocale, consulte a documentação.
Referências da documentação:
(Opcional) Etapa 10: Criando um Componente de Link Localizado
Para garantir que a navegação da sua aplicação respeite a localidade atual, você pode criar um componente Link personalizado. Este componente automaticamente adiciona um prefixo aos URLs internos com o idioma atual. Por exemplo, quando um usuário que fala francês clica em um link para a página "Sobre", ele é redirecionado para /fr/about em vez de /about.
Esse comportamento é útil por várias razões:
- SEO e Experiência do Usuário: URLs localizados ajudam os motores de busca a indexar corretamente as páginas específicas de idioma e fornecem aos usuários conteúdo no idioma preferido.
- Consistência: Usando um link localizado em toda a aplicação, você garante que a navegação permaneça na localidade atual, evitando mudanças inesperadas de idioma.
- Manutenibilidade: Centralizar a lógica de localização em um único componente simplifica o gerenciamento de URLs, tornando sua base de código mais fácil de manter e expandir à medida que sua aplicação cresce.
Abaixo está a implementação de um componente Link localizado em TypeScript:
"use client";import { getLocalizedUrl } from "intlayer";import NextLink, { type LinkProps as NextLinkProps } from "next/link";import { useLocale } from "next-intlayer";import { forwardRef, PropsWithChildren, type ForwardedRef } from "react";/** * Função utilitária para verificar se um URL é externo. * Se o URL começar com http:// ou https://, ele é considerado externo. */export const checkIsExternalLink = (href?: string): boolean => /^https?:///.test(href ?? "");/** * Um componente de Link personalizado que adapta o atributo href com base na localidade atual. * Para links internos, ele usa `getLocalizedUrl` para prefixar o URL com a localidade (ex.: /fr/about). * Isso garante que a navegação permaneça no mesmo contexto de localidade. */export const Link = forwardRef< HTMLAnchorElement, PropsWithChildren<NextLinkProps>>(({ href, children, ...props }, ref: ForwardedRef<HTMLAnchorElement>) => { const { locale } = useLocale(); const isExternalLink = checkIsExternalLink(href.toString()); // Se o link for interno e um href válido for fornecido, obtenha o URL localizado. const hrefI18n: NextLinkProps["href"] = href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href; return ( <NextLink href={hrefI18n} ref={ref} {...props}> {children} </NextLink> );});Link.displayName = "Link";
Como Funciona
Detectando Links Externos:
A função auxiliar checkIsExternalLink determina se um URL é externo. Links externos permanecem inalterados porque não precisam de localização.Recuperando a Localidade Atual:
O hook useLocale fornece a localidade atual (ex.: fr para francês).Localizando o URL:
Para links internos (ou seja, não externos), getLocalizedUrl é usado para prefixar automaticamente o URL com a localidade atual. Isso significa que, se o usuário estiver em francês, passar /about como href será transformado em /fr/about.Retornando o Link:
O componente retorna um elemento <a> com o URL localizado, garantindo que a navegação seja consistente com a localidade.
Configurar TypeScript
O Intlayer utiliza a ampliação de módulos para aproveitar os benefícios do TypeScript e tornar sua base de código mais robusta.
Certifique-se de que sua configuração do TypeScript inclua os tipos gerados automaticamente.
{ // ... Suas configurações existentes do TypeScript "include": [ // ... Suas configurações existentes do TypeScript ".intlayer/**/*.ts", // Inclua os tipos gerados automaticamente ],}
Configuração do Git
Para manter seu repositório limpo e evitar o commit de arquivos gerados, é recomendado ignorar os arquivos criados pelo Intlayer.
Adicione as seguintes linhas ao seu arquivo .gitignore:
# Ignore os arquivos gerados pelo Intlayer.intlayer
Recursos Adicionais
- Documentação do Intlayer: Repositório no GitHub
- Guia do Dicionário: Dicionário
- Documentação de Configuração: Guia de Configuração
Seguindo este guia, você pode integrar efetivamente o Intlayer em sua aplicação Next.js usando o Page Router, permitindo suporte robusto e escalável à internacionalização para seus projetos web.
Avance Mais
Para ir além, você pode implementar o editor visual ou externalizar seu conteúdo usando o CMS.
Se você tiver uma ideia para melhorar esta documentação, sinta-se à vontade para contribuir enviando uma pull request no GitHub.
Link do GitHub para a documentação