# Internationalization

The date-fns internationalization system provides comprehensive support for 97+ languages and regions with customizable date formatting, relative time display, and cultural date conventions. All locale functionality is modular and tree-shakeable.

## Locale System Overview

### Locale Interface

```typescript { .api }
interface Locale {
  code: string;
  formatDistance?: FormatDistanceFn;
  formatLong?: FormatLongOptions;
  formatRelative?: FormatRelativeFn;
  localize?: LocalizeOptions;
  match?: MatchOptions;
  options?: LocaleOptions;
}
```

The locale object contains all language-specific formatting rules and translations needed for date operations in different languages and regions.

## Supported Locales

### Major Language Families

**English Variants**
- `enUS` - English (United States) - Default
- `enGB` - English (United Kingdom)  
- `enCA` - English (Canada)
- `enAU` - English (Australia)
- `enNZ` - English (New Zealand)
- `enIN` - English (India)
- `enIE` - English (Ireland)
- `enZA` - English (South Africa)

**European Languages**
- `de` - German (Germany)
- `deAT` - German (Austria)
- `fr` - French (France)
- `frCA` - French (Canada)
- `frCH` - French (Switzerland)
- `es` - Spanish (Spain)
- `it` - Italian (Italy)
- `itCH` - Italian (Switzerland)
- `pt` - Portuguese (Portugal)
- `ptBR` - Portuguese (Brazil)
- `nl` - Dutch (Netherlands)
- `nlBE` - Dutch (Belgium)

**Nordic Languages**
- `da` - Danish
- `sv` - Swedish
- `nb` - Norwegian Bokmål
- `nn` - Norwegian Nynorsk
- `fi` - Finnish
- `is` - Icelandic

**Slavic Languages**
- `ru` - Russian
- `pl` - Polish
- `cs` - Czech
- `sk` - Slovak
- `sl` - Slovenian
- `hr` - Croatian
- `sr` - Serbian (Cyrillic)
- `srLatn` - Serbian (Latin)
- `bg` - Bulgarian
- `mk` - Macedonian
- `be` - Belarusian
- `beTarask` - Belarusian (Taraskievica)
- `uk` - Ukrainian

**Asian Languages**
- `zhCN` - Chinese (Simplified, China)
- `zhHK` - Chinese (Traditional, Hong Kong)
- `zhTW` - Chinese (Traditional, Taiwan)
- `ja` - Japanese
- `jaHira` - Japanese (Hiragana)
- `ko` - Korean
- `th` - Thai
- `vi` - Vietnamese
- `hi` - Hindi
- `bn` - Bengali
- `gu` - Gujarati
- `kn` - Kannada
- `ta` - Tamil
- `te` - Telugu

**Middle Eastern & African**
- `ar` - Arabic
- `arDZ` - Arabic (Algeria)
- `arEG` - Arabic (Egypt)
- `arMA` - Arabic (Morocco)
- `arSA` - Arabic (Saudi Arabia)
- `arTN` - Arabic (Tunisia)
- `he` - Hebrew
- `faIR` - Persian (Iran)
- `tr` - Turkish
- `af` - Afrikaans

### Complete Locale List

```typescript
// Import specific locales
import { enUS, de, fr, ja, zhCN, ar } from "date-fns/locale";

// Available locales (97 total)
const locales = [
  'af', 'ar', 'arDZ', 'arEG', 'arMA', 'arSA', 'arTN',
  'az', 'be', 'beTarask', 'bg', 'bn', 'bs', 'ca', 'ckb',
  'cs', 'cy', 'da', 'de', 'deAT', 'el', 'enAU', 'enCA',
  'enGB', 'enIE', 'enIN', 'enNZ', 'enUS', 'enZA', 'eo',
  'es', 'et', 'eu', 'faIR', 'fi', 'fr', 'frCA', 'frCH',
  'fy', 'gd', 'gl', 'gu', 'he', 'hi', 'hr', 'ht', 'hu',
  'hy', 'id', 'is', 'it', 'itCH', 'ja', 'jaHira', 'ka',
  'kk', 'km', 'kn', 'ko', 'lb', 'lt', 'lv', 'mk', 'mn',
  'ms', 'mt', 'nb', 'nl', 'nlBE', 'nn', 'oc', 'pl', 'pt',
  'ptBR', 'ro', 'ru', 'se', 'sk', 'sl', 'sq', 'sr', 'srLatn',
  'sv', 'ta', 'te', 'th', 'tr', 'ug', 'uk', 'uz', 'uzCyrl',
  'vi', 'zhCN', 'zhHK', 'zhTW'
];
```

