Skip to content
fluenti

Translating Content

Fluenti offers multiple ways to translate content, all processed at compile time for zero runtime parsing overhead. Choose the right API for each situation:

PriorityAPIWhereFramework
1v-t directiveVue templatesVue only
2t`…` tagged template<script setup> / JSX / JS modulesVue, React, Solid
3<Trans> / <Plural> / <Select>Templates (all frameworks)All
4msg tagged templateOutside components (routes, stores)All
5t() function callFallbackAll

The v-t directive is a compile-time nodeTransform — it rewrites your template during Vue’s SFC compilation, producing zero runtime overhead:

<template>
<h1 v-t>Welcome back, {{ name }}!</h1>
<p v-t>Read the <a href="/terms">terms</a> and <strong>conditions</strong></p>
<img v-t.alt src="/hero.jpg" alt="Welcome banner" />
</template>

For the full v-t reference (interpolation, explicit IDs, pluralization, attributes), see v-t Directive.

The t() function is available in all frameworks. It looks up messages from the compiled catalog by hash:

<script setup>
import { useI18n } from '@fluenti/vue'
const { t } = useI18n()
</script>
<template>
<p>{{ t('Welcome to Fluenti') }}</p>
<p>{{ t('Hello, {name}!', { name: userName }) }}</p>
</template>

The Vite plugin transforms t() calls at build time:

// Input
const greeting = t('Hello, {name}!', { name })
// Output (Vue)
const greeting = __i18n.t('_hash123', { name: unref(name) })
// Output (Solid)
const greeting = __i18n.t('_hash123', { name: name() })

The t` ` tagged template is a compiler macro for reactive translations. You never import it — the Vite plugin injects the necessary imports automatically.

<script setup>
const pageTitle = t`Welcome to Fluenti`
const greeting = t`Hello ${name}, you have ${count} items`
</script>
<template>
<h1>{{ pageTitle }}</h1>
<p>{{ greeting }}</p>
</template>

Returns a ComputedRef — automatically updates when any referenced reactive value changes.

ExpressionICU PlaceholderValue
${name}{name}unref(name)
${user.name}{name}unref(user.name)
${user.profile.displayName}{displayName}unref(user.profile.displayName)
${getName()}{0}getName()
${a + b}{0}a + b

Rules: Simple identifier uses the name as placeholder. Property access uses the last segment. Everything else gets positional {0}, {1}, etc.

Use msg for translations that need to be defined outside of components — in constants, stores, or route definitions.

import { msg } from '@fluenti/core'
const ROLES = {
admin: msg`Administrator`,
user: msg`Regular User`,
}

msg returns a MessageDescriptor — it records the message text without translating it. Resolve it at render time with t():

<template>
<span>{{ t(ROLES.admin) }}</span>
</template>

Use cases: route meta, store constants, config objects, enum-like maps.

When translations contain HTML elements or framework components, use <Trans> with its default slot (Vue) or children (React/Solid). You write native HTML inside the component — no indexed placeholders.

<template>
<Trans>Read the <router-link to="/terms">terms</router-link> and <strong>conditions</strong></Trans>
</template>

Trans, Plural, and Select are globally registered by the Fluenti plugin — no import needed.

The <Trans> component extracts the text content of its default slot (including HTML tags) as the source message. During compilation, translators see the tags as placeholders, and at runtime the translated message is rendered with the original elements restored.

Fluenti uses Intl.PluralRules for locale-aware pluralization, supporting all CLDR plural categories. The <Plural> component is the simplest way to handle plurals. Pass the numeric value and provide a string for each plural category your source language needs. Use # as a placeholder for the numeric value.

<template>
<Plural :value="count" one="# item" other="# items" />
</template>
PropWhen used
value(required) The numeric value to pluralize on
zeroExact zero match
oneCLDR “one” category (e.g., 1 in English)
twoCLDR “two” category (e.g., Arabic dual)
fewCLDR “few” category (e.g., Russian 2-4)
manyCLDR “many” category (e.g., Arabic 11-99)
other(required) Fallback for all other values
tagWrapper element (default: 'span')

Plural forms are auto-extracted to catalogs by fluenti extract. You only write the source-language forms — Fluenti generates the correct ICU {count, plural, ...} pattern in the catalog.

You can also write ICU plural patterns directly in t() calls:

{count, plural,
=0 {No items}
one {# item}
other {# items}
}

Exact matches (=0, =1, =2) are checked before CLDR categories:

{count, plural, =0 {Nobody} =1 {Just you} one {# person} other {# people}}
{count, plural, offset:1
=0 {Nobody}
=1 {Just {name}}
one {# other and {name}}
other {# others and {name}}
}
LanguageCategories
Englishone, other
Chineseother (no plural forms)
Arabiczero, one, two, few, many, other
Russianone, few, many, other
Frenchone, other

ICU select patterns for choosing text based on a string value (e.g., gender, status).

<template>
<Select :value="gender" male="He liked this" female="She liked this" other="They liked this" />
</template>

For programmatic usage, pass an options object instead of individual props:

<Select value={role} options={{ admin: 'Full access', editor: 'Can edit', other: 'Unknown' }} />

Props: value (required), other (required), options (optional object), plus any string keys as individual props. tag optional.

SituationBest API
Vue template textv-t directive
Reactive value in <script setup>t`…` tagged template
JSX expression (React/Solid)t`…` tagged template
Rich text with embedded HTML<Trans> component
Plural forms<Plural> component
Outside component lifecycle (routes, stores)msg tagged template
Dynamic message IDs from APIt() / i18n.t() function