User Rating 0.0
Total Usage 0 times
Drop .po files here or click to browse Supports multiple files
Is this tool helpful?

Your feedback helps us improve.

About

GNU gettext .po files remain the dominant interchange format for software localization, yet modern front-end stacks consume JSON. A manual conversion introduces encoding errors, drops plural forms, and silently mishandles multiline msgstr continuations. This tool parses the full PO grammar - including msgctxt disambiguation, msgstr[N] plural indices, and escaped sequences (\n, \t, \") - then emits clean JSON or an AMD-wrapped JavaScript module. All parsing runs locally in your browser. No file is uploaded to any server.

Limitations: the converter assumes UTF-8 encoding. Binary .mo files are not supported. Obsolete entries (prefixed with #~) are intentionally excluded from output. Fuzzy-flagged entries (marked #, fuzzy) are included by default but can be excluded via the option toggle. Pro tip: if your PO file uses msgctxt for key namespacing, enable the "Use msgctxt as key" option to avoid collisions between identical msgid values in different contexts.

po to json gettext converter po file parser i18n json translation converter amd module localization tool

Formulas

The converter operates as a line-by-line state machine. Each line is classified by its prefix and the parser transitions between states accordingly.

parse(line)
{
COMMENT if line starts with #MSGCTXT if line starts with msgctxtMSGID if line starts with msgidMSGSTR if line starts with msgstrCONTINUATION if line starts with "

Continuation lines (lines beginning with a double quote) are appended to whichever directive was active in the previous state. The final JSON key is determined by the mode:

key =
{
msgctxt if useMsgctxtAsKey = TRUE msgctxt NULLmsgid otherwise

For plural entries, the value becomes an array:

value =
{
string if single msgstr[msgstr[0], msgstr[1], , msgstr[N]] if plural

Where key is the lookup identifier and value is the translated content. The header entry (empty msgid) is always excluded from output. When AMD wrapping is enabled, the output becomes: define(function() { return JSON ; });

Reference Data

PO DirectivePurposeJSON MappingNotes
msgidSource string (key)Object key (default mode)Empty msgid = file header
msgstrTranslated stringObject value (string)Empty msgstr means untranslated
msgctxtDisambiguation contextUsed as key when option enabledAvoids duplicate msgid collisions
msgid_pluralPlural source stringIgnored (informational)Plural source not needed in output
msgstr[0]Singular translationArray index 0Required when plurals present
msgstr[N]Nth plural formArray index NCount depends on language
# (comment)Translator commentNot included in outputInformational only
#.Extracted commentNot included in outputAuto-generated by xgettext
#:Source referenceNot included in outputFile:line location
#,Flags (e.g., fuzzy)Entry skipped if fuzzy excludedComma-separated flags
#~Obsolete entryAlways excludedDeprecated translations
#|Previous msgidNot included in outputUsed by tools for diffing
\nNewline escapeLiteral newline in valueCommon in multiline strings
\tTab escapeLiteral tab in valueRare but valid
\"Escaped quoteLiteral " in valueRequired inside quoted strings
\\Escaped backslashLiteral \ in valueStandard C escape
Plural-FormsHeader: plural ruleNot included (header entry)e.g., nplurals=3; plural=...
Content-TypeHeader: charsetNot included (header entry)Should be text/plain; charset=UTF-8
LanguageHeader: language codeNot included (header entry)ISO 639-1 code (e.g., fr)

Frequently Asked Questions

PO files allow a directive to span multiple lines. The first line contains the directive keyword followed by an empty string (e.g., msgstr ""), and subsequent lines contain only quoted strings (e.g., "continued text"). The parser detects continuation lines - any line starting with a double quote character while not beginning with a keyword - and appends their unquoted content to the current active directive. Escaped newlines (\n) inside the quoted text are converted to actual newline characters in the JSON output.
In default mode (using msgid as key), the second entry overwrites the first because JSON object keys must be unique. This is a known limitation of flat key-value mapping. Enable the "Use msgctxt as key" option to use the disambiguation context as the JSON key instead, which preserves both entries under their distinct msgctxt values. If msgctxt is absent for an entry in this mode, the converter falls back to msgid.
By default, yes. Fuzzy entries (marked with #, fuzzy in comments) represent translations that need human review but may still be partially correct. The converter provides a toggle to exclude fuzzy entries entirely. When excluded, any entry whose flags contain the word "fuzzy" is omitted from the JSON output. This is useful for production builds where only verified translations should ship.
When a PO entry contains msgid_plural and multiple msgstr[N] directives, the converter produces an array value instead of a string. The array indices correspond to the plural form indices: msgstr[0] becomes index 0, msgstr[1] becomes index 1, and so on. The number of plural forms depends on the target language (e.g., 2 for English, 3 for Polish, 6 for Arabic). The Plural-Forms header directive defines the rule but is not included in the output.
Yes. When you upload multiple PO files, the converter can produce either separate JSON outputs (one per file) or a single merged JSON object where each file's translations are nested under a namespace key derived from the filename. For example, uploading messages.po and errors.po produces {"messages": {...}, "errors": {...}}. This mirrors the grunt-po-json behavior of mapping multiple sources to named properties.
No. The header entry (the entry with an empty msgid) contains metadata like Project-Id-Version, Content-Type, and Plural-Forms. This metadata is parsed internally to detect encoding and plural rules, but it is excluded from the JSON output. The header is not a translation entry and would pollute the key-value map with an empty-string key. If you need the header, enable the "Include header" option which adds it under a __header__ key.