Skip to content
fluenti

Recipes

Practical patterns for real-world internationalization challenges.

Use msg to define translatable constants outside component lifecycle, then resolve them at render time:

<script setup>
import { msg } from '@fluenti/vue'
import { useI18n } from '@fluenti/vue'
const STATUS = {
pending: msg`Pending`,
active: msg`Active`,
archived: msg`Archived`,
} as const
const { t } = useI18n()
const props = defineProps<{ status: keyof typeof STATUS }>()
</script>
<template>
<span>{{ t(STATUS[props.status]) }}</span>
</template>

msg creates a lazy descriptor (with an auto-generated hash ID) that is only resolved when passed to t(). This ensures the message is extractable by fluenti extract while remaining outside the reactive component tree.

Translate validation error messages from schema libraries like Zod:

import { msg } from '@fluenti/react'
import { useI18n } from '@fluenti/react'
import { z } from 'zod'
const errors = {
required: msg`This field is required`,
tooShort: msg`Must be at least {min} characters`,
invalidEmail: msg`Please enter a valid email address`,
} as const
const schema = z.object({
email: z.string().min(1, 'required').email('invalidEmail'),
name: z.string().min(2, 'tooShort'),
})
function FormErrors({ issues }: { issues: z.ZodIssue[] }) {
const { t } = useI18n()
return (
<ul>
{issues.map((issue, i) => (
<li key={i}>
{t(errors[issue.message as keyof typeof errors] ?? msg`Unknown error`)}
</li>
))}
</ul>
)
}

Map server error codes to translated user-facing messages. Use te() to gracefully handle unknown codes:

import { msg } from '@fluenti/react'
import { useI18n } from '@fluenti/react'
const API_ERRORS: Record<string, ReturnType<typeof msg>> = {
AUTH_EXPIRED: msg`Your session has expired. Please sign in again.`,
RATE_LIMITED: msg`Too many requests. Please wait a moment.`,
NOT_FOUND: msg`The requested resource was not found.`,
FORBIDDEN: msg`You don't have permission to perform this action.`,
}
function useApiError() {
const { t } = useI18n()
return (code: string) => {
const descriptor = API_ERRORS[code]
return descriptor ? t(descriptor) : t(API_ERRORS.NOT_FOUND)
}
}

Fluenti provides isRTL() and getDirection() utilities for right-to-left language support:

import { isRTL, getDirection } from '@fluenti/core'
isRTL('ar') // true
isRTL('en') // false
getDirection('he') // 'rtl'
getDirection('ja') // 'ltr'

Set dir and lang on the <html> element when the locale changes:

import { useI18n } from '@fluenti/react'
import { getDirection } from '@fluenti/core'
import { useEffect } from 'react'
function App() {
const { locale } = useI18n()
useEffect(() => {
document.documentElement.lang = locale
document.documentElement.dir = getDirection(locale)
}, [locale])
return <main>...</main>
}

Use CSS logical properties instead of physical directions for automatic RTL support:

/* ❌ Physical properties — break in RTL */
.sidebar { margin-left: 1rem; padding-right: 2rem; text-align: left; }
/* ✅ Logical properties — work in both LTR and RTL */
.sidebar { margin-inline-start: 1rem; padding-inline-end: 2rem; text-align: start; }
PhysicalLogical
margin-left / margin-rightmargin-inline-start / margin-inline-end
padding-left / padding-rightpadding-inline-start / padding-inline-end
text-align: left / righttext-align: start / end
border-left / border-rightborder-inline-start / border-inline-end
left / right (positioning)inset-inline-start / inset-inline-end

When the message ID is determined at runtime (e.g., from an API or database), use useI18n().t() with a string key:

const { t } = useI18n()
// Runtime key lookup
const translatedLabel = t(dynamicKey)

Use te() to check if a dynamic key exists before rendering:

function DynamicLabel({ messageKey, fallback }: { messageKey: string; fallback: string }) {
const { te, t } = useI18n()
return <span>{te(messageKey) ? t(messageKey) : fallback}</span>
}

Render translated content only when a translation exists, with graceful fallback:

import { useI18n } from '@fluenti/react'
function FeatureDescription({ feature }: { feature: string }) {
const { te, t } = useI18n()
const descKey = `feature.${feature}.description`
if (!te(descKey)) {
return null // Don't render if no translation exists
}
return <p>{t(descKey)}</p>
}

This pattern is useful for optional content like feature descriptions, promotional banners, or region-specific notices that may not be translated for all locales.