Files, formats and export
A project’s strings arrive as files and leave as files. This page is about both directions.
Supported formats
Section titled “Supported formats”| Format | Extensions | What is kept |
|---|---|---|
| JSON | .json | Nesting and arrays; i18next plurals (_one, _other…) become one plural segment |
| Flutter ARB | .arb | @key metadata becomes the description and is written back whole; @@locale is not a segment |
| YAML | .yaml, .yml | Nesting, block scalars, a Rails language root (en:), plurals as one:/other: |
| gettext | .po, .pot | Wrapped strings, msgctxt, msgid_plural with msgstr[n], #. comments, fuzzy |
| Android resources | .xml | <string>, <plurals>, <string-array>, translatable="false", comments, markup |
| Apple strings | .strings | Comments as descriptions, escapes, empty values |
| Apple plurals | .stringsdict | One plural variable per key |
| Xcode String Catalog | .xcstrings | Every language of the catalog, comments, states, plural variations |
| XLIFF | .xliff, .xlf | 1.2 and 2.0: resname, notes, maxwidth, translate="no", states |
| CSV | .csv | A header names the columns: key, description, max length, one column per language |
| Markdown | .md, .mdx | One segment per block, edited as Markdown |
The format is taken from the extension, and a file whose extension is not on this list is refused with a message naming the ones that are. A file takes at most 10 MB; a bigger project moves in with a project import.
Nested structures become dotted keys, so this file:
{ "home": { "title": "Hello", "cta": "Start" } }produces the keys home.title and home.cta. That is what your code looks up, and the export writes the file back nested, the way it came in.
A key is unique within its file. auth.json and home.json can both have title; one file cannot have it twice. A gettext entry with a context is keyed as context and text together, so Open in a menu and Open on a door stay two segments.
Uploading
Section titled “Uploading”Uploading a source file creates a segment for every key in it. Uploading the same file again — same name, same folder — is how you push changes:
- A key that already exists has its source text updated.
- A key that is no longer in the file is removed from the project, and comes back with its translations if the file has it again.
- A new key is added.
- The order of the file becomes the order of the segments, so a block inserted in the middle stays in the middle rather than jumping to the end.
- A description, a length limit or a “do not translate” mark the file carries is kept on the segment.
An upload is written whole or not at all.
Importing existing translations
Section titled “Importing existing translations”Upload with a target language set and the file is read as translations rather than as sources: the values are matched to the segments of one file by key and written into that language. That file is the one you pick, or else the one with the same name and folder, the only file with that name, or the one the upload is named after — de.yml finds en.yml, values-de/strings.xml finds values/strings.xml, auth.json.xliff finds auth.json. When none of these settles it, the upload is refused rather than spread across files that share a key.
The status of an imported translation comes from the file when the file has one: an XLIFF unit marked final or approved="yes" arrives approved, a fuzzy gettext entry arrives for review. Without a status, a new translation waits for review. A translation whose text changed goes back to review even if it was approved; the same text never loses its status. Approved words count against the plan, and an upload that would go over the limit is refused as a whole.
This is the path for moving in from another tool — push your source file first, then one file per language, or move the whole project with a project import.
Folders
Section titled “Folders”Files live in folders inside the project, and a file is identified by name and path: locales/en.json and mobile/en.json are two different files.
- Rename a folder and every file under it is moved in one operation.
- Merge duplicates cleans up files with the same name and path that were created twice — a common result of the same file being pushed by two different pipelines before either had a file ID.
Export
Section titled “Export”Export writes approved translations back into a file, in the format and the structure the file was uploaded in: an Android file comes back as Android resources, a Rails YAML under the language you asked for, a nested JSON nested.
| What | Where |
|---|---|
| One file, one language | Files tab → Export, or GET /v1/workspaces/{id}/segments/export?fileId=… |
| Every file in every language as a ZIP | Files tab → Export all, or GET /v1/workspaces/{id}/segments/export-zip |
| Straight into the repository | ownlate pull or a repository integration |
| As a runtime bundle | Releases and OTA |
Without a file, the export merges the whole project into one file of the format you name (json by default). Files are taken in path and name order, and a key that lives in several files takes its value from the last of them.
Plural segments are written in the syntax of the format: i18next suffixes in JSON, msgid_plural in gettext, <plurals> in Android, a variation in .stringsdict and .xcstrings.
Two options change what ends up in the file:
- Source fallback — pass a source language and untranslated keys are written with their source text instead of being omitted. Use it when a missing key would break your app; leave it off when you would rather see the gap.
- Untranslatable segments are always written with their source text, whatever else you asked for.