Formatting
Fluenti provides ICU message interpolation via format(), catalog-based translation via t(), and locale-aware date/number formatting via d() and n().
t() vs format()
Section titled “t() vs format()”| Function | Purpose | Source |
|---|---|---|
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 |
format() examples
Section titled “format() examples”const { format } = useI18n()
// Simple interpolationformat('Hello, {name}!', { name: 'World' })// → "Hello, World!"
// Pluralformat('{count, plural, one {# item} other {# items}}', { count: 5 })// → "5 items"
// Selectformat('{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() — Catalog Translation
Section titled “t() — Catalog Translation”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.
Date Formatting — d()
Section titled “Date Formatting — d()”<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" />import { useI18n } from '@fluenti/react'
function DateExample() { const { d } = useI18n() const createdAt = new Date()
return ( <div> <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 */} </div> )}Or use the <DateTime> component:
<DateTime value={createdAt} format="long" />import { useI18n } from '@fluenti/solid'
function DateExample() { const { d } = useI18n() const createdAt = new Date()
return ( <div> <p>{d(createdAt)}</p> <p>{d(createdAt, 'short')}</p> <p>{d(createdAt, 'long')}</p> <p>{d(createdAt, 'relative')}</p> </div> )}Or use the <DateTime> component:
<DateTime value={createdAt} format="long" />Built-in Date Styles
Section titled “Built-in Date Styles”| Style | Example (en) |
|---|---|
default | Jan 15, 2025 |
short | 1/15/2025 |
long | Wednesday, January 15, 2025 |
time | 3:30 PM |
datetime | Jan 15, 2025, 3:30 PM |
relative | 3 days ago / in 2 hours |
Number Formatting — n()
Section titled “Number Formatting — n()”<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" />import { useI18n } from '@fluenti/react'
function NumberExample() { const { n } = useI18n()
return ( <div> <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 */} </div> )}Or use the <NumberFormat> component:
<NumberFormat value={1234.5} format="currency" />import { useI18n } from '@fluenti/solid'
function NumberExample() { const { n } = useI18n()
return ( <div> <p>{n(1234.5, 'currency')}</p> <p>{n(0.85, 'percent')}</p> <p>{n(1234.5, 'decimal')}</p> </div> )}Or use the <NumberFormat> component:
<NumberFormat value={1234.5} format="currency" />Built-in Number Styles
Section titled “Built-in Number Styles”| Style | Example (en) |
|---|---|
default | 1,234.5 |
currency | $1,234.50 (auto-detects currency from locale) |
percent | 85% |
decimal | 1,234.50 |
Auto Currency Detection
Section titled “Auto Currency Detection”The currency style automatically uses the correct currency for each locale:
| Locale | Currency |
|---|---|
en | USD |
en-GB | GBP |
zh-CN | CNY |
ja | JPY |
de / fr | EUR |
Custom Format Styles
Section titled “Custom Format Styles”Define your own date and number format styles when creating your i18n instance.
Custom Date Formats
Section titled “Custom Date Formats”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”
<I18nProvider locale="en" messages={messages} dateFormats={{ 'month-year': { year: 'numeric', month: 'long' }, 'time-24h': { hour: '2-digit', minute: '2-digit', hour12: false }, relative: 'relative', }}> <App /></I18nProvider>Usage: d(date, 'month-year') → “January 2025”
<I18nProvider locale="en" messages={messages} dateFormats={{ 'month-year': { year: 'numeric', month: 'long' }, 'time-24h': { hour: '2-digit', minute: '2-digit', hour12: false }, relative: 'relative', }}> <App /></I18nProvider>Usage: d(date, 'month-year') → “January 2025”
Custom Number Formats
Section titled “Custom Number Formats”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”
<I18nProvider locale="en" messages={messages} numberFormats={{ compact: { notation: 'compact' }, 'currency-no-cents': { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }, }}> <App /></I18nProvider>Usage: n(1234567, 'compact') → “1.2M”
<I18nProvider locale="en" messages={messages} numberFormats={{ compact: { notation: 'compact' }, 'currency-no-cents': { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }, }}> <App /></I18nProvider>Usage: n(1234567, 'compact') → “1.2M”
ICU Custom Formatters
Section titled “ICU Custom Formatters”Beyond the built-in d() and n() helpers, you can register custom ICU function formatters that handle {variable, functionName, style} syntax inside messages.
How it works
Section titled “How it works”When the ICU compiler encounters {variable, functionName} or {variable, functionName, style}, it checks formatters in this order:
- Custom formatters (registered via
formattersconfig) — checked first - 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).
Signature
Section titled “Signature”type CustomFormatter = (value: unknown, style: string, locale: string) => string| Parameter | Description |
|---|---|
value | The interpolated variable value |
style | The style argument from the ICU syntax (e.g., short in {x, date, short}). Empty string if omitted. |
locale | The current locale code |
Registration
Section titled “Registration”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[]), },})<I18nProvider locale="en" messages={messages} formatters={{ uppercase: (value) => String(value).toUpperCase(), list: (value, style, locale) => new Intl.ListFormat(locale, { type: style || 'conjunction' }) .format(value as string[]), }}> <App /></I18nProvider><I18nProvider locale="en" messages={messages} formatters={{ uppercase: (value) => String(value).toUpperCase(), list: (value, style, locale) => new Intl.ListFormat(locale, { type: style || 'conjunction' }) .format(value as string[]), }}> <App /></I18nProvider>Usage in ICU messages
Section titled “Usage in ICU messages”Welcome, {name, uppercase}!→ "Welcome, ALICE!"
Items: {items, list, disjunction}→ "Items: apples, bananas, or cherries"Overriding built-in formatters
Section titled “Overriding built-in formatters”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)"
<DateTime> and <NumberFormat> Components
Section titled “<DateTime> and <NumberFormat> Components”All frameworks provide <DateTime> and <NumberFormat> components for formatting values directly in templates. These are the component equivalents of the d() and n() functions.
When to use components vs functions
Section titled “When to use components vs functions”Component (<DateTime>, <NumberFormat>) | Function (d(), n()) | |
|---|---|---|
| Best for | Template/JSX inline rendering | Computed values, string concatenation |
| Usage | Declarative, in markup | Imperative, in script/logic |
<DateTime>
Section titled “<DateTime>”<template> <p>Created: <DateTime :value="post.createdAt" format="long" /></p> <p>Updated: <DateTime :value="post.updatedAt" format="relative" /></p></template><p>Created: <DateTime value={post.createdAt} format="long" /></p><p>Updated: <DateTime value={post.updatedAt} format="relative" /></p><p>Created: <DateTime value={post.createdAt} format="long" /></p><p>Updated: <DateTime value={post.updatedAt} format="relative" /></p>| Prop | Type | Description |
|---|---|---|
value | Date | number | (required) Date value to format |
style | string? | Named format style: 'short', 'long', 'time', 'datetime', 'relative', or a custom style name |
<NumberFormat>
Section titled “<NumberFormat>”<template> <p>Price: <NumberFormat :value="item.price" format="currency" /></p> <p>Progress: <NumberFormat :value="0.85" format="percent" /></p></template><p>Price: <NumberFormat value={item.price} format="currency" /></p><p>Progress: <NumberFormat value={0.85} format="percent" /></p><p>Price: <NumberFormat value={item.price} format="currency" /></p><p>Progress: <NumberFormat value={0.85} format="percent" /></p>| Prop | Type | Description |
|---|---|---|
value | number | (required) Number value to format |
style | string? | 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.