Guias
Estratégia de URL
Duas formas de levar o idioma: no endereço, ou em lugar nenhum. Esta página é sobre escolher uma de propósito, porque essa escolha decide o seu SEO e mudá-la depois é caro.
As duas estratégias
| Estratégia | O que o visitante vê | Mudar de idioma é |
|---|---|---|
| No endereço | /docs em inglês, /es/docs em espanhol | Navegar para esse endereço |
| Fora do endereço | /docs em todos os idiomas | O 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.
export default {
sourceLocale: 'en',
locales: ['en', 'es', 'pt'],
routing: 'prefix-all', // only when you disagree with what it read
};| Modo | O endereço | Quando |
|---|---|---|
prefix-except-source | /docs e /es/docs | Tudo o que as pessoas encontram buscando, que é quase qualquer site público |
prefix-all | /en/docs e /es/docs | Quando nenhum idioma é o da casa e todos são convidados |
no-prefix | /docs em todos os idiomas | Atrá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.
Com o idioma no endereço ela vai para esse endereço, com a query e a âncora, e essa página já está escrita 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:
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.
O cabeçalho é metade do que um resultado de busca mostra
Uma página pode estar traduzida em tudo o que se vê e mesmo assim dizer a um motor de busca que está em inglês. O título e a descrição vivem no <head>, onde ninguém os vê na página, por isso é fácil esquecê-los. Ligue-os como qualquer outro texto: são quase tudo o que um resultado de pesquisa mostra.
<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.
Quando o endereço leva o idioma, ele manda
Assim que o idioma está no endereço, essa é a resposta e nada a sobrepõe. Alguém abre /es/pricing e recebe espanhol, mesmo que ontem tenha escolhido inglês aqui. Um endereço compartilha-se, liga-se e fica em cache; uma escolha guardada é de uma só pessoa. A outra metade importa igual: uma página sem prefixo é o seu idioma de origem, por isso quem um dia escolheu espanhol nunca encontra as suas páginas em inglês traduzidas sem aviso.
A escolha salva e o idioma do navegador continuam decidindo uma coisa, e só uma: para onde mandar quem chega sem idioma no endereço. Veja Servidor para a integração por framework.
A única diferença que não se contorna
Os motores de busca indexam endereços, não idiomas. Se o seu espanhol e o seu inglês compartilham um endereço, só um deles pode ser indexado, e nada que você faça em runtime muda isso. O hreflang é como você diz a um motor de busca que dois endereços são a mesma página em idiomas diferentes, por isso com um só endereço não há nada para ligar. A Google diz o mesmo: um URL por idioma, nem um cookie nem uma definição do navegador.
O que o Verbaly te dá, conforme você renderiza
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.
| Você renderiza | No endereço | Fora do endereço |
|---|---|---|
| No navegador, uma SPA com router de cliente | localeFromPath lê o idioma do endereço em cada mudança de rota | resolveLocale + persistLocale. Um clique nunca recarrega, e um F5 volta a ler a escolha guardada |
| Num servidor, SvelteKit, Nuxt ou Next.js | O router do seu framework é dono do segmento, o Verbaly dos catálogos | resolveRequestLocale lê o cookie em cada requisição, por isso o documento chega já traduzido. Ligado por você nas três integrações |
| No build, Astro, Eleventy ou qualquer SSG | verbaly render escreve o seu site em cada idioma, com hreflang e um sitemap | Nada faz isto bem. Serve-se um só documento a todo mundo, por isso o idioma só pode mudar depois de chegar |
Por que essa última célula está vazia em todo lugar, não só aqui
Uma hospedagem estática manda o mesmo arquivo a todos. Para mostrar outro idioma sem mudar o endereço alguma coisa tem de rodar antes de o HTML ser enviado, e num site estático não roda nada. As bibliotecas que oferecem este modo o resolvem todas com um servidor lendo 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 roda. O Verbaly não vai fingir o contrário. As suas opções, pela ordem em que as tentaríamos:
- Colocá-lo no endereço.
verbaly render, erender.redirectpara o visitante chegar ao seu idioma sem nunca ver como se decide. É o que este site faz. - Um subdomínio por idioma.
es.example.comnão leva segmento no caminho e mesmo assim tem endereço próprio, por isso a pesquisa continua funcionando. Esta é a opção que todo mundo esquece. - Reescrever no edge. A sua hospedagem pode servir o arquivo pré-renderizado de
/es/no endereço simples conforme um cookie. Funciona, e te custa: um só idioma indexado, e uma entrada de cache por valor de cookie no seu CDN. - Aceitar a troca. Serve o idioma de origem e deixa o
bindDomsubstituir o texto quando o catálogo chegar. Tudo bem por trás de um login, visível numa carga a frio.
O endereço te compra mais uma coisa. Com render.inlineCatalog, cada página leva só as mensagens que mostra, por isso quem lê uma página num idioma traduzido deixa de baixar esse idioma inteiro.
Uma coisa a saber se você faz routing no cliente: cada página leva as suas próprias mensagens, por isso o seu router tem de entregá-las ao trocar de documento, com adoptPage de virtual:verbaly. O <ClientRouter /> do Astro já vem ligado.
O prefixo chega a todos os links, incluindo os que vão escritos dentro de uma frase. Uma mensagem que nomeia um link (<docs>o guia</docs>) é tratada tal como um <a> que você escreveu. Assim, quem clica no meio do parágrafo continua no idioma dele em vez de ir parar no seu idioma de origem.
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.
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. Padrã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 seus endereços não forem idiomas, e uma rota chamada /es nunca poderá ser confundida com espanhol.
Num servidor a mesma ideia acontece um passo antes. resolveRequestLocale lê o cookie, recorre ao Accept-Language e entrega o idioma à instância que renderiza a resposta, por isso ninguém recebe nunca uma página no idioma errado. @verbaly/sveltekit, @verbaly/nuxt e @verbaly/next já fazem isto por você. switchLocale é a outra metade, no navegador: escreve o cookie que o servidor vai ler.
Mudar de ideia mais tarde
Passar de um endereço para muitos é barato: você ativa o render e cada idioma ganha o seu endereço mais o seu hreflang. Ao contrário te custa os endereços que você já publicou, e os motores de busca os guardam muito tempo, por isso redirecione em vez de apagar. Nenhuma das direções toca nas suas mensagens, nas suas keys nem nos seus catálogos: isto é uma decisão de rotas, não de tradução.