Ir para o conteúdo

Guias

Estratégia de URL

Duas formas de levar o idioma: no endereço, ou em lado nenhum. Esta página é sobre escolher uma de propósito, porque essa escolha decide o teu SEO e mudá-la depois é caro.

As duas estratégias

EstratégiaO que o visitante vêMudar de idioma é
No endereço/docs em inglês, /es/docs em espanholNavegar para esse endereço
Fora do endereço/docs em todos os idiomasO texto a mudar onde está

O Verbaly aceita as duas. Este site coloca o idioma no endereço em todas as páginas, porque à documentação se chega pela busca. Um app atrás de um login é o outro caso: troca de idioma com uma chamada e sem navegar, a partir de um único endereço. A estratégia é ditada pela superfície, não pelo seu gosto.

Dê um nome ao modo

Normalmente você não escreve nada. O Verbaly lê a sua montagem: se você constrói uma versão do seu site por idioma tem endereços por idioma, e se não, um único endereço serve para todos. Só diz em voz alta para discordar.

verbaly.config.mjs
export default {
  sourceLocale: 'en',
  locales: ['en', 'es', 'pt'],
  routing: 'prefix-all', // only when you disagree with what it read
};
ModoO endereçoQuando
prefix-except-source/docs e /es/docsTudo o que as pessoas encontram buscando, que é quase qualquer site público
prefix-all/en/docs e /es/docsQuando nenhum idioma é o da casa e todos são convidados
no-prefix/docs em todos os idiomasAtrás de um login, onde ninguém chega de um resultado de busca

Trocar de idioma é uma linha, e é a mesma linha em todos os modos. Importe-a de virtual:verbaly, onde ela já conhece os seus idiomas, a sua fonte e o seu modo.

import { switchLocale } from 'virtual:verbaly';

await switchLocale('es');

Com o idioma no endereço ela vai para esse endereço, que já está escrito em espanhol, então não há espera nem piscada. Sem ele, o texto muda onde está e o endereço não se move. Nos dois casos ela lembra a escolha e ajusta o idioma da página. Dê a ela o router do seu framework e o seu aplicativo sobrevive à troca:

await switchLocale('es', { navigate: (path) => router.push(path) });

npx verbaly doctor diz em que modo você está e se leu isso da sua configuração ou deduziu, para que um modo que ninguém escreveu não pareça uma decisão que alguém tomou. Também avisa quando a sua configuração pede duas coisas que não podem ser verdade ao mesmo tempo.

Uma página pode estar traduzida em tudo o que um visitante olha e ainda assim dizer a um buscador que está em inglês, porque o título e a descrição moram no <head> e ninguém os lê na página. Essa é quase toda a razão de dar a um idioma o seu próprio endereço, então faça o bind deles como de todo o resto.

head.html
<title data-verbaly="page.title">URL strategy</title>
<meta name="description" content="…" data-verbaly-attr='{"content":"page.desc"}'>

verbaly render preenche eles por idioma como o resto da página, e conta as páginas cujo título nunca muda para que você saiba uma vez e não por um resultado de busca. Nunca derruba um build: o nome de um produto pode não se traduzir.

A única diferença que não se contorna

Um motor de busca indexa endereços, não idiomas. Se o teu espanhol e o teu inglês vivem no mesmo endereço, só um é indexado, e não há truque de runtime que mude isso: as anotações hreflang existem precisamente para ligar endereços diferentes, por isso sem eles não há nada para ligar. A própria orientação da Google é usar URLs diferentes por idioma em vez de cookies ou definições do navegador.

O que o Verbaly te dá, conforme renderizas

Manter o idioma estável entre um clique e um F5 é um problema diferente conforme quem constrói o HTML. Estes são os três casos e o que cada um pede.

RenderizasNo endereçoFora do endereço
No navegador, uma SPA com router de clientelocaleFromPath lê o idioma do endereço em cada mudança de rotaresolveLocale + persistLocale. Um clique nunca recarrega, e um F5 volta a ler a escolha guardada
Num servidor, SvelteKit, Nuxt ou Next.jsO router do teu framework é dono do segmento, o Verbaly dos catálogosresolveRequestLocale lê o cookie em cada pedido, por isso o documento chega já traduzido. Ligado por ti nas três integrações
No build, Astro, Eleventy ou qualquer SSGverbaly render escreve o teu site em cada idioma, com hreflang e um sitemapNada faz isto bem. Serve-se um só documento a toda a gente, por isso o idioma só pode mudar depois de chegar

Porque essa última célula está vazia em todo o lado, não só aqui

Um alojamento estático manda o mesmo ficheiro a todos. Para mostrar outro idioma sem mudar o endereço alguma coisa tem de correr antes de o HTML ser enviado, e num site estático não corre nada. As bibliotecas que oferecem este modo resolvem-no todas com um servidor a ler um cookie: o next-intl reescreve no seu middleware, e diz claramente que com o export estático do Next.js esse middleware não corre. O Verbaly não vai fingir o contrário. As tuas opções, pela ordem em que as tentaríamos:

Ficar com um só endereço, na prática

No navegador são duas chamadas. resolveLocale escolhe o idioma de quem chega sem um endereço de onde o ler, e persistLocale lembra a mudança para que o F5 seguinte concorde.

src/i18n.ts
import { createVerbaly, persistLocale, resolveLocale } from 'verbaly';

const supported = ['en', 'es', 'pt'];

export const i18n = createVerbaly({
  locale: resolveLocale({ supported, path: false }),  // no language in the address
  fallback: 'en',
  loaders: { es: () => import('./locales/es.json') },
});

export async function switchTo(locale) {
  await i18n.loadLocale(locale);  // catalog first, so the text never flashes
  i18n.setLocale(locale);
  persistLocale(locale);         // storage + <html lang> + <html dir>
}

O que convém saber é path: false. Por omissão o resolveLocale lê o primeiro segmento do endereço antes de tudo, porque num site que põe lá o idioma o endereço é a única fonte que não pode contradizer a página. Desliga-o quando os teus endereços não forem idiomas, e uma rota chamada /es nunca poderá ser confundida com espanhol.

Num servidor a mesma ideia move-se um passo antes: o resolveRequestLocale lê o cookie, cai no Accept-Language e entrega o locale à instância que renderiza a resposta, por isso o visitante nunca recebe um documento no idioma errado. O @verbaly/sveltekit, o @verbaly/nuxt e o @verbaly/next já o fazem; o switchLocale é a metade do cliente e escreve o cookie que o servidor vai ler.

// the same decision, made before the html exists
const locale = resolveRequestLocale({ supported, cookie, header });

Mudar de ideias mais tarde

Passar de um endereço para muitos é barato: ativas o render e cada idioma ganha o seu endereço mais o seu hreflang. Ao contrário custa-te os endereços que já publicaste, e os motores de busca guardam-nos muito tempo, por isso redireciona em vez de apagar. Nenhuma das direções toca nas tuas mensagens, nas tuas keys nem nos teus catálogos: isto é uma decisão de rotas, não de tradução.

Copiado para a área de transferência