## Using Locales

### Basic Locale Usage

```typescript
import { format, formatDistance, formatRelative } from "date-fns";
import { de, fr, ja, zhCN } from "date-fns/locale";

const date = new Date(2014, 1, 11);

// German
format(date, "EEEE, do MMMM yyyy", { locale: de });
//=> 'Dienstag, 11. Februar 2014'

// French  
format(date, "EEEE, do MMMM yyyy", { locale: fr });
//=> 'mardi, 11e février 2014'

// Japanese
format(date, "EEEE, do MMMM yyyy", { locale: ja });
//=> '火曜日, 11日 2月 2014'

// Chinese (Simplified)
format(date, "EEEE, do MMMM yyyy", { locale: zhCN });
//=> '星期二, 11日 二月 2014'
```

### Distance Formatting with Locales

```typescript
import { formatDistance, formatDistanceToNow } from "date-fns";
import { de, es, ru, ar } from "date-fns/locale";

const date1 = new Date(2014, 6, 2);
const date2 = new Date(2015, 0, 1);

// German
formatDistance(date2, date1, { locale: de });
//=> 'etwa 6 Monate'

// Spanish
formatDistance(date2, date1, { locale: es });
//=> 'alrededor de 6 meses'

// Russian
formatDistance(date2, date1, { locale: ru });
//=> 'около 6 месяцев'

// Arabic
formatDistance(date2, date1, { locale: ar });
//=> 'حوالي 6 أشهر'
```

### Relative Formatting with Locales

```typescript
import { formatRelative } from "date-fns";
import { de, fr, ja } from "date-fns/locale";

const baseDate = new Date(2000, 0, 1, 0, 0, 0); // Jan 1, 2000
const date = new Date(1999, 11, 27); // Dec 27, 1999

// German
formatRelative(date, baseDate, { locale: de });
//=> 'letzten Montag um 00:00'

// French
formatRelative(date, baseDate, { locale: fr });
//=> 'lundi dernier à 00:00'

// Japanese  
formatRelative(date, baseDate, { locale: ja });
//=> '先週の月曜日 0:00'
```

## Locale Configuration Options

### Week Configuration

```typescript
import { format, startOfWeek } from "date-fns";
import { de, ar, enUS } from "date-fns/locale";

const date = new Date(2014, 1, 11); // Tuesday

// Different week start days by locale
startOfWeek(date, { locale: enUS }); // Sunday start
//=> Sun Feb 09 2014

startOfWeek(date, { locale: de }); // Monday start  
//=> Mon Feb 10 2014

// Manual override
startOfWeek(date, { locale: enUS, weekStartsOn: 1 }); // Force Monday start
//=> Mon Feb 10 2014
```

### First Week Configuration

```typescript
import { getWeek } from "date-fns";
import { de, enUS } from "date-fns/locale";

const date = new Date(2014, 0, 1); // Jan 1, 2014

// Different first week rules
getWeek(date, { locale: enUS }); 
//=> 1 (US: week containing Jan 1 is week 1)

getWeek(date, { locale: de });
//=> 1 (German: week with 4+ days in new year is week 1)
```

## Locale-Specific Patterns

### Date Patterns by Locale

```typescript
import { format } from "date-fns";
import { enUS, de, ja, ar } from "date-fns/locale";

const date = new Date(2014, 1, 11);

// US format (M/d/yyyy)
format(date, "P", { locale: enUS });
//=> '2/11/2014'

// German format (dd.MM.yyyy)
format(date, "P", { locale: de });
//=> '11.02.2014'

// Japanese format (yyyy/MM/dd)  
format(date, "P", { locale: ja });
//=> '2014/02/11'

// Arabic format (d‏/M‏/yyyy)
format(date, "P", { locale: ar });
//=> '11‏/2‏/2014'
```

