# Formatting

Starting with **i18next>=21.3.0** you can use the built-in formatting functions based on the [Intl API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl).

{% hint style="warning" %}
Starting with **i18next v26.0.0**, the legacy `interpolation.format` function will be removed. The built-in Formatter is now always used. For custom formatting, use `i18next.services.formatter.add()` or `.addCached()` as described below, or provide a custom Formatter module via `.use()`.
{% endhint %}

*You may need to* [*polyfill*](https://formatjs.io/docs/polyfills/) *the Intl API:*

* [*Intl.PluralRules*](https://formatjs.io/docs/polyfills/intl-pluralrules)
* [*Intl.RelativeTimeFormat*](https://formatjs.io/docs/polyfills/intl-relativetimeformat)
* [*Intl.ListFormat*](https://formatjs.io/docs/polyfills/intl-listformat)
* [*Intl.DisplayNames*](https://formatjs.io/docs/polyfills/intl-displaynames)
* [*Intl.NumberFormat*](https://formatjs.io/docs/polyfills/intl-numberformat) *(ES2020)*
* [*Intl.Locale*](https://formatjs.io/docs/polyfills/intl-locale)
* [*Intl.getCanonicalLocales*](https://formatjs.io/docs/polyfills/intl-getcanonicallocales)
* [*Intl.DateTimeFormat*](https://formatjs.io/docs/polyfills/intl-datetimeformat) *(ES2020)*

{% hint style="info" %}
🎓 Check out this topic in the [i18next crash course video](https://youtu.be/SA_9i4TtxLQ?t=557).
{% endhint %}

## Basic usage

The translation string has the following signature:

```json
{
  "key": "Some format {{value, formatname}}",
  "keyWithOptions": "Some format {{value, formatname(option1Name: option1Value; option2Name: option2Value)}}"
}
```

{% hint style="info" %}
Use a "semicolon" delimited list of options.
{% endhint %}

{% tabs %}
{% tab title="JavaScript" %}
Passing options to the formatting:

1. In the translation string using `{{value, formatname(options1: options1Value)}}`
2. Using the root level options when calling `t('key', { option1: option1Value })`
3. Using the per value options like: `t('key', { formatParams: { value: { option1: option1Value } })`

Samples

```javascript
// JSON
{
  "intlNumber": "Some {{val, number}}",
  "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}"
}

i18next.t('intlNumber', { val: 1000 });
// --> Some 1,000
i18next.t('intlNumber', { val: 1000.1, minimumFractionDigits: 3 });
// --> Some 1,000.100
i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } });
// --> Some 1,000.100
i18next.t('intlNumberWithOptions', { val: 2000 });
// --> Some 2,000.00
i18next.t('intlNumberWithOptions', { val: 2000, minimumFractionDigits: 3 });
// --> Some 2,000.000
```

{% endtab %}

{% tab title="TypeScript" %}
Passing options to the formatting:

1. In the translation string using `{{value, formatname(options1: options1Value)}}`
2. Using the root level options when calling `t($ => $.key, { option1: option1Value })`
3. Using the per value options like: `t($ => $.key, { formatParams: { value: { option1: option1Value } })`

Samples

```typescript
// JSON
{
  "intlNumber": "Some {{val, number}}",
  "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}"
}

i18next.t($ => $.intlNumber, { val: 1000 });
// --> Some 1,000
i18next.t($ => $.intlNumber, { val: 1000.1, minimumFractionDigits: 3 });
// --> Some 1,000.100
i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } });
// --> Some 1,000.100
i18next.t($ => $.intlNumberWithOptions, { val: 2000 });
// --> Some 2,000.00
i18next.t($ => $.intlNumberWithOptions, { val: 2000, minimumFractionDigits: 3 });
// --> Some 2,000.000
```

{% endtab %}
{% endtabs %}

#### Overriding the language to use

The language can be overridden by passing it in t.options

{% tabs %}
{% tab title="JavaScript" %}

```javascript
i18next.t('intlNumber', { val: 1000.1, lng: 'de' }); 
// or: i18next.t('intlNumber', { val: 1000.1, locale: 'de' });
i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { lng: 'de' } } });
// or: i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { locale: 'de' } } });
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
i18next.t($ => $.intlNumber, { val: 1000.1, lng: 'de' }); 
// or: i18next.t($ => $.intlNumber, { val: 1000.1, locale: 'de' });
i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { lng: 'de' } } }); 
// or: i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { locale: 'de' } } });
```

{% endtab %}
{% endtabs %}

#### Adding custom format function

It's rather simple to add own function:

```javascript
// after i18next.init(options);
i18next.services.formatter.add('lowercase', (value, lng, options) => {
  return value.toLowerCase();
});
i18next.services.formatter.add('underscore', (value, lng, options) => {
  return value.replace(/\s+/g, '_');
});
```

{% hint style="warning" %}
Make sure you add your custom format function **AFTER** the `i18next.init()` call.
{% endhint %}

There's also an addCached version for optimized performance:

```javascript
i18next.services.formatter.addCached('specialformat', (lng, options) => {
  const formatter = new Intl.NumberFormat(lng, options);
  return (val) => formatter.format(val);
});
```

#### Using multiple formatters

```json
{
  "key": "Some format {{value, formatter1, formatter2}}"
}
```

## Built-in formats

### Number

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// JSON
{
  "intlNumber": "Some {{val, number}}",
  "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}"
}

i18next.t('intlNumber', { val: 1000 });
// --> Some 1,000
i18next.t('intlNumber', { val: 1000.1, minimumFractionDigits: 3 });
// --> Some 1,000.100
i18next.t('intlNumber', { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } });
// --> Some 1,000.100
i18next.t('intlNumberWithOptions', { val: 2000 });
// --> Some 2,000.00
i18next.t('intlNumberWithOptions', { val: 2000, minimumFractionDigits: 3 });
// --> Some 2,000.000
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// JSON
{
  "intlNumber": "Some {{val, number}}",
  "intlNumberWithOptions": "Some {{val, number(minimumFractionDigits: 2)}}"
}

i18next.t($ => $.intlNumber, { val: 1000 });
// --> Some 1,000
i18next.t($ => $.intlNumber, { val: 1000.1, minimumFractionDigits: 3 });
// --> Some 1,000.100
i18next.t($ => $.intlNumber, { val: 1000.1, formatParams: { val: { minimumFractionDigits: 3 } } });
// --> Some 1,000.100
i18next.t($ => $.intlNumberWithOptions, { val: 2000 });
// --> Some 2,000.00
i18next.t($ => $.intlNumberWithOptions, { val: 2000, minimumFractionDigits: 3 });
// --> Some 2,000.000
```

{% endtab %}
{% endtabs %}

For options see: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat>

### Currency

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// JSON
{
  "intlCurrencyWithOptionsSimplified": "The value is {{val, currency(USD)}}",
  "intlCurrencyWithOptions": "The value is {{val, currency(currency: USD)}}",
  "twoIntlCurrencyWithUniqueFormatOptions": "The value is {{localValue, currency}} or {{altValue, currency}}",
}

i18next.t('intlCurrencyWithOptionsSimplified', { val: 2000 });
// --> The value is $2,000.00
i18next.t('intlCurrencyWithOptions', { val: 2300 });
// --> The value is $2,300.00
i18next.t('twoIntlCurrencyWithUniqueFormatOptions',
          {
            localValue: 12345.67,
            altValue: 16543.21,
            formatParams: {
              localValue: { currency: 'USD', locale: 'en-US' },
              altValue: { currency: 'CAD', locale: 'fr-CA' },
            },
          },);
// --> The value is $12,345.67 or 16 543,21 $ CA
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// JSON
{
  "intlCurrencyWithOptionsSimplified": "The value is {{val, currency(USD)}}",
  "intlCurrencyWithOptions": "The value is {{val, currency(currency: USD)}}",
  "twoIntlCurrencyWithUniqueFormatOptions": "The value is {{localValue, currency}} or {{altValue, currency}}",
}

i18next.t($ => $.intlCurrencyWithOptionsSimplified, { val: 2000 });
// --> The value is $2,000.00
i18next.t($ => $.intlCurrencyWithOptions, { val: 2300 });
// --> The value is $2,300.00
i18next.t($ => $.twoIntlCurrencyWithUniqueFormatOptions,
          {
            localValue: 12345.67,
            altValue: 16543.21,
            formatParams: {
              localValue: { currency: 'USD', locale: 'en-US' },
              altValue: { currency: 'CAD', locale: 'fr-CA' },
            },
          },);
// --> The value is $12,345.67 or 16 543,21 $ CA
```

{% endtab %}
{% endtabs %}

For options see: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat>

### DateTime

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// JSON
{
  "intlDateTime": "On the {{val, datetime}}",
}

i18next.t('intlDateTime', { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) });
// --> On the 12/20/2012
i18next.t('intlDateTime',
          {
            val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)),
            formatParams: {
              val: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' },
            },
          });
// --> On the Thursday, December 20, 2012
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// JSON
{
  "intlDateTime": "On the {{val, datetime}}",
}

i18next.t($ => $.intlDateTime, { val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) });
// --> On the 12/20/2012
i18next.t($ => $.intlDateTime,
          {
            val: new Date(Date.UTC(2012, 11, 20, 3, 0, 0)),
            formatParams: {
              val: { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' },
            },
          });
// --> On the Thursday, December 20, 2012
```

{% endtab %}
{% endtabs %}

For options see: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat>

### RelativeTime

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// JSON
{
  "intlRelativeTime": "Lorem {{val, relativetime}}",
  "intlRelativeTimeWithOptions": "Lorem {{val, relativetime(quarter)}}",
  "intlRelativeTimeWithOptionsExplicit": "Lorem {{val, relativetime(range: quarter; style: narrow;)}}",
}

i18next.t('intlRelativeTime', { val: 3 });
// --> Lorem in 3 days
i18next.t('intlRelativeTimeWithOptions', { val: -3 });
// --> Lorem 3 quarters ago
i18next.t('intlRelativeTimeWithOptionsExplicit', { val: -3 });
// --> Lorem 3 qtrs. ago
i18next.t('intlRelativeTimeWithOptionsExplicit', { val: -3, style: 'long' });
// --> Lorem 3 quarters ago
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// JSON
{
  "intlRelativeTime": "Lorem {{val, relativetime}}",
  "intlRelativeTimeWithOptions": "Lorem {{val, relativetime(quarter)}}",
  "intlRelativeTimeWithOptionsExplicit": "Lorem {{val, relativetime(range: quarter; style: narrow;)}}",
}

i18next.t($ => $.intlRelativeTime, { val: 3 });
// --> Lorem in 3 days
i18next.t($ => $.intlRelativeTimeWithOptions, { val: -3 });
// --> Lorem 3 quarters ago
i18next.t($ => $.intlRelativeTimeWithOptionsExplicit, { val: -3 });
// --> Lorem 3 qtrs. ago
i18next.t($ => $.intlRelativeTimeWithOptionsExplicit, { val: -3, style: 'long' });
// --> Lorem 3 quarters ago
```

{% endtab %}
{% endtabs %}

For options see: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat>

### List

{% tabs %}
{% tab title="JavaScript" %}

```javascript
// JSON
{
  "intlList": "A list of {{val, list}}"
}

i18next.t('intlList', { val: ['locize', 'i18next', 'awesomeness'] });
// --> A list of locize, i18next, and awesomeness
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
// JSON
{
  "intlList": "A list of {{val, list}}"
}

i18next.t($ => $.intlList, { val: ['locize', 'i18next', 'awesomeness'] });
// --> A list of locize, i18next, and awesomeness
```

{% endtab %}
{% endtabs %}

For options see: <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/ListFormat>

## Additional options

Prefix/Suffix for interpolation and other options can be overridden in init option:

sample

```javascript
i18next.init({
    interpolation: { ... }
});
```

| option          | default | description                                                         |
| --------------- | ------- | ------------------------------------------------------------------- |
| alwaysFormat    | false   | used to always call the format function for all interpolated values |
| formatSeparator | ','     | used to separate format from interpolation value                    |

While there are a lot of options going with the defaults should get you covered.

## Custom formatter

{% hint style="info" %}
Do you want to create some sort of default formatter, that does not need a specific format to be passed via i18n resources? i18next gets you covered also with that...
{% endhint %}

Create a custom formatter plugin, and pass it to i18next:

{% tabs %}
{% tab title="JavaScript" %}

<pre class="language-javascript"><code class="lang-javascript">const myFormatter = {
  type: 'formatter',
  init(services, backendOptions, i18nextOptions) {}, // of you need some init stuff to be done...
  format(value, format, lng, options) {
    // do whatever you like here... and return the formatted string
    if (!format &#x26;&#x26; value instanceof Date) {
      return value.toUTCString()
    }
  },
  add(name, fc) {
    // handle adding a new format, if you need it
  },
  addCached(name, fc) {
    // handle adding a new cached format, if you need it
  }
}

i18next
<strong>  .use(myFormatter)
</strong>  .init({
    fallbackLng: "en",
    interpolation: {
      alwaysFormat: true // set alwaysFormat to true
    },
    resources: {
      en: {
        translation: {
          testKeyWithoutFormat: 'On the "{val}"',
        }
      }
    }
  });
  
i18next.t("testKeyWithoutFormat", { val: new Date() }) // On the "Mon, 07 Jul 2025 11:44:50 GMT"
</code></pre>

{% endtab %}

{% tab title="TypeScript" %}

<pre class="language-typescript"><code class="lang-typescript">const myFormatter = {
  type: 'formatter',
  init(services, backendOptions, i18nextOptions) {}, // of you need some init stuff to be done...
  format(value, format, lng, options) {
    // do whatever you like here... and return the formatted string
    if (!format &#x26;&#x26; value instanceof Date) {
      return value.toUTCString()
    }
  },
  add(name, fc) {
    // handle adding a new format, if you need it
  },
  addCached(name, fc) {
    // handle adding a new cached format, if you need it
  }
}

i18next
<strong>  .use(myFormatter)
</strong>  .init({
    fallbackLng: "en",
    interpolation: {
      alwaysFormat: true // set alwaysFormat to true
    },
    resources: {
      en: {
        translation: {
          testKeyWithoutFormat: 'On the "{val}"',
        }
      }
    }
  });
  
i18next.t($ => $.testKeyWithoutFormat, { val: new Date() }) // On the "Mon, 07 Jul 2025 11:44:50 GMT"
</code></pre>

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.i18next.com/translation-function/formatting.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
