Adicione funcionalidades de i18n
Astro não tem suporte integrado a internacionalização (i18n), mas você pode construir a sua própria solução. Nesta receita, você vai aprender como usar as coleções de conteúdo e roteamento dinâmico para fornecer conteúdo em diferentes línguas.
Esse exemplo utiliza cada língua como seu próprio subcaminho, e.x. example.com/en/blog
para Inglês e example.com/fr/blog
para Francês.
Se você prefere que a língua padrão não seja visível na URL ao contrário de outras línguas, abaixo tem instruções para ocultar a língua padrão.
Receita
Configure páginas para cada língua
-
Crie um diretório para cada língua que você quer oferecer suporte. Por exemplo,
en/
efr/
se você estiver oferecendo suporte para inglês e francês:Diretóriosrc/
Diretóriopages/
Diretórioen/
- about.astro
- index.astro
Diretóriofr/
- about.astro
- index.astro
- index.astro
-
Configure
src/pages/index.astro
para redirecionar para a língua padrão.src/pages/index.astro <meta http-equiv="refresh" content="0;url=/en/" />Esta abordagem utiliza meta refresh e funcionará independentemente de como você fizer deploy do seu site. No entanto, alguns hosts estáticos também permitem que você configure redirecionamentos pelo servidor com um arquivo de configuração personalizado. Verifique a documentação da sua plataforma de deploy para mais detalhes.
Se você está utilizando um adaptador SSR, você pode usar
Astro.redirect
para redirecionar para a linguagem padrão no servidor.src/pages/index.astro ---return Astro.redirect('/en/');---
Use coleções para conteúdo traduzido
-
Crie um diretório em
src/content/
para cada tipo de conteúdo que você quer incluir e adicione subdiretórios para cada língua suportada. Por exemplo, para oferecer suporte a postagens de blog em inglês e francês:Diretóriosrc/
Diretóriocontent/
Diretórioblog/
Diretórioen/ Postagens de blog em inglês
- post-1.md
- post-2.md
Diretóriofr/ Postagens de blog em francês
- post-1.md
- post-2.md
-
Crie um arquivo
src/content/config.ts
e exporte uma coleção para cada tipo de conteúdo.src/content/config.ts import { defineCollection, z } from 'astro:content';const blogCollection = defineCollection({schema: z.object({title: z.string(),author: z.string(),date: z.date()})});export const collections = {'blog': blogCollection};📚 Leia mais sobre Coleções de Conteúdo.
-
Use rotas dinâmicas para buscar e renderizar conteúdo baseado em parâmetros
lang
eslug
.Em modo de renderização estático, use
getStaticPaths
para mapear cada entrada de conteúdo para uma página:src/pages/[lang]/blog/[...slug].astro ---import { getCollection } from 'astro:content'export async function getStaticPaths() {const paginas = await getCollection('blog')const caminhos = paginas.map(pagina => {const [lang, ...slug] = pagina.slug.split('/');return { params: { lang, slug: slug.join('/') || undefined }, props: pagina }})return caminhos;}const { lang, slug } = Astro.params;const pagina = Astro.props;const dataFormatada = pagina.data.data.toLocaleString(lang);const { Content } = await page.render();---<h1>{page.data.titulo}</h1><p>by {page.data.autor} • {dataFormatada}</p><Content/>Em modo SSR, busque a entrada solicitada diretamente:
src/pages/[lang]/blog/[...slug].astro ---import { getEntryBySlug } from 'astro:content';const { lang, slug } = Astro.params;const pagina = await getEntryBySlug('blog', `${lang}/${slug}`);if (!pagina) {return Astro.redirect('/404');}const dataFormatada = page.data.data.toLocaleString(lang);const { Content, headings } = await page.render();---<h1>{page.data.titulo}</h1><p>by {page.data.autor} • {dataFormatada}</p><Content/>📚 Leia mais sobre roteamento dinâmico.
O exemplo acima utiliza o método de formatação de data
toLocaleString()
para criar uma string legível a partir da data da página. Isso garante que a data e a hora sejam formatadas de acordo com a língua do usuário.
Traduza strings da UI
Criar dicionários de termos para traduzir as labels dos elementos de UI em todo o seu site. Isso permite que seus visitantes experimentem seu site completamente na língua deles.
-
Crie um arquivo
src/i18n/ui.ts
para armazenar suas strings de tradução:src/i18n/ui.ts export const linguas = {en: 'English',fr: 'Français',};export const linguaPadrao = 'en';export const ui = {en: {'nav.home': 'Home','nav.about': 'About','nav.twitter': 'Twitter',},fr: {'nav.home': 'Accueil','nav.about': 'À propos',},} as const; -
Crie duas funções: uma para detectar a língua da página baseado na URL atual, e outra para obter as strings de tradução para diferentes partes da UI em
src/i18n/utils.ts
:src/i18n/utils.ts import { ui, linguaPadrao } from './ui';export function pegarLangDeURL(url: URL) {const [, lang] = url.pathname.split('/');if (lang in ui) return lang as keyof typeof ui;return linguaPadrao;}export function usarTraducoes(lang: keyof typeof ui) {return function t(key: keyof typeof ui[typeof linguaPadrao]) {return ui[lang][key] || ui[linguaPadrao][key];}}No passo 1, a string
nav.twitter
não foi traduzida para o francês. Você pode não querer traduzir todos os termos, como nomes próprios ou termos comuns da indústria. A funçãouseTranslations
irá retornar o valor da língua padrão se uma chave não for traduzida. Neste exemplo, os usuários franceses também verão “Twitter” na barra de navegação. -
Importe as funções onde necessário e use-as para escolher a string de UI que corresponde a língua atual. Por exemplo, um componente de navegação pode ser assim:
src/components/Nav.astro ---import { pegarLangDeURL, usarTraducoes } from '../i18n/utils';const lang = pegarLangDeURL(Astro.url);const t = usarTraducoes(lang);---<ul><li><a href={`/${lang}/home/`}>{t('nav.home')}</a></li><li><a href={`/${lang}/about/`}>{t('nav.about')}</a></li><li><a href="https://twitter.com/astrodotbuild">{t('nav.twitter')}</a></li></ul> -
Cada página deve ter um atributo
lang
no elemento<html>
que corresponda a língua da página. Neste exemplo, um layout reutilizável extrai a língua da rota atual:src/layouts/Base.astro ---import { pegarLangDeURL } from '../i18n/utils';const lang = pegarLangDeURL(Astro.url);---<html lang={lang}><head><meta charset="utf-8" /><link rel="icon" type="image/svg+xml" href="/favicon.svg" /><meta name="viewport" content="width=device-width" /><title>Astro</title></head><body><slot /></body></html>Assim, você pode usar este layout base para garantir que as páginas usem o atributo
lang
correto automaticamente.src/pages/en/about.astro ---import Base from "../../layouts/Base.astro"---<Base><h1>About me</h1>...</Base>
Permitir que os usuários alternem entre línguas
Criar links para as diferentes línguas que você oferece suporte para que os usuários possam escolher a língua que eles querem ler seu site.
-
Crie um componente para mostrar um link para cada língua:
src/components/SeletorLinguas.astro ---import { linguas } from '../i18n/ui';---<ul>{Object.entries(linguas).map(([lang, label]) => (<li><a href={`/${lang}/`}>{label}</a></li>))}</ul> -
Adicione
<SeletorLinguas />
ao seu site para que ele seja mostrado em todas as páginas. O exemplo abaixo adiciona ele ao rodapé do site em um layout base:src/layouts/Base.astro ---import SeletorLinguas from '../components/SeletorLinguas.astro';import { pegarLangDeURL } from '../i18n/utils';const lang = pegarLangDeURL(Astro.url);---<html lang={lang}><head><meta charset="utf-8" /><link rel="icon" type="image/svg+xml" href="/favicon.svg" /><meta name="viewport" content="width=device-width" /><title>Astro</title></head><body><slot /><footer><SeletorLinguas /></footer></body></html>
Ocultar a língua padrão na URL
-
Crie um diretório para cada língua, exceto a língua padrão. Por exemplo, armazene suas páginas da língua padrão diretamente em
pages/
, e suas páginas traduzidas emfr/
:Diretóriosrc/
Diretóriopages/
- about.astro
- index.astro
Diretóriofr/
- about.astro
- index.astro
-
Adicione outra linha ao arquivo
src/i18n/ui.ts
para ativar o recurso:src/i18n/ui.ts export const mostrarLinguaPadrao = false; -
Adicione uma função ao arquivo
src/i18n/utils.ts
, para traduzir caminhos baseado na língua atual:src/i18n/utils.ts import { ui, linguaPadrao, mostrarLinguaPadrao } from './ui';export function usarCaminhoTraduzido(lang: keyof typeof ui) {return function traduzirCaminho(caminho: string, l: string = lang) {return !mostrarLinguaPadrao && l === linguaPadrao ? caminho : `/${l}${caminho}`}} -
Importe a função onde for necessário. Por exemplo, um componente
nav
pode ficar assim:src/components/Nav.astro ---import { pegarLangDeURL, usarTraducoes, usarCaminhoTraduzido } from '../i18n/utils';const lang = pegarLangDeURL(Astro.url);const t = usarTraducoes(lang);const traduzirCaminho = usarCaminhoTraduzido(lang);---<ul><li><a href={traduzirCaminho('/home/')}>{t('nav.home')}</a></li><li><a href={traduzirCaminho('/about/')}>{t('nav.about')}</a></li><li><a href="https://twitter.com/astrodotbuild">{t('nav.twitter')}</a></li></ul> -
A função também pode ser usada para traduzir caminhos para uma língua específica. Por exemplo, quando os usuários alternam entre línguas:
src/components/SeletorLinguas.astro ---import { linguas } from '../i18n/ui';---<ul>{Object.entries(linguas).map(([lang, label]) => (<li><a href={traduzirCaminho('/', lang)}>{label}</a></li>))}</ul>
Traduzir rotas
Traduzir as rotas das suas páginas para cada língua.
- Adicione mapeamento de rotas no arquivo
src/i18n/ui.ts
:
export const rotas = { de: { 'services': 'leistungen', }, fr: { 'services': 'prestations-de-service', }, }
- Atualize a função
usarCaminhoTraduzido
no arquivosrc/i18n/utils.ts
para adicionar a lógica de tradução de roteamento.
import { ui, linguaPadrao, mostrarLinguaPadrao, rotas } from './ui';
export function usarCaminhoTraduzido(lang: keyof typeof ui) { return function traduzirCaminho(caminho: string, l: string = lang) { const nomeCaminho = caminho.replaceAll('/', '') const temTraducao = linguaPadrao !== l && rotas[l] !== undefined && rotas[l][nomeCaminho] !== undefined const caminhoTraduzido = temTraducao ? '/' + rotas[l][nomeCaminho] : path
return !mostrarCaminhoTraduzido && l === linguaPadrao ? caminhoTraduzido : `/${l}${caminhoTraduzido}` }}
- Crie uma função auxiliar para obter a rota, se ela existir baseada na URL atual, em
src/i18n/utils.ts
:
import { ui, linguaPadrao, mostrarLinguaPadrao, rotas } from './ui';
export function pegarRotaDeUrl(url: URL): string | undefined { const nomeCaminho = new URL(url).pathname const partes = nomeCaminho?.split('/') const caminho = partes.pop() || partes.pop()
if (caminho === undefined) { return undefined }
const linguaAtual = pegarLangDeURL(url);
if (linguaPadrao === linguaAtual) { const rota = Object.values(rotas)[0]; return rota[caminho] !== undefined ? rota[caminho] : undefined }
const pegarChavePeloValor = (obj: Record<string, string>, valor: string): string | undefined => { return Object.keys(obj).find((chave) => obj[chave] === valor) }
const chaveRevertida = pegarChavePeloValor(rotas[linguaAtual], caminho)
if (chaveRevertida !== undefined) { return chaveRevertida }
return undefined}
- A função auxiliar pode ser usada para obter uma rota traduzida. Por exemplo, quando nenhuma rota traduzida é definida, o usuário será redirecionado para sua página inicial:
--- import { languages } from '../i18n/ui'; const rota = pegarRotaDeUrl(Astro.url); ---
<ul> {Object.entries(linguas).map(([lang, label]) => ( <li> <a href={traduzirCaminho(`/${rota ? rota : ''}`, lang)}>{label}</a> </li> ))} </ul>
Recursos
Bibliotecas da comunidade
- astro-i18next — Uma integração Astro para i18next incluindo alguns componentes utilitários.
- astro-i18n — Uma biblioteca de internacionalização focada em TypeScript para Astro.
- astro-i18n-aut — Uma integração Astro para i18n que suporta
defaultLocale
sem geração de páginas. A integração é agnóstica a adaptadores e frameworks de UI.