Features Overview
A scrollable showcase. Each section has the smallest example that captures the feature, then a link to the full guide. Most demos use the framework-agnostic @comvi/core; tag rendering, reactivity, and SSR show one framework binding where it matters.
All examples below assume this minimal instance. Translation values are added inline per section to keep each demo self-contained.
import { createI18n } from '@comvi/core';
const i18n = createI18n({ locale: 'en', fallbackLocale: 'en', translation: { en: { /* values shown per section below */ }, },});
await i18n.init();Translation Function
Section titled “Translation Function”Look up a translation by key. Pass {name} placeholders to interpolate runtime parameters.
{ "greeting": "Hello, {name}!" }i18n.t('greeting', { name: 'Alice' });// → "Hello, Alice!"
i18n.t('missing.key', { fallback: 'Hi!' });// → "Hi!"Pluralization & ICU
Section titled “Pluralization & ICU”ICU plural, select, and selectordinal work for every language — including ones with complex rules like Ukrainian, Polish, and Arabic. Backed by Intl.PluralRules.
{ "cart.items": "{count, plural, =0 {Cart is empty} one {# item} other {# items}}"}i18n.t('cart.items', { count: 0 }); // → "Cart is empty"i18n.t('cart.items', { count: 1 }); // → "1 item"i18n.t('cart.items', { count: 5 }); // → "5 items"Tag Interpolation
Section titled “Tag Interpolation”Translators write tags inside the sentence; your code maps them to real components. Word order stays in the translator’s hands — no string concatenation in your UI.
{ "consent": "I agree to the <tos>Terms of Service</tos>." }import { T } from '@comvi/react';
<T i18nKey="consent" components={{ tos: <a href="/terms" /> }}/>// → "I agree to the <a href="/terms">Terms of Service</a>."Namespaces
Section titled “Namespaces”Split keys into logical groups — per page, per feature. Namespaces load on demand: only the strings the user actually needs.
{ "title": "Admin Dashboard" }await i18n.addActiveNamespace('admin');
i18n.t('title', { ns: 'admin' }); // → "Admin Dashboard"Language Switching
Section titled “Language Switching”Change the active locale at runtime. Translations for the new locale load automatically.
await i18n.setLocaleAsync('de');
i18n.t('greeting', { name: 'Alice' });// → "Hallo, Alice!"setLocaleAsync() waits for namespace loading; i18n.locale = 'de' is fire-and-forget.
Reactive Translations
Section titled “Reactive Translations”Framework bindings expose locale, loading state, and the translation function as reactive primitives. Components re-render automatically when the locale changes or new translations load — no manual subscriptions.
import { useI18n } from '@comvi/react';
function Greeting() { const { t, locale, setLocale } = useI18n(); return ( <> <p>{t('greeting', { name: 'Alice' })}</p> <button onClick={() => setLocale('de')}>Deutsch</button> </> );}The same pattern works in Vue (refs), Solid (Accessors), and Svelte (Readable stores).
Loading Translations
Section titled “Loading Translations”Plug in a loader for runtime fetch (CDN), keep them static at build time, or write a custom one. With the Fetch Loader, translators ship updates without redeploying the app.
import { FetchLoader } from '@comvi/plugin-fetch-loader';
createI18n({ locale: 'en' }) .use(FetchLoader({ cdnUrl: 'https://cdn.comvi.io/your-distribution-id', }));The Fetch Loader respects HTTP cache headers and deduplicates concurrent requests for the same locale/namespace.
Formatting
Section titled “Formatting”Locale-aware formatting for numbers, dates, currency, and relative time — Intl.* under the hood. Switch locale and the formatters follow automatically.
i18n.formatNumber(1234567.89); // → "1,234,567.89"i18n.formatCurrency(1234.5, 'USD'); // → "$1,234.50"i18n.formatDate(new Date(), { dateStyle: 'long' }); // → "May 1, 2026"i18n.formatRelativeTime(-3, 'day'); // → "3 days ago"Type Safety
Section titled “Type Safety”Generated types augment @comvi/core’s TranslationKeys interface. Typos and missing parameters become compile-time errors.
declare module '@comvi/core' { interface TranslationKeys { 'greeting': { name: string }; }}
i18n.t('greeting', { name: 'Alice' }); // ✅i18n.t('greting', { name: 'Alice' }); // ❌ TS2345: not assignablei18n.t('greeting'); // ❌ missing param 'name'The Comvi CLI (comvi typegen) generates this declaration automatically from your translations.
Error Handling
Section titled “Error Handling”Hooks for missing keys, load failures, and broader runtime errors. Comvi runs in resilient mode by default — errors are reported, not thrown.
createI18n({ locale: 'en', onMissingKey: ({ key, locale, namespace }) => { console.warn(`Missing: ${key} (${locale}/${namespace})`); return `[!${key}]`; // final fallback after locales are checked }, onError: (error, ctx) => { Sentry.captureException(error, { extra: ctx }); },});Server-Side Rendering
Section titled “Server-Side Rendering”Pre-load translations on the server, render real text, hydrate cleanly on the client. Built-in helpers for Next.js and Nuxt; React/Vue can pass SSR state explicitly.
import { setRequestLocale, loadTranslations } from '@comvi/next/server';
export default async function Layout({ params }) { const { locale } = await params; setRequestLocale(locale); await loadTranslations(locale); return /* ...children with <I18nProvider>... */;}No FOUC, no hydration mismatch.