# Catalog Formats

Catalog format (configured by the [`format`](https://lingui.dev/ref/conf.md#format) option) refers to the offline catalog file format. This format is never used in production, because the catalog is compiled into a JS module.

The reason for this build step is that the choice of catalog format depends on the individual internationalization workflow. On the other hand, the runtime catalog should be as simple as possible so that it can be parsed quickly without additional overhead.

## PO[​](#po "Direct link to PO")

PO files are translation files used by [gettext](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html) internationalization system. This is the **recommended** and the **default** catalog format in Lingui.

[![Version](https://img.shields.io/npm/v/@lingui/format-po.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-po) [![Downloads](https://img.shields.io/npm/dw/@lingui/format-po.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-po)

The advantages of this format are:

* readable even for large messages
* supports comments for translators
* supports metadata (origin, flags)
* supports contexts
* standard format supported by many localization tools

### Installation[​](#po-installation "Direct link to Installation")

* npm
* Yarn
* pnpm

```
npm install --save-dev @lingui/format-po
```

```
yarn add --dev @lingui/format-po
```

```
pnpm add --save-dev @lingui/format-po
```

### Usage[​](#po-usage "Direct link to Usage")

lingui.config.{js,ts}

```
import { defineConfig } from "@lingui/cli";

import { formatter } from "@lingui/format-po";



export default defineConfig({

  // [...]

  format: formatter({ lineNumbers: false }),

});
```

### Configuration[​](#po-configuration "Direct link to Configuration")

PO formatter accepts the following options:

| Option                        | Type                            | Default | Description                                                                                                                                                                                                                                                         |
| ----------------------------- | ------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `origins`                     | boolean                         | `true`  | Include comments in the PO file that indicate where each message is used in the source code. This provides additional context during the translation                                                                                                                |
| `lineNumbers`                 | boolean                         | `true`  | Include line numbers in the origin comments. This makes it easier to locate messages in the source code                                                                                                                                                             |
| `printLinguiId`               | boolean                         | `false` | Add a `js-lingui-id: hash` comment to each message in the PO file. This ID is a hash generated by Lingui                                                                                                                                                            |
| `explicitIdAsDefault`         | boolean                         | `false` | Use the `msgid` as is for messages with explicit IDs. The formatter will add the `js-lingui-explicit-id` flag for such strings                                                                                                                                      |
| `customHeaderAttributes`      | `{[key: string]: string}`       | `{}`    | Allows adding custom key-value pairs to the PO file header                                                                                                                                                                                                          |
| `printPlaceholdersInComments` | boolean \| `{ limit?: number }` | `true`  | Print values for unnamed placeholders as comments for each message. This can give translators more context for better translations. By default, the first 3 placeholders are displayed                                                                              |
| `foldLength`                  | number                          | `0`     | Maximum line width before folding long strings. When a string exceeds this length, it will be split across multiple lines. Set to `0` to disable folding (strings will only break on actual newlines)                                                               |
| `compactMultiline`            | boolean                         | `true`  | When `true`, multiline strings start with content on the first line. When `false`, uses GNU gettext's traditional format with an empty first line. The compact format is recommended as it's compatible with translation platforms that may strip empty first lines |

### Examples[​](#po-examples "Direct link to Examples")

```
#: src/App.js:3

#. Comment for translators

msgid "messageId"

msgstr "Translated Message"



#: src/App.js:3

#, obsolete

msgid "obsoleteId"

msgstr "Obsolete Message"
```

Messages with context are exported in the following way:

```
#: src/Inbox.js:12

msgctxt "my context"

msgid "msg.inbox"

msgstr "Message Inbox"
```

Messages with plurals are exported in [ICU MessageFormat](https://lingui.dev/guides/message-format.md):

```
msgid "{count, plural, one {Message} other {Messages}}"

msgstr "{count, plural, one {Message} other {Messages}}"
```

Messages with placeholders:

```
t`Hello ${user.name} ${value}`;
```

are exported as:

```
#. placeholder {0}: user.name

msgid "Hello {0} {value}"

msgstr "Hello {0} {value}"
```

## PO with gettext Plurals[​](#po-gettext "Direct link to PO with gettext Plurals")

When using localization backends that don't understand the ICU plural syntax exported by the default `po` formatter, **po-gettext** can be used to read and write to PO files using gettext-native plurals.

[![Version](https://img.shields.io/npm/v/@lingui/format-po-gettext.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-po-gettext) [![Downloads](https://img.shields.io/npm/dw/@lingui/format-po-gettext.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-po-gettext)

### Installation[​](#po-gettext-installation "Direct link to Installation")

* npm
* Yarn
* pnpm

```
npm install --save-dev @lingui/format-po-gettext
```

```
yarn add --dev @lingui/format-po-gettext
```

```
pnpm add --save-dev @lingui/format-po-gettext
```

### Usage[​](#po-gettext-usage "Direct link to Usage")

lingui.config.{js,ts}

```
import { defineConfig } from "@lingui/cli";

import { formatter } from "@lingui/format-po-gettext";



export default defineConfig({

  // [...]

  format: formatter({ lineNumbers: false }),

});
```

### Configuration[​](#po-gettext-configuration "Direct link to Configuration")

The PO Gettext formatter accepts the following options:

| Option                 | Type    | Default        | Description                                                                                                                                                              |
| ---------------------- | ------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `origins`              | boolean | `true`         | Include comments in the PO file that indicate where each message is used in the source code. This provides additional context during the translation                     |
| `lineNumbers`          | boolean | `true`         | Include line numbers in the origin comments. This makes it easier to locate messages in the source code                                                                  |
| `disableSelectWarning` | boolean | `false`        | Disable warnings about unsupported `Select` features encountered in catalogs. This can be useful if you're aware of the limitation and want to suppress related warnings |
| `customICUPrefix`      | string  | `"js-lingui:"` | Override the default prefix for ICU and plural comments in the final PO catalog                                                                                          |
| `mergePlurals`         | boolean | `false`        | Combine plural entries that have the same content but different variables into a single PO entry                                                                         |
| `foldLength`           | number  | `0`            | Maximum line width before folding long strings. When a string exceeds this length, it will be split across multiple lines. Set to `0` to disable folding                 |
| `compactMultiline`     | boolean | `true`         | When `true`, multiline strings start with content on the first line. When `false`, uses GNU gettext's traditional format with an empty first line                        |

### Examples[​](#po-gettext-examples "Direct link to Examples")

With this format, plural messages are exported in the following ways, depending on whether an explicit ID is set:

* Message **with custom ID "my\_message"** that is pluralized on property "*someCount*".

  ```
  #. js-lingui:pluralize_on=someCount

  msgid "my_message"

  msgid_plural "my_message_plural"

  msgstr[0] "Singular case"

  msgstr[1] "Case number {someCount}"
  ```

  Note that `msgid_plural` was created by appending a `_plural` suffix.

* Message **without custom ID** that is pluralized on property "*anotherCount*".

  To allow matching this PO item to the appropriate catalog entry when deserializing, the original ICU message is also stored in the generated comment.

  ```
  #. js-lingui:icu=%7BanotherCount%2C+plural%2C+one+%7BSingular+case%7D+other+%7BCase+number+%7BanotherCount%7D%7D%7D&pluralize_on=anotherCount

  msgid "Singular case"

  msgid_plural "Case number {anotherCount}"

  msgstr[0] "Singular case"

  msgstr[1] "Case number {anotherCount}"
  ```

  Note how `msgid` and `msgid_plural` were extracted from the original message.

* Message **with a custom comment prefix**.

  Some TMS might modify the ICU comment by attempting to split lines to be 80 characters or less, or have trouble reading lingui comments because of the `js-lingui:` prefix. To change the prefix, set `customICUPrefix` to modify the prefix for ICU comments.

  ```
  # with default prefix

  #. js-

  #. lingui:icu=%7BanotherCount%2C+plural%2C+one+%7BSingular+case%7D+other+%7BCase+number+%7BanotherCount%7D%7D%7D&pluralize_on=anotherCount



  # customICUPrefix = jsi18n:

  #. jsi18n:icu=%7BanotherCount%2C+plural%2C+one+%7BSingular+case%7D+other+%7BCase+number+%7BanotherCount%7D%7D%7D&pluralize_on=anotherCount
  ```

#### Duplicate Plurals[​](#duplicate-plurals "Direct link to Duplicate Plurals")

When two calls to `plural` or `<Plural />` are made with identical strings, but pluralize on different variables, they will create separate PO entries. However, `msgid` will be the same. Some TMS might not allow duplicate `msgid`, even with different comments, and should use `mergePlurals` option to merge these entries into a single PO entry during extraction. During compilation, it will be re-expanded to multiple units.

```
plural(count, {

  one: "one book",

  other: "many books",

});

plural(anotherCount, {

  one: "one book",

  other: "many books",

});
```

Without `mergePlurals`:

```
#. js-lingui:icu={count, plural, one {one book} other {many books}}&pluralize_on=count

msgid "one book"

msgid_plural "many books"

msgstr[0] "one book"

msgstr[1] "many books"



#. js-lingui:icu={anotherCount, plural, one {one book} other {many books}}&pluralize_on=anotherCount

msgid "one book"

msgid_plural "many books"

msgstr[0] "one book"

msgstr[1] "many books"
```

With `mergePlurals`:

```
#. js-lingui:icu={$var, plural, one {one book} other {many books}}&pluralize_on=count,anotherCount

msgid "one book"

msgid_plural "many books"

msgstr[0] "one book"

msgstr[1] "many books"
```

### Limitations[​](#po-gettext-limitations "Direct link to Limitations")

This format comes with several caveats and should only be used when using ICU plurals in PO files is not an option:

* Nested/multiple plurals in a message as shown in [`plural`](https://lingui.dev/ref/macro.md#plural) are not supported because they cannot be expressed with gettext plurals. Messages containing nested/multiple formats will not be output correctly.
* A [`Plural`](https://lingui.dev/ref/macro.md#plural-1) nested inside a [`Trans`](https://lingui.dev/ref/macro.md#trans) (`<Trans>You have <Plural … /></Trans>`) is exported as a single ICU message rather than as `msgid`/`msgid_plural`. Keep the plural as the top-level translation unit; the [`no-plural-inside-trans`](https://github.com/lingui/eslint-plugin/blob/main/docs/rules/no-plural-inside-trans.md) ESLint rule catches this.
* The [`select`](https://lingui.dev/ref/macro.md#select) and [`selectOrdinal`](https://lingui.dev/ref/macro.md#selectordinal) cannot be expressed with gettext plurals, but the original ICU format is still stored in the `msgid`/`msgstr` properties. To disable the warning that this may not be the expected behavior, add `{ disableSelectWarning: true }` to the [`format`](https://lingui.dev/ref/conf.md#format) options.
* Source/development languages with more than two plurals could experience difficulties when no custom IDs are used, as gettext cannot have more than two plurals cases identifying an item (`msgid` and `msgid_plural`).
* Gettext doesn't support plurals for negative and fractional numbers even though some languages have special rules for these cases.

## JSON[​](#json "Direct link to JSON")

This format is used to store messages in a JSON file. There are two types of JSON format: [minimal](#minimal-style) and [lingui](#lingui-style).

[![Version](https://img.shields.io/npm/v/@lingui/format-json.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-json) [![Downloads](https://img.shields.io/npm/dw/@lingui/format-json.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-json)

### Installation[​](#json-installation "Direct link to Installation")

* npm
* Yarn
* pnpm

```
npm install --save-dev @lingui/format-json
```

```
yarn add --dev @lingui/format-json
```

```
pnpm add --save-dev @lingui/format-json
```

### Usage[​](#json-usage "Direct link to Usage")

lingui.config.{js,ts}

```
import { defineConfig } from "@lingui/cli";

import { formatter } from "@lingui/format-json";



export default defineConfig({

  // [...]

  format: formatter({ style: "lingui" }),

});
```

### Configuration[​](#json-configuration "Direct link to Configuration")

JSON formatter accepts the following options:

| Option        | Type                      | Default    | Description                                                                                                                                       |
| ------------- | ------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `style`       | `"lingui"` \| `"minimal"` | `"lingui"` | Specify the output style of the JSON file. `lingui` includes full Lingui-specific metadata, while `minimal` may output a more compact format      |
| `origins`     | boolean                   | `true`     | Include information in the JSON file about where each message is used in the source code. This provides additional context during the translation |
| `lineNumbers` | boolean                   | `true`     | Include line numbers in the origin comments. This makes it easier to locate messages in the source code                                           |
| `indentation` | number                    | `2`        | Set the number of spaces to use for indentation in the output JSON file. This affects the readability of the file when opened in a text editor    |

### Examples[​](#json-examples "Direct link to Examples")

#### Minimal style[​](#minimal-style "Direct link to Minimal style")

A simple JSON file where each key is a message ID and the value is the translation. The JSON is flat, and there's no reason to use nested keys. The usual motivation behind nested JSON is to save file space, but this file format is only used offline.

The downside of this format is that all metadata about the message is lost. This includes the default message, the origin of the message, and any message flags (obsolete, fuzzy, etc.).

```
{

  "messageId": "translation"

}
```

#### Lingui style[​](#lingui-style "Direct link to Lingui style")

This file format simply outputs all internal data in JSON format. It's the original file format used by Lingui before support for other catalog formats was added. It might be useful for tools build on top of Lingui CLI which needs to further process catalog data.

```
{

  "messageId": {

    "translation": "Translated message",

    "message": "Default message",

    "description": "Comment for translators",

    "origin": [["src/App.js", 3]]

  },

  "obsoleteId": {

    "translation": "Obsolete message",

    "origin": [["src/App.js", 3]],

    "obsolete": true

  }

}
```

## CSV[​](#csv "Direct link to CSV")

The CSV format is a simple format that can be used to import and export messages from spreadsheets or other tools that support CSV files. It has two columns: message ID and message (source or translation).

[![Version](https://img.shields.io/npm/v/@lingui/format-csv.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-csv) [![Downloads](https://img.shields.io/npm/dw/@lingui/format-csv.svg?cacheSeconds=86400)](https://www.npmjs.com/package/@lingui/format-csv)

### Installation[​](#csv-installation "Direct link to Installation")

* npm
* Yarn
* pnpm

```
npm install --save-dev @lingui/format-csv
```

```
yarn add --dev @lingui/format-csv
```

```
pnpm add --save-dev @lingui/format-csv
```

### Usage[​](#csv-usage "Direct link to Usage")

lingui.config.{js,ts}

```
import { defineConfig } from "@lingui/cli";

import { formatter } from "@lingui/format-csv";



export default defineConfig({

  // [...]

  format: formatter(),

});
```

This formatter has no configurable options.

### Examples[​](#csv-examples "Direct link to Examples")

```
messageId,Message

msg.common,String for translation
```

## See Also[​](#see-also "Direct link to See Also")

* [Custom Formatter](https://lingui.dev/guides/custom-formatter.md)
