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:

Instalação

Instale o pacote com o seu gerenciador de pacotes preferido.

 pnpm add @verbaly/svelte

Setup e stores

+layout.svelte · Inbox.svelte
<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>

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.

Inbox.svelte
<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):

Title.svelte
<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 }} />

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.

O SvelteKit precisa do pacote de SSR (@verbaly/sveltekit) junto aos bindings do Svelte:

 pnpm add verbaly @verbaly/sveltekit @verbaly/svelte @verbaly/vite

Conecte tudo

Três fios no servidor, um no cliente. Primeiro o plugin do Vite e o placeholder de lang:

vite.config.ts · src/app.html
// 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 · src/app.d.ts
// 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:

src/routes/+layout.server.ts · +layout.ts · +layout.svelte
// +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:

LangPicker.svelte
<script>
  import { switchLocale } from '@verbaly/sveltekit';
  import { useVerbaly } from '@verbaly/svelte';

  const verbaly = useVerbaly();
</script>

<button onclick={() => switchLocale(verbaly, 'es')}>Español</button>
Copiado para a área de transferência