Ir para o conteúdo

Início

Migrar para o Verbaly

Sair de outra biblioteca de i18n é sobretudo mecânico, e não é preciso fazê-lo de uma vez: os dois runtimes convivem enquanto você vai arquivo a arquivo. As três seções a seguir à primeira valem venha de onde vier; a primeira é para o i18next, que é de onde chega quase todo mundo.

Você vem do i18next: o que equivale a quê

O modelo mental se transfere um a um, e a única coisa que muda é a sintaxe:

i18nextVerbaly
i18next.init({ … })npx verbaly init + um plugin de build
t('inbox.title')t('inbox.title'): a mesma chamada, com as keys já tipadas
{{name}}{name}
messages_one / messages_other{count | one: … | other: # …}: opcional, as keys com sufixo continuam funcionando tal como estão
format: 'currency' (interpolação){price:currency/EUR} (Intl nativo)
i18next-browser-languagedetectorresolveLocale() + persistLocale()
i18next-http-backend (lazy load)per-locale code-splitting, built into the plugin
useTranslation() (react-i18next)useT() (@verbaly/react)
Trans componentTrans component: values / components map over
i18next.changeLanguage('es')await setLocale('es')
saveMissing, runtime fallbacksnpx verbaly check: CI fails instead

Fique com os seus catálogos: eles entram tal como estão

Os seus catálogos entram sem mudar de forma. Os grupos aninhados continuam aninhados, _one e _other continuam funcionando como as keys que são, e um namespace com dois pontos continua sendo uma key. Uma só coisa tem de mudar, e o migrate a faz: {{name}} passa a {name}, e uma chave que o i18next mostrava como texto é duplicada, porque uma chave duplicada é como o Verbaly escreve uma chave literal.

npx verbaly migrate             # what it would port
npx verbaly migrate --write     # apply it

Primeiro reporta, reescreve só as chaves, e lista o que não vai adivinhar para que você decida. Isto é o que faz ao arquivo:

i18nextlocales/en.json
Verbalylocales/en.json
{
{
"inbox": { "title": "Inbox" },
"inbox": { "title": "Inbox" },
"messages_one": "one message",
"messages_one": "one message",
"messages_other": "{{count}} messages"
"messages_other": "{count} messages"
}
}

Duas melhorias que você pode deixar para depois, e nenhuma é precisa para funcionar. Juntar _one e _other numa só mensagem com variantes ({count | one: … | other: # …}) é o que te dá a seleção automática de plural, e o # pinta o número já localizado, sem um formattedCount à parte. A segunda é menor: os pontos são uma convenção de nomes, não um formato. Uma chave se lê igual se o seu arquivo a escreve como "inbox.title" ou a coloca como title dentro de um grupo inbox.

Troque o runtime

As keys existentes continuam funcionando via t('key', params), então os componentes migrados quase não mudam. Em React:

react-i18next
@verbaly/react
import { useTranslation } from 'react-i18next';
import { useT } from '@verbaly/react';
const { t } = useTranslation();
const t = useT();
t('inbox.title');
t('inbox.title');
t('messages', { count });
t('messages', { count }); // params now typed

Se os seus componentes chamam um hook próprio, como um useTranslate em volta do useTranslation, mantenha-o e faça-o devolver useT(): nada do que o chama muda. Um tipo de chave construído a partir do seu JSON, como um NestedKeyOf, também lista os caminhos dos grupos, então transforme-o em VerbalyKey de virtual:verbaly. Para esperar o idioma do visitante antes da primeira pintura, como fazia um limite de Suspense, renderize dentro de setLocale(locale).then(…): um await de nível superior na sua entrada parte o bundle em muitos chunks.

O bundle nota. Uma app React com i18next e react-i18next embarca cerca de 23 KB de runtime; a mesma app com o Verbaly embarca cerca de 4. Sem framework são 13,6 contra 3,3. Os quatro números são gzip e estão medidos, não estimados.

Medido no Memos, um app de código aberto em 46 idiomas: 20 arquivos alterados à mão, o build e os testes como antes, e cerca de 11 KB a menos para cada visitante na primeira carga.

O texto novo pula a cerimônia de keys: escreva como tagged template e deixe o compilador extrair, ou mantenha ids legíveis com t.id. Os adapters de Vue e Svelte seguem o mesmo padrão, e páginas de HTML puro podem fazer bind com data-verbaly.

src/app.tsx
t`Hola ${name}`;                 // key + types generated
t.id('inbox.title')`Inbox`;      // readable id, i18next-style

Vindo sem i18n nenhum? Deixe o wrap fazer a parte chata

Se seu app tem texto hardcoded em vez de uma biblioteca de i18n, npx verbaly wrap escaneia seu JSX, encontra as strings visíveis ao usuário e as envolve em t`…` por você. Ele só reporta até você passar --write, e o que for ambíguo (como uma frase misturada com markup) é listado para você envolver à mão em vez de adivinhado.

npx verbaly wrap
  1. would wrap 37 texts in 12 files (report only, use --write to apply)
  2. src/App.tsx:12 "Welcome back"
  3. src/Nav.tsx:8 aria-label → "Open menu"
npx verbaly wrap --write   # then: add t to scope and run npx verbaly extract

Detecção de idioma e carga lazy

O plugin detector e o backend HTTP desaparecem. resolveLocale lê o storage → navigator.languages → fallback (SSR-safe, com narrowing BCP-47), persistLocale guarda a escolha e sincroniza <html lang>, e setLocale carrega o chunk daquele idioma sob demanda:

src/main.ts
import { resolveLocale, persistLocale } from 'verbaly';
import { setLocale, getLocale } from 'virtual:verbaly';

await setLocale(resolveLocale({ supported: ['en', 'es', 'pt'] }));
persistLocale(getLocale());

Migre incrementalmente

Não precisa de big-bang: o runtime do Verbaly pesa ~3 KB, então as duas bibliotecas podem conviver enquanto você migra uma página ou namespace por vez. Quando os catálogos estiverem convertidos, dê ao i18next interpolation: { prefix: '{', suffix: '}' } para que ele também os leia. Uma ordem pragmática:

  1. Rode os dois lado a lado

    npx verbaly init e o plugin de build, então o toolchain roda ao lado do i18next desde o dia um. Ele aponta o config para os catálogos que você já tem, estejam onde estiverem.

  2. Passe os catálogos

    npx verbaly migrate --write. Transforma {{name}} em {name}, duplica uma chave que o i18next mostrava como texto para que continue texto, e lembra quais idiomas converteu, então rodá-lo de novo é seguro.

  3. Troque os hooks página por página

    Substitua useTranslation por useT e apague cada namespace do i18next quando esvaziar.

  4. Verifique no CI

    npx verbaly check no CI, e npx verbaly pseudo para caçar strings hardcoded que a migração deixou passar.

↑↓para navegarEnterpara abrir
Copiado para a área de transferência