### Time Patterns by Locale

```typescript
import { format } from "date-fns";
import { enUS, de, ja } from "date-fns/locale";

const date = new Date(2014, 1, 11, 14, 30);

// US format (2:30 PM)
format(date, "p", { locale: enUS });
//=> '2:30 PM'

// German format (14:30)
format(date, "p", { locale: de });
//=> '14:30'

// Japanese format (14:30)
format(date, "p", { locale: ja });
//=> '14:30'
```

### Long Format Patterns

```typescript
import { format } from "date-fns";
import { enUS, de, fr, ja } from "date-fns/locale";

const date = new Date(2014, 1, 11, 14, 30, 45);

// Full date and time formats
format(date, "PPPPpppp", { locale: enUS });
//=> 'Tuesday, February 11th, 2014 at 2:30:45 PM GMT+2'

format(date, "PPPPpppp", { locale: de });
//=> 'Dienstag, 11. Februar 2014 um 14:30:45 GMT+2'

format(date, "PPPPpppp", { locale: fr });
//=> 'mardi 11 février 2014 à 14:30:45 GMT+2'

format(date, "PPPPpppp", { locale: ja });
//=> '2014年2月11日火曜日 14:30:45 GMT+2'
```

## Creating Custom Locales

### Locale Structure

```typescript { .api }
interface Locale {
  code: string;
  formatDistance: FormatDistanceFn;
  formatLong: FormatLongOptions;
  formatRelative: FormatRelativeFn;
  localize: LocalizeOptions;
  match: MatchOptions;
  options?: LocaleOptions;
}
```

### Custom Locale Example

```typescript
import { Locale } from "date-fns";

const customLocale: Locale = {
  code: 'custom',
  
  formatDistance: (token, count, options) => {
    // Custom distance formatting logic
    const formatDistanceLocale = {
      lessThanXSeconds: 'less than {{count}} second{{s}}',
      xSeconds: '{{count}} second{{s}}',
      halfAMinute: 'half a minute',
      lessThanXMinutes: 'less than {{count}} minute{{s}}',
      xMinutes: '{{count}} minute{{s}}',
      aboutXHours: 'about {{count}} hour{{s}}',
      xHours: '{{count}} hour{{s}}',
      xDays: '{{count}} day{{s}}',
      aboutXWeeks: 'about {{count}} week{{s}}',
      xWeeks: '{{count}} week{{s}}',
      aboutXMonths: 'about {{count}} month{{s}}',
      xMonths: '{{count}} month{{s}}',
      aboutXYears: 'about {{count}} year{{s}}',
      xYears: '{{count}} year{{s}}',
      overXYears: 'over {{count}} year{{s}}',
      almostXYears: 'almost {{count}} year{{s}}'
    };

    const result = formatDistanceLocale[token].replace(
      '{{count}}', 
      count.toString()
    );
    
    return result.replace('{{s}}', count === 1 ? '' : 's');
  },

  formatLong: {
    time: 'HH:mm:ss',
    date: 'dd/MM/yyyy',
    dateTime: '{{date}} {{time}}',
    longDate: 'MMMM d, yyyy',
    fullDate: 'EEEE, MMMM do, yyyy',
    shortTime: 'HH:mm',
    longTime: 'HH:mm:ss',
    fullTime: 'HH:mm:ss'
  },

  formatRelative: (token, date, baseDate, options) => {
    // Custom relative formatting
    const formatRelativeLocale = {
      lastWeek: "'last' eeee 'at' p",
      yesterday: "'yesterday at' p",
      today: "'today at' p", 
      tomorrow: "'tomorrow at' p",
      nextWeek: "eeee 'at' p",
      other: 'P'
    };
    
    return formatRelativeLocale[token];
  },

  localize: {
    // Month names, day names, etc.
    month: (month) => ['Jan', 'Feb', 'Mar', /*...*/][month],
    day: (day) => ['Sun', 'Mon', 'Tue', /*...*/][day],
    // Additional localization functions...
  },

  match: {
    // Parsing patterns for custom locale
    // Match functions for parsing formatted dates
  },

  options: {
    weekStartsOn: 1, // Monday
    firstWeekContainsDate: 4
  }
};
```

