Dsantiagomj

i18n

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.

Dsantiagomj 0 Updated 7mo ago

Resources

1
GitHub

Install

npx skillscat add dsantiagomj/dsmj-ai-toolkit/i18n

Install via the SkillsCat registry.

About this skill

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.

SKILL.md

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:


References


Maintained by dsmj-ai-toolkit