File formats

File formats

Every file format transglot reads and writes, the identifier you use for it in configuration and the API, and how keys, plurals and placeholders map.

transglot reads and writes twenty file formats. Each has an identifier, the string you put in the format field of a CLI rule, in API requests, and in Delivery format for the runtime SDKs.

Formats

FormatIdentifierExtensionsPluralsNested keysDescriptions
JSON (flat)json_flat.jsonNoNoNo
JSON (nested)json_nested.jsonNoYes, split on .No
Laravel JSONlaravel_json.jsonNoNoNo
Laravel PHPlaravel_php.phpNoNoNo
YAMLyaml.yml, .yamlNoYes, split on .No
Flutter ARBflutter_arb.arbYes, ICU plural messagesNoYes
Android XMLandroid_xml.xmlYes, <plurals>NoNo
Apple Stringsios_strings.stringsNoNoNo
Apple Stringsdictios_stringsdict.stringsdictPlural keys onlyNoNo
Apple String Catalogios_xcstrings.xcstringsYesNoYes
XLIFF 1.2xliff_12.xlf, .xliffNoNoYes
XLIFF 2.0xliff_20.xlf, .xliffNoNoNo
gettext POgettext_po.po, .potYes, msgid_pluralNoYes
Unreal POunreal_po.poNoNoYes
Java propertiesjava_properties.propertiesNoNoNo
.NET resxresx.resxNoNoNo
CSVcsv.csvYes, one row per formNoYes
Excelxlsx.xlsxYes, one row per formNoYes
Unity CSVunity_csv.csvNoNoYes
Markdown / MDXmarkdown.md, .mdxNoNot key-basedNo

Descriptions means the file has a place for a note to translators, which becomes the key's description when you import and is written back when you export. In the other formats, keep descriptions in the console.

How a format is chosen

  • CLI and API. Every CLI rule names its format, and the API takes it as a parameter. transglot init proposes one from your files.
  • Browser upload. transglot guesses from the file name and contents, and shows the guess with a control to change it before anything is imported. When it cannot tell, it asks rather than guessing.

The guess uses the extension first, then the contents for extensions several formats share:

  • .json: @@locale means Flutter ARB; sourceLanguage with strings means an Apple String Catalog; any nested object means JSON (nested); a key containing a space means Laravel JSON; otherwise JSON (flat).
  • .xml: <resources> means Android, <root> with <data> means .NET resx, <plist> means Stringsdict.
  • .xlf and .xliff: the version on <xliff>, or the namespace, picks 1.2 or 2.0.

Unity CSV and Unreal PO are never guessed, because their files look like CSV and gettext PO. Choose them explicitly.

One file, one locale

Every format is read and written one locale at a time. A file that holds several languages (an Apple String Catalog, a Unity string table) is read for the locale you are importing, and an export contains that one locale.

Keys

Each format derives key names in its own way, described on its page. Two rules apply everywhere:

  • A key name appears once per file. A duplicate is an error, not a silent overwrite.
  • Nested formats (JSON (nested) and YAML) join nested object keys with . when you import ({"home": {"title": ...}} becomes home.title) and split on . when you export. A project that holds both home and home.title cannot be exported to them, because home would have to be both a string and an object. The export fails and names the colliding keys; publishing in such a format fails with the problem type nested-key-collision. Flat formats keep dots as part of the key.

Plurals

transglot stores a plural key as one form per CLDR plural category of each locale: one and other for English, one, few, many and other for Polish, and so on. See Plural forms.

  • Formats with a plural construct (the ones marked in the table) read and write those forms. A category the file leaves out is stored empty. In most of them, a category the locale does not use, such as few in an English file, is an import error; each format's page says how it handles one.
  • Formats without one cannot carry a plural key. Exporting to them leaves plural keys out and counts them (the X-Skipped-Keys response header on an API pull).
  • In any format, a string can hold an ICU message such as {count, plural, one {# item} other {# items}}. It is stored as an ordinary string and written back unchanged.

Placeholders

Placeholders are read and written exactly as they appear in the file; no format rewrites them. transglot recognizes these syntaxes, and its quality checks flag a translation that loses or alters one:

SyntaxExamples
Double braces{{name}}
Single braces (ICU, .NET, Python, Rails %{name}){name}, {0}, { user.name }
printf%s, %d, %1$s, %.2f, %%
HTML tags<b>, </b>, <a href="...">
Laravel parameters:name, :count

What an export leaves out

An export, a CLI pull, or an API pull contains only translated keys the format can carry. The API's pull response reports each kind of omission in its own header:

HeaderCounts
X-Omitted-Empty-KeysKeys with no translation yet in that locale.
X-Skipped-KeysKeys the format cannot carry, such as plural keys in JSON, or simple keys in Stringsdict.
X-Omitted-Invalid-Icu-KeysOn a project whose message syntax is ICU, translations left out because they are not valid ICU.

The export screen in the console warns before you choose a format that would leave keys out, and blocks one that cannot produce a usable file for the project.

Encoding

Files are read as UTF-8. A leading byte order mark is ignored in the JSON, ARB, String Catalog, Apple Strings, YAML, Java properties, CSV and Unreal PO formats and in the XML-based formats. Other encodings are not supported: convert UTF-16 files (common for older Apple .strings) to UTF-8 first.

On this page