Skip to content
fluenti

Formatting

Fluenti provides ICU message interpolation via format(), catalog-based translation via t(), and locale-aware date/number formatting via d() and n().

FunctionPurposeSource
t(message, values?)Translate a message from the compiled catalog. The message is looked up by hash, and the translated string for the current locale is returned.Catalog (PO/JSON)
format(pattern, values?)Direct ICU MessageFormat interpolation. No catalog lookup — the pattern is interpreted as-is. Use for dynamic patterns (e.g., server-provided templates, user-generated content).Inline pattern
const { format } = useI18n()
// Simple interpolation
format('Hello, {name}!', { name: 'World' })
// → "Hello, World!"
// Plural
format('{count, plural, one {# item} other {# items}}', { count: 5 })
// → "5 items"
// Select
format('{role, select, admin {Full access} other {Limited access}}', { role: 'admin' })
// → "Full access"

Use format() when the pattern itself is dynamic or not part of your static catalog — for example, patterns received from an API response or a CMS.

t() is the primary API for translating static messages:

const { t } = useI18n()
t('Hello, {name}!', { name: 'World' })
// Looks up the hash of "Hello, {name}!" in the compiled catalog,
// returns the translated string for the current locale.

Messages used with t() are extracted by fluenti extract and compiled into per-locale bundles.


<script setup>
import { useI18n } from '@fluenti/vue'
const { d } = useI18n()
const createdAt = new Date()
</script>
<template>
<p>{{ d(createdAt) }}</p> <!-- Default format -->
<p>{{ d(createdAt, 'short') }}</p> <!-- 1/15/2025 -->
<p>{{ d(createdAt, 'long') }}</p> <!-- Wednesday, January 15, 2025 -->
<p>{{ d(createdAt, 'relative') }}</p> <!-- 3 days ago -->
</template>

Or use the <DateTime> component:

<DateTime :value="createdAt" format="long" />
StyleExample (en)
defaultJan 15, 2025
short1/15/2025
longWednesday, January 15, 2025
time3:30 PM
datetimeJan 15, 2025, 3:30 PM
relative3 days ago / in 2 hours
<script setup>
import { useI18n } from '@fluenti/vue'
const { n } = useI18n()
</script>
<template>
<p>{{ n(1234.5, 'currency') }}</p> <!-- $1,234.50 -->
<p>{{ n(0.85, 'percent') }}</p> <!-- 85% -->
<p>{{ n(1234.5, 'decimal') }}</p> <!-- 1,234.50 -->
</template>

Or use the <NumberFormat> component:

<NumberFormat :value="1234.5" format="currency" />
StyleExample (en)
default1,234.5
currency$1,234.50 (auto-detects currency from locale)
percent85%
decimal1,234.50

The currency style automatically uses the correct currency for each locale:

LocaleCurrency
enUSD
en-GBGBP
zh-CNCNY
jaJPY
de / frEUR

Define your own date and number format styles when creating your i18n instance.

const i18n = createFluenti({
locale: 'en',
messages,
dateFormats: {
'month-year': { year: 'numeric', month: 'long' },
'time-24h': { hour: '2-digit', minute: '2-digit', hour12: false },
relative: 'relative',
},
})

Usage: {{ d(date, 'month-year') }} → “January 2025”

const i18n = createFluenti({
locale: 'en',
messages,
numberFormats: {
compact: { notation: 'compact' },
'currency-no-cents': { style: 'currency', currency: 'USD', maximumFractionDigits: 0 },
// Function form for locale-dependent config
currency: (locale) => ({
style: 'currency',
currency: CURRENCY_MAP[locale] ?? 'USD',
}),
},
})

Usage: {{ n(1234567, 'compact') }} → “1.2M”


Beyond the built-in d() and n() helpers, you can register custom ICU function formatters that handle {variable, functionName, style} syntax inside messages.

When the ICU compiler encounters {variable, functionName} or {variable, functionName, style}, it checks formatters in this order:

  1. Custom formatters (registered via formatters config) — checked first
  2. Built-in formatters (number, date, time) — fallback

This means custom formatters can override built-in behavior if you register a formatter with the same name (e.g., a custom number formatter replaces the default Intl.NumberFormat handling).

type CustomFormatter = (value: unknown, style: string, locale: string) => string
ParameterDescription
valueThe interpolated variable value
styleThe style argument from the ICU syntax (e.g., short in {x, date, short}). Empty string if omitted.
localeThe current locale code
const i18n = createFluenti({
locale: 'en',
messages,
formatters: {
uppercase: (value) => String(value).toUpperCase(),
list: (value, style, locale) =>
new Intl.ListFormat(locale, { type: style || 'conjunction' })
.format(value as string[]),
},
})
Welcome, {name, uppercase}!
→ "Welcome, ALICE!"
Items: {items, list, disjunction}
→ "Items: apples, bananas, or cherries"

Register a formatter named number, date, or time to replace the default behavior:

formatters: {
// Custom number formatter with accounting notation
number: (value, style, locale) => {
if (style === 'accounting') {
const n = Number(value)
return n < 0
? `(${Math.abs(n).toLocaleString(locale)})`
: n.toLocaleString(locale)
}
// Fall back to default Intl formatting for other styles
return new Intl.NumberFormat(locale).format(Number(value))
},
}

Usage: {amount, number, accounting} with value -1234"(1,234)"

All frameworks provide <DateTime> and <NumberFormat> components for formatting values directly in templates. These are the component equivalents of the d() and n() functions.

Component (<DateTime>, <NumberFormat>)Function (d(), n())
Best forTemplate/JSX inline renderingComputed values, string concatenation
UsageDeclarative, in markupImperative, in script/logic
<template>
<p>Created: <DateTime :value="post.createdAt" format="long" /></p>
<p>Updated: <DateTime :value="post.updatedAt" format="relative" /></p>
</template>
PropTypeDescription
valueDate | number(required) Date value to format
stylestring?Named format style: 'short', 'long', 'time', 'datetime', 'relative', or a custom style name
<template>
<p>Price: <NumberFormat :value="item.price" format="currency" /></p>
<p>Progress: <NumberFormat :value="0.85" format="percent" /></p>
</template>
PropTypeDescription
valuenumber(required) Number value to format
stylestring?Named format style: 'currency', 'percent', 'decimal', or a custom style name

Custom styles are defined via dateFormats and numberFormats in the provider configuration. See Configuration for details.