Internationalization (i18n) patterns for multi-language applications. Covers next-intl, ICU message syntax, pluralization, date/number formatting, RTL support, and locale management. Trigger: When implementing translations, when supporting multiple languages, when formatting dates or numbers for different locales, when handling RTL languages.
Resources
1Install
npx skillscat add dsantiagomj/dsmj-ai-toolkit/i18n Install via the SkillsCat registry.
This skill provides internationalization patterns for multi-language web applications, covering next-intl setup, ICU message syntax, pluralization, date and number formatting, and RTL support. It addresses the problem of localizing user interfaces and content across different locales and scripts. Developers should use it when adding translations, supporting multiple languages, formatting locale-specific data, or handling right-to-left text.
Internationalization (i18n)
Build applications that speak your users' language
When to Use This Skill
Use this skill when:
- Implementing multi-language support
- Formatting dates/numbers for different locales
- Handling RTL languages
- Managing translation files
Critical Patterns
Pattern 1: Basic Translation
When: Displaying translated text
Good:
// useTranslations hook
import { useTranslations } from 'next-intl';
export default function HomePage() {
const t = useTranslations('homepage');
return (
<div>
<h1>{t('title')}</h1>
<p>{t('subtitle')}</p>
</div>
);
}
// Translation file
// messages/en.json
{
"homepage": {
"title": "Welcome to Our Store",
"subtitle": "Find the best products"
}
}Why: Centralized translations make it easy to support multiple languages.
Pattern 2: Variables in Translations
When: Including dynamic values
Good:
{
"welcome": "Welcome, {username}!",
"itemCount": "You have {count} items"
}<p>{t('welcome', { username: 'Alice' })}</p>
<p>{t('itemCount', { count: 5 })}</p>Why: ICU syntax allows flexible variable interpolation.
Pattern 3: Pluralization
When: Handling singular/plural forms
Good:
{
"items": "{count, plural, =0 {No items} =1 {1 item} other {# items}}"
}<p>{t('items', { count: 0 })}</p> // "No items"
<p>{t('items', { count: 1 })}</p> // "1 item"
<p>{t('items', { count: 5 })}</p> // "5 items"Why: Different languages have different pluralization rules.
Pattern 4: Date/Number Formatting
When: Displaying locale-specific formats
Good:
import { useFormatter } from 'next-intl';
export default function EventDate({ date, amount }) {
const format = useFormatter();
return (
<div>
{/* Date: "January 15, 2024" (en), "15 janvier 2024" (fr) */}
<p>{format.dateTime(date, { dateStyle: 'long' })}</p>
{/* Currency: "$99.99" (en-US), "99,99 €" (de-DE) */}
<p>{format.number(amount, {
style: 'currency',
currency: 'USD'
})}</p>
</div>
);
}Why: Date and number formats vary by locale.
Pattern 5: RTL Support
When: Supporting Arabic, Hebrew, etc.
Good:
/* Use logical properties */
.card {
margin-inline-start: 1rem; /* Left in LTR, right in RTL */
padding-inline-end: 2rem;
}
/* Manual RTL handling */
[dir='rtl'] .arrow {
transform: scaleX(-1);
}// Set dir attribute
<html lang={locale} dir={locale === 'ar' ? 'rtl' : 'ltr'}>Why: RTL languages need flipped layouts.
Best Practices
Do's:
- ✅ Extract all user-facing text to translation files
- ✅ Use ICU syntax for complex messages
- ✅ Test with long German text (30% longer)
- ✅ Test RTL languages
- ✅ Format dates/numbers with locale-aware formatters
- ✅ Provide context in translation keys
Don'ts:
- ❌ Don't hardcode strings
- ❌ Don't concatenate translations
- ❌ Don't use locale for business logic
- ❌ Don't forget text expansion
Code Examples
Example 1: Basic Translation with Variables
// messages/en.json
{
"welcome": "Welcome, {username}!",
"cartItems": "You have {count, plural, =0 {no items} =1 {1 item} other {# items}} in your cart"
}
// Component
import { useTranslations } from 'next-intl';
export default function Header({ username, cartCount }: HeaderProps) {
const t = useTranslations();
return (
<header>
<h1>{t('welcome', { username })}</h1>
<p>{t('cartItems', { count: cartCount })}</p>
</header>
);
}Example 2: Locale-Aware Date and Number Formatting
import { useFormatter } from 'next-intl';
export default function ProductCard({ product }: ProductCardProps) {
const format = useFormatter();
return (
<div>
<h3>{product.name}</h3>
<p>{format.number(product.price, {
style: 'currency',
currency: 'USD'
})}</p>
<time>{format.dateTime(product.releaseDate, {
year: 'numeric',
month: 'long',
day: 'numeric'
})}</time>
</div>
);
}For comprehensive examples and detailed implementations, see the references/ folder.
Progressive Disclosure
For detailed implementations:
- next-intl Setup - Installation, middleware, layouts
- ICU Patterns - Variables, pluralization, rich text, formatting
References
Maintained by dsmj-ai-toolkit