What’s covered
- Quick comparison: localization file formats at a glance
- The seven localization file formats: what each one is built for
- How to choose localization file format: a decision framework
- The real problem: most teams don’t use one localization file format
- Key takeaways
- FAQs
Picture a normal Tuesday for a localization team. Engineering exports a fresh batch of en.json from the app. The LSP sends back .xliff files with tracked changes and QA notes baked in. A PM, trying to get quick sign-off from a regional stakeholder, exports a .csv because it opens cleanly in Sheets. None of the three line up. Keys are missing from one, plural forms are handled differently in another, and someone spends an afternoon reconciling them by hand instead of shipping translations.
This is not a tooling failure so much as a format problem. The file format you use shapes how much friction sits inside your localization process, and most teams never actually choose a format. They inherit whatever their tech stack, vendor, or first translator happened to default to.
This post breaks down seven formats you are likely to run into, when each one earns its place, and what to do once you are managing more than one at a time. If you want the broader picture first, [internal link: our guide to software localization] covers the end-to-end process this fits into.
Quick comparison: localization file formats at a glance
Before the details, here is the short version. Use this table as a reference point and come back to it later in the post.
| Format | Typical source | Plural support | Human-editable | Biggest pitfall |
|---|---|---|---|---|
| JSON | Web and JS apps, config files | Depends on library (no native rule) | Yes, but nesting gets messy | No built-in plural syntax, so plural handling is inconsistent across tools |
| XLIFF (.xlf) | LSPs, CAT tools, TMS exports | Yes, standardized in 2.0+ | Only with a CAT tool, not raw | Version mismatches (1.2 vs 2.x) break interoperability |
| CSV | PM exports, quick reviews, spreadsheets | No native support | Yes, very | Commas, quotes, and line breaks inside strings silently corrupt rows |
| YAML | Ruby on Rails, config-heavy apps | No native support | Yes | Whitespace and indentation errors break the whole file |
| PO/POT (gettext) | Open source software, WordPress, Django | Yes, via Plural-Forms header | Yes, with a PO editor | Missing or wrong Plural-Forms header breaks pluralization for the whole file |
| RESX | .NET and Windows apps | No native support | Awkward, XML-heavy | Encoding issues break non-Latin scripts if the file isn't saved as UTF-8 |
| .strings / .stringsdict | iOS and macOS apps | .stringsdict handles plurals, .strings does not | Yes, simple key-value | Easy to desync .strings and .stringsdict for the same key |
The seven localization file formats: what each one is built for
JSON: the developer default
JSON is a lightweight, key-value data format designed for web and JavaScript applications that need string data in a structure the browser or runtime can parse natively. It is the default export for most JavaScript, React, and mobile-adjacent frameworks, and it is where a lot of localization work starts, because it is where the strings already live in the codebase.
- Where it's used: web apps, single-page applications, and most JS-based i18n libraries (i18next, react-intl, and similar).
- The pitfall: JSON has no native plural syntax. Most i18n libraries work around this by mapping onto the Unicode CLDR plural categories, zero, one, two, few, many, and other, the standard set of grammatical plural forms used across languages, but each library implements the mapping with its own key convention (Unicode CLDR, n.d.). i18next, for example, uses key suffixes like
_oneand_other. Plural handling breaks in JSON because the format has no rule of its own, so every library and every contributor fills the gap differently unless the convention is written down. - Verdict: good for web-first teams with a dev-heavy workflow, but you will need a library-specific plural convention layered on top.
XLIFF (.xlf): the industry standard for exchange
XLIFF, the XML Localization Interchange File Format, is an XML-based format maintained by OASIS specifically to let localization tools exchange content without losing metadata. The XLIFF Technical Committee first convened at OASIS in December 2001, and the first fully ratified version, XLIFF 1.2, appeared in February 2008 (Wikipedia, 2026). The specification has continued to evolve since, with version 2.2 released in March 2025, backward compatible with version 2.1 from 2018 (Wikipedia, 2026).
- Where it's used: almost universally in translation management systems, CAT tools, and LSP handoffs. If you work with an agency, XLIFF is often the format they expect.
- The pitfall: not every "XLIFF" file is the same. XLIFF 1.2 and XLIFF 2.x are structurally different, and a tool built for one will often choke on the other. XLIFF interoperability breaks down when the sending and receiving tools assume different versions, because the element structure changed significantly between 1.2 and 2.0.
- Verdict: the closest thing to a non-negotiable format if you work with translation agencies, but confirm the XLIFF version your tools and vendors expect before you build a pipeline around it. If you are still working out how much of this handoff to automate.
XLIFF vs JSON: which one for what
These two come up together often enough to call out directly, since they solve different problems rather than competing for the same job. JSON is best for storing and shipping strings inside a codebase, while XLIFF is best for sending those strings out for translation and getting them back with metadata intact. In practice, a JS-first team usually keeps JSON as the source format and converts to XLIFF only at the point of vendor handoff, rather than trying to make one format cover both jobs.
CSV: the quick-and-dirty reviewer favorite
CSV is a plain-text, tabular format designed for quick data exchange between spreadsheet tools, not for structured localization content. It opens natively in Excel, Sheets, and basically anything, and that is its entire appeal.
- Where it's used: ad hoc reviews, quick stakeholder sign-off, small glossary or terminology exports.
- The pitfall: CSV was never designed for localization content. A string containing a comma, a line break, or an unescaped quote can silently shift every column after it, and the error often is not visible until someone opens the file and finds translations in the wrong row. CSV corrupts easily in localization because the format has no structural safeguard against the exact punctuation that shows up constantly in real, translated sentences.
- Verdict: fine for a quick, low-stakes review pass. Risky as a production format for anything that needs to round-trip back into your codebase.
YAML: the Rails and config-file favorite
YAML is a human-readable data format designed for config-heavy applications, most notably Ruby on Rails, where the same format already handles environment settings, database config, and localization strings side by side. It relies on indentation instead of brackets or tags, which is exactly why it is popular in codebases that also use it for configuration.
- Where it's used: Ruby on Rails i18n, many static site generators, and general app configuration.
- The pitfall: YAML is whitespace-sensitive. A single misplaced space breaks the entire file, because unlike JSON, YAML has no closing bracket to mark where a block should end, so the parser has nothing else to fall back on. Translators editing YAML directly, without a dedicated editor, need to be warned about this specifically.
- Verdict: a natural fit if your stack already uses YAML for config, but only with tooling that validates indentation before it reaches translators.
PO/POT (gettext): the open source standard
PO and POT are two halves of the same format, from the GNU gettext system that WordPress, Django, and a long list of open source projects adopted early and never left. A POT (portable object template) file contains the source strings with empty translation fields. A PO (portable object) file is the same structure with translations filled in for one language, and PO files are typically generated by running the source strings through the POT template (SimpleLocalize, 2025).
- Where it's used: WordPress, Django, and a long list of open source projects that adopted gettext early and never left.
- The pitfall: PO files rely on a
Plural-Formsheader to tell the system how many plural slots a language needs and which rule maps a number to which slot. If that header is missing or wrong for the target language, pluralization breaks across the entire file, not just one string, because every plural entry depends on that single header. - Verdict: solid, mature, and well-supported by CAT tools, but the plural header is a common source of silent bugs. Worth a validation step before any PO file ships.
RESX: the .NET default
RESX is Microsoft’s XML-based resource format, designed for .NET applications that need to externalize strings, images, and other assets from a Windows or ASP.NET codebase into culture-specific files the runtime can load automatically.
- Where it's used: .NET applications, Windows desktop software, older enterprise stacks.
- The pitfall: RESX files are XML and are expected to declare and hold UTF-8 (or UTF-16) encoding to render non-Latin characters correctly (Microsoft Learn, n.d.). When a file that should be UTF-8 gets saved as a different encoding, non-Latin scripts such as Japanese, Korean, Arabic, or Cyrillic render as garbled characters, because the byte sequences no longer map to the right glyphs, an error that tends to surface late, often after a translation has already come back from a vendor.
- Verdict: the expected choice for a .NET stack, but confirm UTF-8 encoding is enforced at every export and import step, not just assumed.
.strings and .stringsdict: Apple’s pair
.strings and .stringsdict are Apple’s paired formats designed specifically for iOS and macOS apps. .strings is a simple key-value format for standard localized text, while .stringsdict is a companion property list format built to define language-specific plural rules that .strings cannot express on its own (Apple Developer Documentation, n.d.).
- Where it's used: iOS and macOS localization, almost exclusively.
- The pitfall: because plurals live in a separate file from the base strings, it is easy for the two to drift out of sync. A string gets added or edited in
.strings, and the corresponding plural entry in.stringsdictgets forgotten, so the app falls back to an ungrammatical default for some languages. - Verdict: required for any Apple platform release. Treat
.stringsand.stringsdictas one unit that always gets updated together, not two separate deliverables.
A quick note on engine-specific exports
Unity and Unreal Engine each have their own string table and export formats for in-game text, and they come with their own set of quirks around variables, rich text tags, and localization IDs. That is a deep enough topic to deserve its own guide rather than a few paragraphs here. Our Unity localization workflow guide and our guide to Unreal Engine localization namespaces cover the engine-specific detail.
How to choose localization file format: a decision framework
There is no universally “best” format. The right one depends on four things.
- By tech stack. Web and JavaScript apps default to JSON. .NET applications default to RESX. iOS defaults to
.stringsand.stringsdict. Rails and other config-heavy frameworks lean YAML. In most cases, the format is already decided by whatever your engineers are building in, not by a deliberate localization decision. - By team composition. A dev-heavy team can work comfortably in raw JSON or YAML. A team with non-technical translators or reviewers needs either a CAT tool sitting on top of the raw format, or a simpler format like CSV for lightweight review passes.
- By vendor or LSP requirements. Translation agencies frequently standardize on XLIFF, because it round-trips cleanly through CAT tools and preserves metadata that other formats drop. If XLIFF is not negotiable for your vendor, it is usually worth building your export pipeline around it rather than fighting it.
- By scale. A single format is manageable when you have one platform and one team. It becomes untenable the moment you add a second platform, a second vendor, or a second contributor group, because each addition tends to bring its own preferred format with it.
- A worked example. Take a mobile game studio shipping to iOS and Android, working with an external LSP. Tech stack points to two formats already,
.strings/.stringsdictfor iOS and whatever the Android build pipeline uses. Team composition adds a non-technical LQA reviewer who needs a simpler view of the strings than raw code files. Vendor requirements bring XLIFF into the mix, since that is what the LSP's CAT tool expects on both delivery and return. By the time all four factors are accounted for, the studio is not running one format, it is running three or four at once, which is exactly the scenario the next section gets into.
The real problem: most teams don’t use one localization file format
Here is the honest version of the story: as a product grows, you stop choosing a format and start managing several at once. A typical mid-size team ends up with JSON from the web app, RESX from an internal admin tool, XLIFF from the translation agency, and a CSV or two floating around from ad hoc reviews.
Multiple formats introduce three specific problems.
- Version drift. The JSON file gets updated with new strings before the XLIFF export catches up, and translators end up working from a stale source.
- Inconsistent terminology across formats. The same term gets translated two different ways because the glossary lives in one system and the CSV reviewer never saw it.
- Manual reconciliation. Someone, usually a PM or a lead translator, spends recurring hours matching strings across formats by hand, which does not scale and is exactly the kind of work that introduces new errors.
What a format-agnostic system actually needs to do is straightforward: import and export any format your team touches, keep a single source of truth regardless of which format content enters or leaves in, and remove the manual reconciliation step entirely. This is the specific problem Gridly is built to solve, letting teams import from JSON, XLIFF, CSV, or other formats into one shared content base instead of stitching formats together by hand.
If your team is already juggling more than two of these, see how our software localization platform handles multiple formats without the manual reconciliation.
Key takeaways
- JSON - web and JS apps. Add a documented plural convention.
- XLIFF - LSP and CAT tool exchange. Confirm the version (1.2 vs 2.x) before you build a pipeline.
- CSV - quick reviews only. Not safe for production round-trips.
- YAML - Rails and config-heavy stacks. Validate indentation before it reaches translators.
- PO/POT - gettext-based open source projects. Check the Plural-Forms header.
- RESX - .NET apps. Enforce UTF-8 encoding at every step.
- .strings / .stringsdict - iOS and macOS. Update both files together, always.
FAQs
What is XLIFF used for in localization?
XLIFF is an XML-based interchange format used to pass localizable content between different tools, most commonly between a source system and a translation agency’s CAT tool, without losing formatting, context, or translation status metadata along the way.
Can JSON handle pluralization?
Not natively. JSON has no built-in plural syntax, so pluralization depends entirely on the i18n library reading the file, and different libraries use different key conventions to represent plural forms.
Is CSV good for localization files?
It works for quick, low-stakes reviews because it is easy to open and edit, but it is risky as a production format. Commas, quotes, or line breaks inside a translated string can silently shift data into the wrong column.
What’s the difference between PO and POT files?
A POT file is a template containing source strings with empty translation fields. A PO file has the same structure with translations filled in for a specific language. POT files generate the initial PO files for each target language.
Why do RESX files break with non-Latin languages?
RESX files can be saved with an incorrect encoding. When a file that should be UTF-8 gets saved differently, characters in scripts like Japanese, Arabic, or Cyrillic no longer map correctly and render as garbled text, an error that often only surfaces after translation.
Author
Quang Pham
Quang has spent the last 5 years as a UX and technical writer, working across both B2C and B2B applications in global markets. His experience translating complex features into clear, user-friendly content has given him a deep appreciation for how localization impacts product success.
When he's not writing, you'll likely find him watching Arsenal matches or cooking.