Skip to main content

Catalog Formats

Catalog format (configured by the 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 behind this build step is that the choice of catalog format depends on the individual internationalization workflow. On the other hand, runtime catalog should be as simple as possible, so it can be parsed quickly without additional overhead.

PO File (strongly recommended)

PO files are translation files used by gettext internationalization system. This is the recommended and the default catalog format.

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
#: 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"

PO File 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.

This is how the regular PO format exports plurals:

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

With po-gettext, plural messages are exported in the following way, depending on whether an explicit ID is set:

  1. Message with custom ID "my_message" that is pluralized on property "someCount".

Notice that msgid_plural was generated by appending a _plural suffix.

#. js-lingui:pluralize_on=someCount
msgid "my_message"
msgid_plural "my_message_plural"
msgstr[0] "Singular case"
msgstr[1] "Case number {someCount}"
  1. Message without custom ID that is pluralized on property "anotherCount".

Notice how msgid and msgid_plural were extracted from original message.

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 that this format comes with several caveats and should therefore only be used if using ICU plurals in PO files is not an option:

  • Nested/multiple plurals in one message as shown in plural are not supported as it cannot be expressed with gettext plurals. Messages containing nested/multiple formats will not be output correctly.
  • select and selectOrdinal cannot be expressed with gettext plurals, but the original ICU format is still saved to the msgid/msgstr properties. To disable the warning that this might not be the expected behavior, include { disableSelectWarning: true } in the 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 (minimal)

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 (raw)

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


The CSV file with two columns - message ID and message (source or translation):

msg.common,String for translation