Skip to content
HexSlate

XLIFF Editor & Viewer

Drop an .xlf file here

Or open one, or paste the XML below. It is read in your browser and never uploaded.

What an .xlf file is, and how to open one

XLIFF is the XML Localisation Interchange File Format, an OASIS standard, and it arrives as a .xlf or .xliff file. It is what a developer hands a translator: one entry per message, each holding the original text and a slot for the translated text, plus whatever the tool that produced it wants to remember. Angular, .NET, iOS, Symfony and every serious CAT tool read and write it, which is why it turns up in an inbox belonging to someone who has never heard of it.

It is XML, so any text editor will show you the file. That is rarely what you want: the words you are looking for sit between tags, wrapped in placeholders, three levels deep. Drop the file on this page and it opens as a list instead, one row per entry, original beside translation. Nothing is installed, nothing is uploaded, and the file is read by your own browser.

Reading and editing are the same screen here. As a viewer, open the file, scan the rows, filter to what is still untranslated, and close the tab: nothing is written unless you download. As an editor, type in the target column and download the file when you are done. The rest of this page is about what happens on that download, because that is where an XLIFF tool usually damages a file.

What this editor changes, and what it leaves alone

Your file is parsed once and kept as a parsed document. When you download, only the <target> elements you actually edited are written back, and the same document is serialised out again. Comments, notes, <context-group> blocks, tool metadata, indentation and elements this editor has never heard of are all still there, because nothing ever visited them.

Some things do move, and all of them are the XML layer rather than this page. A namespace declaration is written before the other attributes on the element carrying it, so <xliff version="1.2" xmlns="…"> can come back with those two the other way round. An attribute this editor sets, such as target-language, is appended after the ones already there. And a line break inside an attribute value comes back as a space: XML 1.0 §3.3.3 requires every conforming parser to normalise it that way, so the document that was read genuinely never had the newline. Angular produces those in the equiv-text hint of a placeholder taken from a multi-line template tag.

Writing the document out normalises seven more things, and a diff will show all of them. CRLF line endings become LF. An empty element loses its closing tag, so <target></target> comes back as <target/>. A character reference is written as the character it names, so &#39; becomes an apostrophe. Attribute values quoted with single quotes are requoted with double ones. A UTF-8 byte order mark is dropped. The file ends with a newline. And a processing instruction ahead of the root element, an <?xml-stylesheet?> for instance, keeps its own text but loses the line break after it, so it ends up on the same line as <xliff>. None of that changes a value, an id or a message, but if your repository stores .xlf files with CRLF endings the whole file will read as rewritten, so commit the download on its own. Everything else in a diff against the original is a translation you wrote.

Units with no <target> at all, which is every unit of a freshly extracted file, get one created after the source, at the file's own indentation. The target language is written to target-language on each <file> in XLIFF 1.2 and to trgLang on the root in 2.0.

Why the target box shows markup

A message is rarely plain text. Angular writes <x id="INTERPOLATION"/> where an expression goes and <x id="START_BOLD_TEXT"/> where a tag opens; XLIFF 2.0 spells the same thing <ph/> and <pc>. Those are not decoration. They are the holes the running application fills, and a translation that loses one is a translation that will not compile.

So the target is edited as the XML it really is, and the placeholders in the source are offered as buttons that insert the original tag verbatim, attributes and all. Every unit is checked as you type: a target whose placeholders do not match its source is flagged, and so is one that is no longer well-formed. The Issues filter collects them.

XLIFF 1.2 and 2.0

Both are read and written. They differ in more than a version number: 1.2 holds the text in <trans-unit> and marks progress with state on the target, from new through needs-translation to translated, signed-off and final. 2.0 wraps everything in a <segment> and keeps the state there, with a shorter vocabulary: initial, translated, reviewed, final. The state picker shows whichever set your file actually allows, and the value is written where that version keeps it.

XLIFF 2.1 and 2.2 open as 2.0. They are additive revisions with the same unit structure and extra optional modules, none of which this editor touches.

Filling a new extraction from an old translation

The common job after adding a feature: messages.xlf has been re-extracted and has no targets, and last release's messages.nl.xlf has hundreds. Open the new file, load the old one with Compare with, and Fill empty targets copies every translation across by unit id.

Units whose source text has changed are skipped rather than filled, and the Source changed filter lists them. A message id is a hash of the message, so in principle changing the English mints a new id and the old translation simply does not match; in practice ids are also carried by hand, aliased and copied between files, and a translation written for a sentence that has since changed is exactly the kind of wrong text that ships unnoticed.

Frequently asked questions

Is my file uploaded anywhere?

No. It is read with the browser's own file API and parsed by the browser's own XML parser, in the page. There is no request, no account and no storage: closing the tab loses the edits, which is the trade for nothing ever leaving the machine.

Why is every target empty after ng extract-i18n?

Because extraction produces a source file, not a translation. Angular writes the messages it found and no targets at all; messages.xlf is the template every messages.<locale>.xlf is made from. Set the target language, translate, and download under the locale name.

The build says a translation is missing. Why?

With i18nMissingTranslation: "error" Angular fails when a message in the source has no unit in the locale file, usually because the file was extracted before the message existed. Re-extract, merge with the file you already have, and the id will be there. An empty <target> is a different failure: it compiles, and ships a blank string.

How do I open an .xlf file?

Drop it on this page, or use the file button. There is nothing to install and no account to make. On a desktop you can also open it in any text editor, since XLIFF is XML, but you will be reading markup rather than sentences. A CAT tool such as memoQ, Trados or Phrase opens one too, and is the right answer when you are translating for a living rather than checking one file.

Is this a viewer or an editor?

Both, and the difference is whether you press download. Opening a file changes nothing on disk, so it works as a plain viewer or reader for checking what a translator delivered, finding one string, or counting what is left. The file you started with is untouched either way.

Can it open .po, .resx or .json?

No. This reads XLIFF, the format Angular, .NET, iOS and most CAT tools exchange. Other formats are a different parser and a different set of rules about what may be lost.

How large a file can it take?

Up to 20 MB, which is far past any real translation file: a few thousand units is normally under a megabyte. Every unit is rendered in the list, and the rows that are off screen cost nothing until you scroll to them.