Drop Locale

PO file translator that runs in your browser

Drop a .po or .pot file in below, pick a target language, download the translated file. The PO file stays on your device.

Loading translator...

How it works

Drop a .po or .pot file on the page, click to choose one, or paste the contents straight in. The parser reads the file in your browser and tells you how many strings still need translation. Auto-detect picks the source language from the PO header (the "Language: xx_XX\n" line). Pick a target language and translation starts immediately. There is no “Go” button because there is nothing else to decide.

Quality Warning

Please don’t rely on the quality of these translations to ship a finalized product. This is just a starting point. It’s machine translation and there are no guarantees about its quality.

What we do not do

The file itself never leaves your device. We do not see what you are translating, we do not store any of the strings, and there is nothing about your file in our logs. The privacy wedge in DropFormat is structural: the PO parser, the Google Translate caller, and the file writer all run inside your browser tab.

What does leave your device: the individual strings go to translate.googleapis.com the same way they would if you pasted them into translate.google.com yourself. We are not in the middle. If your file contains internal product strings you do not want a third party to see, do not translate it here; use an offline tool.

What it supports

msgctxt, msgid_plural, escape sequences, translator comments, file references, and obsolete entries are preserved on the round trip. The legacy hand-rolled parser this tool replaces silently dropped most of those; this one uses the maintained pofile library so you can paste your real production .po and not have a third of its metadata vanish.

Plural forms get N translation slots per the original file’s structure. If your source PO has six Arabic plural forms, the output has six (filled in with the best machine guess we have). Override any of them in the review pane before downloading.

What we tolerate, and what we reject

Some malformed files we repair on the way in. Others we refuse to load so we do not make things worse. This list is the parser’s actual behaviour, generated from the format module itself, not aspirational copy.

Repaired automatically:

  • UTF-8 byte order mark (BOM) at the start of the file
  • Windows (CRLF) or mixed line endings
  • Leading blank lines before the first entry
  • Malformed Plural-Forms header (falls back to nplurals=2)
  • Comments inserted between msgid and msgstr lines
  • Duplicate msgid entries (later one wins; first is flagged)
  • msgctxt declared without a following msgid
  • msgstr[N] plural indices listed out of numeric order
  • Negative or out-of-range msgstr[N] indices
  • Missing PO header block entirely
  • Non-UTF-8 charset declared in the header (we still read as UTF-8)
  • Plural entry missing one or more msgstr forms
  • Trailing whitespace at the end of values
  • File truncated mid-string at the tail
  • Unescaped double quotes inside a msgstr value
  • Unmatched quotation mark in a string

Refused with an explanation:

  • Empty file. Add at least one msgid/msgstr pair and re-upload.
  • Wrong format (looks like HTML, JSON, or XLIFF). Use the /translate/ hub to pick the translator for the file format you have.
  • No translatable entries (no msgid lines). Confirm the file has at least one msgid line, then re-upload.
  • Non-UTF-8 encoding declared (e.g. UTF-16 BOM). Re-save the file as UTF-8 and re-upload.

Common questions

Why is the translation in some cases worse than the Google Translate website? The free endpoint we use is the same one the Google Translate website uses, but the API does not always know about the context the website’s interface provides. For names, branded terms, or jargon, expect to override in the review pane.

What if I am translating something Google’s endpoint will not accept (slang, profanity, code-mixed text)? The free endpoint occasionally returns the source unchanged for content it would rather not translate. Those entries show “kept original” in the review pane so you can hand-translate just those.

Does it cache anything? No. Each run starts fresh. We could cache identical strings across runs to save API calls, but caching in the browser introduces consistency questions and the existing tool’s cache had bugs (see the audit at task c212). Keeping it stateless is simpler and surprises the user less.

What about XLIFF, ARB, .xcstrings, .properties? Each in turn after PO proves itself. The translator hub is intentionally being built one format at a time so the interface is polished before being replicated.

Is there a paid tier? Not yet, and not for PO specifically. If a paid tier ships it is for batch translation across many files, glossary persistence, and side-by-side review with a teammate, not for “more megabytes.” File size has no meaningful limit for text files anyway.

Why this exists

I built this because translating a PO file string by string by hand is tedious, and I could not find a free browser-based tool that did it. POEdit is free to use as a PO editor, but its machine pre-translation feature requires a paid Pro plan. This tool does the same pre-translation step for free, in your browser, with no account required.

What is a PO file?

PO (“portable object”) is the source format for gettext, the i18n system used by WordPress, Drupal, most PHP applications, Python with Babel, Ruby with gettext, and many GTK/Qt desktop applications. Each entry has a msgid (the English source) and a msgstr (the translation), optionally with context, plurals, and references back to the source code line that emitted the string.

You typically generate a .pot template from your source code with xgettext, copy it once per language into a .po file, and ship the .mo (compiled binary) form with the application. PO files are plain UTF-8 text, so they are friendly to diff, merge in pull requests, and edit by hand. They are also exactly the kind of file most “cloud translation services” want you to upload, which is why a browser-only translator makes sense for the wedge cases where uploading the file is what you specifically want to avoid.