KINTO Tech Blog
Localization

Managing Dynamic Placeholders in Multilingual Content: A Non-Developers Guide

Cover Image for Managing Dynamic Placeholders in Multilingual Content: A Non-Developers Guide

Introduction

Handling variables like URLs, dates, or times in translatable sentences is a common challenge in localization. The position or format of these can vary significantly depending on the language, making it tricky to manage strings across languages, especially if you are managing multiple languages at the same time.
Hello! I’m Maya and I lead localization at KINTO Technologies. This article is for anyone managing multilingual content in-house in several languages without a coding background but would like to create a lean mechanism alongside their development colleagues. Don't worry if you're not familiar with coding; while having direct access to colleagues who can assist with implementation would be ideal, there are many resources available online to support you in managing your source language and translation data cohesively with your engineering team. In our case, we use Lokalise as our TMS and source of truth, integrated with GitHub to keep translation data and development in sync.

Why This Matters

For localization specialists, understanding how to use dynamic placeholders like URLs or dates can streamline your workflow and close the gap in communication between dev and localization teams. Shoutout to our teammate Wen-san for explaining this method in a beginner-friendly way!
In my case, since we implemented this approach, we’ve significantly reduced manual string adjustments, especially for placeholder-heavy sentences like terms and conditions and date/time formats. Internal rework due to these issues dropped from about 5 reports per month to nearly zero. We not only saved time but also minimized QA back-and-forth and improved trust between localization and development teams.

The Problem

Let’s take a sample sentence in English with two URLs:
"By using our service, you agree to our Terms and Conditions and Privacy Policy."
In Japanese, the URLs will be placed in a different position relative to the English one:
"本サービスを利用することにより、利用規約 および プライバシーポリシー に同意したものとみなされます。
If we had a third language, especially the more it differs from the above two, the position may again be different. If you’re handling multiple languages, managing these differences manually can be very time-consuming and error-prone.

The Solution: formatString()

Here’s where this function can be a lifesaver. It allows us to create a flexible template where the URLs can be placed dynamically, depending on the language. You can adjust the placement of the URLs in a sentence without having to rewrite the entire sentence for each language.
The tedious alternative many teams still face is hardcoding the URLs directly into each localized string, which leads to manually having to recreate near-identical sentence variants with cluttered string files, a higher risk of typos or broken links, and painful maintenance when URLs change.
This article introduces one solution to this issue using JavaScript as an example, but it can also be expressed in other programming languages such as Phython, C# or PHP.

Step 1: Identify the Dynamic Elements in Your Sentence

Let’s start with the previous sample sentence in English, our base language in this example:
"By using our service, you agree to our {Terms and Conditions} and {Privacy Policy}."
The placeholders {Terms and Conditions} and {Privacy Policy} represent URLs. While their content and placement will vary by language, they must remain clickable. Because sentence structures can differ across languages, these placeholders should be handled dynamically to fit each language's syntax.

Step 2: Create the Translatable String with Placeholders

In your i18n file in key-value format, you’ll define the placeholders that will be replaced by URLs. Using names ones instead of symbols ensures clarity and will prevent errors:
{
"terms_and_privacy": "By using our service, you agree to our {terms} and {privacy}."
}
Here I have renamed them simplified as {terms} and {privacy} to avoid issues in code. Best practice is to use simple, descriptive keys in snake_case or camelCase.

Step 3: Define the URLs and Anchor Texts Per Language

Now, define not just the URLs, but also the translated anchor texts. You’ll need to handle these separately for each language.
For English:
const en = {
terms: '<a href="https://example.com/terms_en">Terms and Conditions</a>',
privacy: '<a href="https://example.com/privacy_en">Privacy Policy</a>'
};
For Japanese:
const ja = {
terms: '<a href="https://example.com/terms_ja">利用規約</a>',
privacy: '<a href="https://example.com/privacy_ja">プライバシーポリシー</a>',
};

This gives flexibility, ensuring that both the anchor text and links are localized and reusable.

Step 4: Use the format() Function for Dynamic Replacement

Now comes the key step: using the format() method to replace the placeholders with the actual URLs.
While JavaScript doesn’t have a built-in method like some other languages such as Python, we can define our own formatting function to replace placeholders dynamically like this:

String.prototype.format = function (replacements) {
return this.replace(/{(\w+)}/g, (match, key) =>
typeof replacements[key] !== 'undefined' ? replacements[key] : match
);
};

// Example of localized string from i18n file
const localizedString = i18n.t('terms_and_privacy');

// Example for English
const formattedStringEn = localizedString.format(en);
console.log(formattedStringEn);
// Output: By using our service, you agree to our <a href="https://example.com/terms_en">Terms and Conditions</a> and <a href="https://example.com/privacy_en">Privacy Policy</a>.

// Example for Japanese
const formattedStringJa = localizedString.format(ja);
console.log(formattedStringJa);
// Output: 本サービスを利用することにより<a href="https://example.com/terms_ja">利用規約</a>および<a href="https://example.com/privacy_ja">プライバシーポリシー</a>に同意したものとみなされます。

The format() function searches for placeholders in curly braces, like {terms} or {privacy}, and replaces them with the corresponding values from the urls object.
Note for developers: you will see that I have inserted raw HTML into the strings, just for visual aid and demonstration purposes. In a production app, always sanitize them to prevent injection.

Final Thoughts

Combining placeholder-based translation strings with dynamic formatting gives you flexibility and control. It keeps your source clean and helps avoid many technical issues as well as human errors.
There are different placeholders, depending on the language, framework, or the type of argument they represent. While the Microsoft internationalization guidelines suggest giving translators control over placeholder naming, the key I think here is ensuring that developers and translators share a clear understanding of what each placeholder signifies.
To quote an example from their guidelines, to express Available Monday to Friday, from 8 AM to 5 PM Central Time, the first version will be easier to understand than the second one:
Available {firstWeekDay} to {lastWeekDay}, from {startTime} to {endTime} {timeZone}.
vs.
Available %s to %s, from %s to %s %s.
To wrap up, here’s a quote I like from Microsoft:
When working on any software project, it's important to think about internationalization from the very beginning of its design. Your first iteration or release may not be translated into another language, but the decisions that you make early in the project can determine your ability to deliver to other markets later. […] It's important to ensure all our features are world-ready.

Facebook

関連記事 | Related Posts

We are hiring!

【フロントエンドエンジニア(リードクラス)】プロジェクト推進G/東京

配属グループについて▶新サービス開発部 プロジェクト推進グループ 中古車サブスク開発チームTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 中古車 』のWebサイトの開発、運用を中心に、その他サービスの開発、運用も行っています。“とりあえずやってみる”から始まる開発文化。

【PjM】プロジェクト推進G/東京

新サービス開発部 プロジェクト推進グループについてプロジェクト推進グループでは、​クルマのサブスクリプションサービスである『 KINTO ONE 』をはじめ、国内向けサービスのプロジェクト計画立案からリリース、運用保守に至るまでのプロジェクト管理を行っています。

イベント情報