Skip to main content
Lokalise universal placeholders

Our internal placeholders are automatically converted to those required by your file format.

Ilya Krukowski avatar
Written by Ilya Krukowski
Updated over 2 months ago

We recommend storing all your platform keys (e.g., web and mobile) in the same project to avoid duplicate translations. However, different platforms often require placeholders in different formats, which can be a challenge. To address this, we’ve introduced Lokalise universal placeholders.

You might also want to explore custom placeholders for more advanced customization.

Introduction

The idea behind Lokalise universal placeholders is simple: all your placeholders can be stored in a universal format within Lokalise, so you don’t need to worry about platform differences. When exporting translations, these universal placeholders are automatically replaced with platform-specific formats.

Additionally, when uploading a translation file, Lokalise can detect platform-specific placeholders and convert them to the universal format.


Lokalise placeholders

Universal placeholders

You can use the following universal placeholders on Lokalise to represent various data types:

  • [%s], [%1$s], [%s:name]  — string

  • [%i], [%1$i], [%i:name]  — integer

  • [%f], [%.2f], [%1$.2f], [%.2f:name]  — float

The :name postfix is used in formats that support named placeholders and will be ignored in others.

Special placeholders

Lokalise also supports the following special placeholders:

  • [%] — exported as %% for printf and iOS placeholder formats if the string contains at least one placeholder; otherwise, it is exported as %.

  • [VOID] — represents an absent translation, exported as an empty string but counted as "translated" on Lokalise.

  • [TRUE], [FALSE] — exported as platform-specific boolean values.

[VOID], [TRUE], and [FALSE] placeholders should be the only text in a given translation. For example, writing "This sentence is [FALSE]" is incorrect usage of the [FALSE] placeholder and will be exported as plain text.

Reference placeholder

[%key_id:key_id%]  represents key referencing. Please find more information in the Key referencing article.


Universal placeholders usage

Sample files

Suppose you have a mobile and web version of an app with two English translation files:

en.json (Web)

{
"your_order": "Here's your order, {{name}}!"
}

en.xml (Android)

<?xml version="1.0" encoding="UTF-8"?>
<resources>
<string name="your_order">Here's your order, %s!</string>
</resources>

These files use different placeholder formats ({{name}} for Web and %s for Android).

Understanding the problem

If you upload these files without enabling any special options, Lokalise will merge keys with identical names into a single entry. The problem here is that one of the translation values will be lost because it’s not possible to have multiple translations for the same language within a single key. Losing one of the translations also means losing the corresponding platform-specific placeholder.

One way to avoid this issue is to enable the Differentiate keys by file option. This option prevents keys from being merged into a single entry; instead, they will be assigned to different filenames, preserving both keys. However, this solution comes with a drawback: you’ll end up with two nearly identical texts that need to be translated separately, doubling the work.

Importing translation files with placeholders

A better approach is to enable the Convert to universal placeholders option. This feature automatically converts all platform-specific placeholders into universal ones during the import process:

Once you’ve enabled this option, press Import files and return to the editor. Here’s the result:

As shown, the platform-specific placeholder has been successfully replaced with a universal placeholder. You can also choose to display all placeholders as blocks, as explained in the corresponding article.

With this method, you now have a single translation key that links both the Web and Android platforms to the JSON and XML files. This approach eliminates the need to translate the same text twice, while ensuring that the placeholder is correctly maintained for each platform.

Downloading translation files and replacing with platform-specific placeholders

When you're ready to export your translations, head over to the Download page. Start by selecting the export format, such as Android Resources (XML) or JSON:

Next, in the Advanced settings section, choose the appropriate Placeholder format:

Finally, click Build and download or Preview to generate your files. Here’s what the output will look like:

As you can see, the universal placeholder was successfully replaced with the platform-specific placeholder (e.g., {{name}}). This process ensures that your placeholders are correctly formatted for the chosen platform.

The same outcome can be achieved when downloading your files using the API.


Platform-specific placeholder formats

Suppose you have the following string using Lokalise universal placeholders: My name is [%s:name]. I have [%.2f] dollars. Here’s how these universal placeholders are replaced with platform-specific ones across different formats:

  • Printf-style placeholders:
    My name is %s. I have %.2f dollars.
    %i is converted to %d. Other placeholders remain unchanged.

  • iOS-style placeholders:
    My name is %@. I have %.2f dollars.
    %s is converted to %@, and %i is converted to %li (%li is used to support both 32- and 64-bit integers). Other placeholders remain unchanged.

  • ICU Message Format placeholders:
    My name is {name}. I have {0} dollars.
    Placeholders with names are exported as {name}. Other placeholders are exported as {n}, where n is the positional index of the placeholder. In ICU plurals, the placeholder with a positional index of 1 will be exported as #.

  • .NET placeholder format:
    My name is {0}. I have {0:0.00} dollars.

  • Symfony placeholder format:
    My name is %name%. I have %placeholder_1% dollars.
    Unnamed placeholders are exported as placeholder_n, where n is the positional index.

  • i18n format:
    Commonly used in various tools and frameworks, such as JavaScript-based i18n solutions:
    My name is {{name}}. I have {{0}} dollars.

  • Raw format:
    No formatting is applied. Placeholders are exported exactly as they are.

Did this answer your question?