### Using Custom Locales

```typescript
import { format } from "date-fns";

// Use the custom locale
format(new Date(), "PPP", { locale: customLocale });
```

## Locale Helper Functions

### Locale Detection

```typescript
// Browser locale detection
function getBrowserLocale(): string {
  return navigator.language || navigator.languages[0] || 'en-US';
}

// Map browser locale to date-fns locale
function getDateFnsLocale(browserLocale: string): Locale {
  const localeMap: Record<string, () => Promise<Locale>> = {
    'de': () => import('date-fns/locale/de'),
    'de-DE': () => import('date-fns/locale/de'),
    'fr': () => import('date-fns/locale/fr'),
    'fr-FR': () => import('date-fns/locale/fr'),
    // Add more mappings...
  };
  
  const loader = localeMap[browserLocale] || 
                 localeMap[browserLocale.split('-')[0]] ||
                 (() => import('date-fns/locale/en-US'));
  
  return loader();
}
```

### Dynamic Locale Loading

```typescript
// Lazy load locales
class LocaleManager {
  private loadedLocales = new Map<string, Locale>();
  
  async getLocale(code: string): Promise<Locale> {
    if (this.loadedLocales.has(code)) {
      return this.loadedLocales.get(code)!;
    }
    
    try {
      const locale = await import(`date-fns/locale/${code}`);
      this.loadedLocales.set(code, locale.default);
      return locale.default;
    } catch {
      // Fallback to English
      const enUS = await import('date-fns/locale/en-US');
      return enUS.default;
    }
  }
}
```

## Right-to-Left (RTL) Support

### Arabic and Hebrew Examples

```typescript
import { format } from "date-fns";
import { ar, he } from "date-fns/locale";

const date = new Date(2014, 1, 11);

// Arabic (RTL)
format(date, "EEEE، do MMMM yyyy", { locale: ar });
//=> 'الثلاثاء، 11 فبراير 2014'

// Hebrew (RTL)  
format(date, "EEEE, do MMMM yyyy", { locale: he });
//=> 'יום שלישי, 11 פברואר 2014'
```

### Handling RTL in Applications

```typescript
import { ar, he, enUS } from "date-fns/locale";

function isRTLLocale(locale: Locale): boolean {
  const rtlCodes = ['ar', 'he', 'fa', 'ur'];
  return rtlCodes.includes(locale.code);
}

function formatWithDirection(date: Date, pattern: string, locale: Locale): {
  text: string;
  direction: 'ltr' | 'rtl';
} {
  return {
    text: format(date, pattern, { locale }),
    direction: isRTLLocale(locale) ? 'rtl' : 'ltr'
  };
}
```

## Option Types

### LocaleOptions

```typescript { .api }
interface LocaleOptions {
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
  firstWeekContainsDate?: 1 | 2 | 3 | 4 | 5 | 6 | 7;
}
```

### FormatLongOptions

```typescript { .api }
interface FormatLongOptions {
  time?: string;
  date?: string;
  dateTime?: string;
  longDate?: string;
  fullDate?: string;
  shortTime?: string;
  longTime?: string;
  fullTime?: string;
}
```

### FormatDistanceFn

```typescript { .api }
type FormatDistanceFn = (
  token: string,
  count: number,
  options?: { addSuffix?: boolean; comparison?: number }
) => string;
```

### FormatRelativeFn

```typescript { .api }
type FormatRelativeFn = (
  token: 'lastWeek' | 'yesterday' | 'today' | 'tomorrow' | 'nextWeek' | 'other',
  date: Date,
  baseDate: Date,
  options?: any
) => string;
```