Pular para o conteúdo

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

  1. Crie um diretório para cada língua que você quer oferecer suporte. Por exemplo, en/ e fr/ 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
  2. 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.

Use coleções para conteúdo traduzido

  1. 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
  2. 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.

  3. Use rotas dinâmicas para buscar e renderizar conteúdo baseado em parâmetros lang e slug.

    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/>

    📚 Leia mais sobre roteamento dinâmico.

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.

  1. 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;
  2. 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];
    }
    }
  3. 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>
  4. 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.

  1. 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>
  2. 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

  1. 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 em fr/:

    • Diretóriosrc/
      • Diretóriopages/
        • about.astro
        • index.astro
        • Diretóriofr/
          • about.astro
          • index.astro
  2. Adicione outra linha ao arquivo src/i18n/ui.ts para ativar o recurso:

    src/i18n/ui.ts
    export const mostrarLinguaPadrao = false;
  3. 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}`
    }
    }
  4. 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>
  5. 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.

  1. Adicione mapeamento de rotas no arquivo src/i18n/ui.ts:
src/i18n/ui.ts
export const rotas = {
de: {
'services': 'leistungen',
},
fr: {
'services': 'prestations-de-service',
},
}
  1. Atualize a função usarCaminhoTraduzido no arquivo src/i18n/utils.ts para adicionar a lógica de tradução de roteamento.
src/i18n/utils.ts
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}`
}
}
  1. Crie uma função auxiliar para obter a rota, se ela existir baseada na URL atual, em src/i18n/utils.ts:
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
}
  1. 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:
src/components/SeletorLinguas.astro
---
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.