@comvi/vue API Reference
@comvi/vue provides Vue 3 composables, a <T> component for safe rich-text interpolation, and a Vue plugin for global access. It builds on top of @comvi/core and re-exports all core APIs.
createI18n(options)
Section titled “createI18n(options)”Creates a Vue i18n instance. Returns a VueI18n instance that is both a standard i18n object and a Vue plugin compatible with app.use().
import { createI18n } from '@comvi/vue';
const i18n = createI18n({ locale: 'en', fallbackLocale: 'en',});Options
Section titled “Options”Accepts all core I18nOptions plus:
| Option | Type | Default | Description |
|---|---|---|---|
ssrLanguage | string | — | Explicit hydration locale for SSR (prevents mismatch) |
The returned instance supports chaining:
const i18n = createI18n({ locale: 'en' }) .use(FetchLoader({ cdnUrl: '...' })) .use(LocaleDetector({ order: ['cookie', 'navigator'] }));Plugin Installation
Section titled “Plugin Installation”Install the i18n instance as a Vue plugin with app.use(i18n) to provide useI18n() composable and $t, $i18n globals.
import { createApp } from 'vue';import { i18n } from './i18n';import App from './App.vue';
const app = createApp(App);app.use(i18n);app.mount('#app');app.use(i18n) auto-calls init() if !isInitialized && !isInitializing.
After installation, every component has access to $t() and $i18n (Options API) and useI18n() (Composition API).
useI18n(ns?)
Section titled “useI18n(ns?)”The primary composable for translating strings and reading i18n state. Reactive state (locale, isLoading, isInitializing, dir, translationCache) is returned as Vue refs/computeds; the rest are methods bound to the i18n instance.
<script setup lang="ts">import { useI18n } from '@comvi/vue';
const { t, locale, setLocale, isLoading, isInitializing } = useI18n();</script>
<template> <div v-if="isLoading">Loading translations...</div> <div v-else> <h1>{{ t('hello.world') }}</h1> <p>{{ t('greeting', { name: 'Alice' }) }}</p> </div></template>Signature
Section titled “Signature”useI18n(ns?: string)Pass an optional namespace string to load and scope all t() calls to that namespace.
Returned Values
Section titled “Returned Values”interface UseI18nReturn { t: TypedTranslationFunction; // returns string tRaw: RawTranslationFunction; // returns TranslationResult locale: Ref<string>; setLocale(locale: string): Promise<void>; translationCache: Readonly<Ref<Readonly<ReadonlyMap<string, FlattenedTranslations>>>>; isLoading: Readonly<Ref<boolean>>; isInitializing: Readonly<Ref<boolean>>; dir: ComputedRef<"ltr" | "rtl">;
addTranslations(translations: Record<string, Record<string, TranslationValue>>): void; addActiveNamespace(namespace: string): Promise<void>; setFallbackLocale(locales: string | string[]): void; onMissingKey( cb: (key: string, locale: string, namespace: string) => TranslationResult | void, ): () => void; onLoadError(cb: (locale: string, namespace: string, error: Error) => void): () => void; clearTranslations(locale?: string, namespace?: string): void; reloadTranslations(locale?: string, namespace?: string): Promise<void>; hasLocale(locale: string, namespace?: string): boolean; hasTranslation(key: string, locale?: string, namespace?: string, checkFallbacks?: boolean): boolean; getLoadedLocales(): string[]; getActiveNamespaces(): string[]; getDefaultNamespace(): string; on<E extends I18nEvent>(event: E, cb: (payload: I18nEventData[E]) => void): () => void; reportError(error: unknown, context?: ErrorReportContext): void; formatNumber(value: number, options?: Intl.NumberFormatOptions): string; formatDate(value: Date | number, options?: Intl.DateTimeFormatOptions): string; formatCurrency(value: number, currency: string, options?: Intl.NumberFormatOptions): string; formatRelativeTime( value: number, unit: Intl.RelativeTimeFormatUnit, options?: Intl.RelativeTimeFormatOptions, ): string; destroy(): void;}t() returns a plain string. tRaw() returns TranslationResult (string or array of strings/VirtualNodes) for advanced renderers.
Key properties:
localeis a reactive ref; setting.valuetriggers language switch (fire-and-forget, usesetLocale()to await)setLocale()is asynchronous and resolves after translations are loadedisLoading,isInitializing, andtranslationCacheare readonly refsdiris a computed ref- All pass-through methods mirror the i18n instance
Changing Language
Section titled “Changing Language”You can set locale.value directly or call setLocale(). Both load translations first and then switch — the only difference is that setLocale() returns a promise you can await:
<script setup lang="ts">import { useI18n } from '@comvi/vue';
const { locale, setLocale } = useI18n();
// Option 1: Direct assignment (fire-and-forget)function switchDirect(lang: string) { locale.value = lang;}
// Option 2: Async — same behavior, but you can await the resultasync function switchAsync(lang: string) { await setLocale(lang); // Translations are guaranteed to be loaded here}</script>Namespace Scoping
Section titled “Namespace Scoping”Pass a namespace to scope all t() calls within a component:
<script setup lang="ts">import { useI18n } from '@comvi/vue';
const { t } = useI18n('dashboard');</script>
<template> <!-- Resolves keys from the 'dashboard' namespace --> <h1>{{ t('page.title') }}</h1></template><T> Component
Section titled “<T> Component”The <T> component renders translations that contain rich content (HTML tags, Vue components, or links) safely, without v-html. It uses named slots for tag interpolation.
import { T } from '@comvi/vue';interface TProps { i18nKey: string; params?: Record<string, unknown>; ns?: string; locale?: string; fallback?: string; components?: { [tag: string]: string | Component | { component: Component; props?: object }; }}i18nKey— requiredcomponents— map of tag names to Vue components/HTML tags. Thecomponentsprop takes precedence over slots when both define the same tag.
Basic Usage
Section titled “Basic Usage”<template> <!-- Translation: "Hello, {name}!" --> <T i18n-key="greeting" :params="{ name: 'Alice' }" /></template>Rich Text with Slots
Section titled “Rich Text with Slots”Use named slots to replace tagged sections in translation values with Vue components or elements:
<template> <!-- Translation: "Read our <link>terms of service</link>" --> <T i18n-key="legal.tos"> <template #link="{ children }"> <RouterLink to="/terms">{{ children }}</RouterLink> </template> </T></template><template> <!-- Translation: "This is <bold>important</bold> and <italic>urgent</italic>" --> <T i18n-key="notice"> <template #bold="{ children }"> <strong>{{ children }}</strong> </template> <template #italic="{ children }"> <em>{{ children }}</em> </template> </T></template>Rich Text with Components Prop
Section titled “Rich Text with Components Prop”As an alternative to slots, use the components prop. This is useful when you want to reuse the same handlers across many <T> calls or configure handlers at runtime. String handlers, such as bold: 'strong', render as plain HTML tags without instantiating a Vue component:
<template> <T i18n-key="legal.tos" :components="{ link: { component: 'a', props: { href: '/terms' } }, bold: 'strong', }" /></template>I18N_INJECTION_KEY
Section titled “I18N_INJECTION_KEY”The Vue injection key used internally by app.use(i18n) to provide the i18n instance through Vue’s dependency injection system. You only need this if you are manually providing the instance with provide/inject instead of using the plugin.
import { I18N_INJECTION_KEY } from '@comvi/vue';import { provide, inject } from 'vue';
// Provide manually (rare — use app.use(i18n) instead)provide(I18N_INJECTION_KEY, i18nInstance);
// Inject manuallyconst i18n = inject(I18N_INJECTION_KEY);Options API
Section titled “Options API”When the plugin is installed, two global properties are available in all components:
$t(key, params?)— translate a key to a string$tRaw(key, params?)— translate a key to a rawTranslationResult$i18n— the i18n instance
<template> <h1>{{ $t('hello.world') }}</h1> <p>Language: {{ $i18n.locale }}</p></template>Re-exports from @comvi/core
Section titled “Re-exports from @comvi/core”@comvi/vue re-exports everything from @comvi/core for convenience. You do not need to install @comvi/core separately:
createI18n(Vue-enhanced version)- All event types
- All plugin types (
I18nPlugin,I18nPluginFactory) - All type utilities (
I18nInstance,I18nEvent,I18nEventData, etc.)
See the @comvi/core API Reference for the full list.