One project for Android, iOS, web, and every other platform.
Universal placeholders let you translate an app once and ship it to Android, iOS, web, and every other platform from a single Localizely project. Placeholders are stored in one form, {name}, and converted to the syntax of each file format when you upload and download files.
Every platform writes placeholders differently. Android says Hello %1$s, iOS says Hello %1$@, Flutter says Hello {name}, and a web app might say Hello {{name}}. Uploading files from two platforms into one project therefore either overwrites one syntax with the other on every upload, or forces you to keep two copies of the same string key and translate everything twice.
Universal placeholders remove the difference. Translators see and type {name} regardless of the platform, and every platform gets its own syntax back in the files it downloads.
{name}, the syntax of ICU messages.%lld back while Android gets %d.Here is one stored translation and what each download produces from it:
| File format | Translation |
|---|---|
| Stored in Localizely | Hello {name}, you have {count} new messages |
| Android Resources | Hello %1$s, you have %2$d new messages |
| Apple Strings, Stringsdict, and String Catalog | Hello %1$@, you have %2$lld new messages |
| Flutter ARB | Hello {name}, you have {count} new messages |
| Key-Value JSON with i18next syntax | Hello {{name}}, you have {{count}} new messages |
| .NET Resources | Hello {0}, you have {1} new messages |
| Ruby on Rails YAML | Hello %{name}, you have %{count} new messages |
| Gettext PO | Hello %1$s, you have %2$d new messages |
File formats with a fixed placeholder syntax are converted automatically, without any setup:
| File format | Placeholder syntax |
|---|---|
| Android Resources (.xml) | Java printf: %s, %1$s, %d, %.2f |
| Apple Strings (.strings), Stringsdict (.stringsdict), and String Catalog (.xcstrings) | Apple printf: %@, %1$@, %lld, %.2f |
| Flutter ARB (.arb) | ICU: {name}, no conversion needed |
| .NET Resources (.resx) | {0}, {1:F2} |
| Ruby on Rails YAML (.yml) | %{name}, %<count>d |
| Gettext PO (.po, .pot) | C printf: %s, %1$s, %(name)s |
Generic file formats have no placeholder syntax of their own: Key-Value JSON, Java Properties, CSV, Excel, and XLIFF. For these, the syntax is chosen by you. Set the default under Settings, tab Placeholders, as the Placeholder syntax of generic file formats, and override it for a single file with the Placeholder syntax in the file option of the upload and download, or with the placeholder_format parameter of the API, the CLI, and the configuration file. The available syntaxes are Android / Java printf, Apple printf, C / gettext printf, ICU, .NET, Ruby, and i18next. Choose None to leave the text as it is.
Universal placeholders are enabled per project. New projects can switch before the first upload, and existing projects can switch at any time:
A few things to know about the switch:
%@ and {{name}} in one translation, or different syntaxes in different languages. They are left untouched, so check them in the editor after the switch.%d, are read, and that single braces in Android, iOS, Ruby, and i18next text are literal text rather than placeholders.arg1, arg2, and so on. The first main-language upload in a format with named placeholders, for example a Flutter ARB or an i18next JSON file, gives them their real names in every language. You can also rename a placeholder in the editor.{{user.name}}, keeps its token remembered, while the placeholder keeps its automatic name.%d to %lld.%@ for text and %lld for a whole number on iOS.%2$d, when a translation reorders the placeholders or when a placeholder has no token of that platform yet, so that translators can reorder placeholders freely.%% in printf formats when the translation has a placeholder. A literal brace is quoted the ICU way in the stored text, '{' and '}', and written as a plain brace on download.%n or %tY on Android, pass through unchanged.The translation editor has a Placeholders tab for every string key. It lists the placeholders of the key with their type and the token each platform wrote, inserts a placeholder into the translation with one click, renames a placeholder in every language, and shows a live preview of the current translation in the syntax of every platform.
The placeholder consistency QA check compares placeholders between languages in the stored form, so it works the same for every platform. Translation Memory suggestions that come from projects with platform-specific placeholders are shown in the stored form as well, so applying one never brings %1$s into a translation.
Not every string key exists on every platform. Tags decide which keys go into which file:
tag_in_file parameter of the API and the configuration file, with one tag per platform, for example android or ios. The tag is added to every key in the file and removed from keys that are not in it, so keys shared by both platforms carry both tags.include_tags parameter, with the tag of the platform.One repository can hold the files of several platforms. In the configuration file of the GitHub, GitLab, and Bitbucket integrations, and of the CLI, each file can carry its own file_type and tags:
config_version: 1.0
project_id: c776c33e-f428-4c91-87e1-a6a18c1554fe
upload:
files:
- file: android/app/src/main/res/values/strings.xml
locale_code: en
file_type: android_xml
tag_in_file: # Added to every key in this file, removed from keys that are not in it
- android
- file: ios/App/Localizable.xcstrings
file_type: ios_xcstrings
tag_in_file:
- ios
download:
files:
- file: android/app/src/main/res/values/strings.xml
locale_code: en
file_type: android_xml
include_tags: # Only keys with this tag are written to this file
- android
- file: android/app/src/main/res/values-de/strings.xml
locale_code: de
file_type: android_xml
include_tags:
- android
- file: ios/App/Localizable.xcstrings
file_type: ios_xcstrings
include_tags:
- ios%d on Android or %lld on iOS, is mapped to the plural variable of the key, count by default.{name} in an ARB file and {{user}} in a JSON file, get two placeholders. Align the names in the files, or rename the placeholder in the editor.Previous: Supported file formats
Read next: Language & Country Codes
Tired of manually editing translation files?
Our platform streamlines software localization for you.