Framework
Svelte
O pacote oficial de Svelte 5 para Verbaly. Stores idiomáticos sobre o mesmo core reativo, factories de stores para uso no nível do app, e um componente <Trans> para rich text.
O que você pode fazer:
- Traduza com stores:
$tre-renderiza a cada troca de idioma, sem fiação - Vincule um seletor de idioma em uma linha:
bind:valueno store do locale simplesmente funciona - Use contexto ou factories de stores, com ou sem árvore de componentes
- Mapeie uma tag de uma mensagem para seu próprio componente: <Trans> ganha a prop components na 0.23.0
Instalação
Instale o pacote com o seu gerenciador de pacotes preferido.
pnpm add @verbaly/svelteSetup e stores
<script>
// root component / layout:
import { provideVerbaly } from '@verbaly/svelte';
import { verbaly } from 'virtual:verbaly';
provideVerbaly(verbaly);
</script>
<script>
// any child component:
import { useT, useLocale } from '@verbaly/svelte';
const t = useT();
const locale = useLocale(); // writable store
</script>
<p>{$t('inbox', { count: 3 })}</p>
<select bind:value={$locale}>…</select>- Stores idiomáticos:
$tre-renderiza a cada troca de idioma;bind:value={$locale}num select funciona direto. - Sem árvore de componentes?
tStore(instance)/localeStore(instance)constroem os mesmos stores sem context, como singletons no nível do app. - Rich text: o interpretador do DOM do core funciona em qualquer app Svelte via
data-verbaly-rich+bindDom(ver HTML puro → Rich text).
Escreva o texto no lugar
Desde 0.20.0 o compilador também lê seus arquivos .svelte: escreva o texto fonte com o tag do store, no markup ou no script, e ele é extraído, ganha sua chave e seus tipos ao salvar. Sem inventar chaves, sem tocar em catálogos.
<h1>{$t`Hola ${name}, tienes ${count} mensajes`}</h1>
<!-- extracted on save; the build rewrites it to: -->
<h1>{$t('x7Ka9q2f', { name, count })}</h1>Prefere chaves legíveis? $t.id('inbox.title') antes do template extrai sob o seu id em vez de um hash do conteúdo.
Rich text com <Trans>
Desde 0.10.0 o Svelte também tem componente real: importe do subpath Trans.svelte (componente cru, compilado pelo seu bundler):
<script>
import Trans from '@verbaly/svelte/Trans.svelte';
import DocsLink from './DocsLink.svelte';
</script>
<Trans id='home.title' />
<Trans id='greet' values={{ name: 'Aron' }} />
<!-- message: 'Read the <docs>guide</docs>' → your component wraps the tag content -->
<Trans id='cta' components={{ docs: DocsLink }} />- Tags da mensagem (
The <em>build</em> gate) renderizam como elementos reais contra a mesma whitelist phrasing dodata-verbaly-rich. Tags desconhecidas se desfazem em texto inerte,richTagssobrescreve. - Usa a instância do
provideVerbaly; passeinstance={verbaly}explícito quando não há contexto. Re-renderiza a cada troca de locale. - Links nomeados (
0.11.0): a proplinksrenderiza tags nomeadas como elementos<a>reais, com hrefs do seu código, nunca das mensagens;javascript:bloqueado. - Seus próprios componentes (
0.23.0): a propcomponentsmapeia uma tag para um componente Svelte que recebe o conteúdo da tag como children, e vence links e whitelist. Exige Svelte 5; no Svelte 4 fique na0.22.0.
SvelteKit
As páginas renderizadas no servidor chegam já traduzidas no idioma do visitante, e o cliente hidrata com o mesmo locale e o mesmo catálogo, sem flash de texto sem tradução nem mismatch de hidratação.
- Cada página é renderizada no idioma do visitante, escolhido a cada request a partir do cookie ou do header
Accept-Language - Sem flash de texto sem tradução: o HTML que o servidor envia e a página já hidratada são idênticos, catálogo incluído
- Cada request tem sua própria instância, então dois visitantes simultâneos nunca veem o idioma um do outro
- Um seletor de idioma em uma chamada:
switchLocalecarrega o catálogo e persiste a escolha para o próximo render do servidor
O SvelteKit precisa do pacote de SSR (@verbaly/sveltekit) junto aos bindings do Svelte:
pnpm add verbaly @verbaly/sveltekit @verbaly/svelte @verbaly/viteConecte tudo
Três fios no servidor, um no cliente. Primeiro o plugin do Vite e o placeholder de lang:
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import verbaly from '@verbaly/vite';
export default { plugins: [verbaly(), sveltekit()] };
<!-- src/app.html -->
<html lang="%verbaly.lang%">O hook do servidor resolve o locale por request (cookie, depois Accept-Language, depois seu fallback) e preenche o placeholder:
// src/hooks.server.ts
import { verbalyHandle } from '@verbaly/sveltekit';
import { locales } from 'virtual:verbaly';
export const handle = verbalyHandle({ locales });
// src/app.d.ts
declare namespace App {
interface Locals { verbalyLocale: string }
}Entregue o locale ao cliente e construa uma instância por render com o catálogo aguardado, a garantia sem flash:
// +layout.server.ts
export const load = ({ locals }) => ({ locale: locals.verbalyLocale });
// +layout.ts
import { createRequestInstance } from 'virtual:verbaly';
export const load = async ({ data }) => ({
...data,
verbaly: await createRequestInstance(data.locale), // catalog ready BEFORE render
});
<!-- +layout.svelte -->
<script>
import { provideVerbaly } from '@verbaly/svelte';
let { data, children } = $props();
provideVerbaly(data.verbaly);
</script>
{@render children()}Daqui em diante é @verbaly/svelte normal: os stores useT() / useLocale() e o Trans.svelte funcionam sem mudanças em cada componente.
Trocar de idioma
switchLocale carrega o catálogo primeiro, troca ao vivo e grava o cookie que o hook do servidor lê, então o próximo request SSR já corresponde:
<script>
import { switchLocale } from '@verbaly/sveltekit';
import { useVerbaly } from '@verbaly/svelte';
const verbaly = useVerbaly();
</script>
<button onclick={() => switchLocale(verbaly, 'es')}>Español</button>- O cookie padrão é
verbaly-locale(a mesma identidade da key de storage do core);cookie: falseem qualquer um dos lados o desativa, paraAccept-Languagepuro. fallbacké por padrão seu primeiro locale; a negociação entende q-values e estreita regiões (es-PEcasa comes).- Sem dependência do próprio SvelteKit: o hook é tipado estruturalmente e continua compatível ao longo do Kit 2.x.