tags: gui, font title: Localization (RTL/LTR) brief: This example demonstrates how to handle localization in games, Unicode text layout, RTL rendering, and runtime font switching for localization. author: The Defold Foundation scripts: main.gui_script, localization_helper.lua, ui_helper.lua
This example demonstrates how to handle localization in games, Unicode text layout, RTL rendering, and runtime font switching for localization.
Click the buttons (EN, AR, PT, JA) to switch between 4 languages.
Arabic demonstrates right-to-left layout, while English/Portuguese/Japanese show left-to-right layout.
The example is intentionally modularized and the flow in the program is linear:
This illustrates a practical localization flow in Defold:
font.add_font() / font.remove_font().font.prewarm_text().To recreate such an example:
Add to your project an App Manifest file with the option Use full font layout system enabled. The rest of the settings doesn't matter for this example, so are left as default.

Use this App Manifest file in the game.project file in the Native Extension section in the App Manifest setting.

Then, also in the game.project file in the Font section enable the Runtime Generation setting.

Project setup used by this example:
game.project with runtime font generation enabled and custom app manifest main.appmanifest.main.collection with:
go with:
ar_proxy - collection proxy component referring to lang_ar.collection file.ja_proxy - collection proxy component referring to lang_ja.collection file.main.gui - GUI component with main.gui_script.The 2 mentioned collections (lang_ar.collection / lang_ja.collection) contain:
go game object with:
label - component with Font property set to noto_ar.font/noto_ja.fontIn the assets folder there are two subfolders:
fonts - containing .ttf font files and .font Defold resources referencing those font files respectivelyimg - containing images and atlas used for GUI nodes.texts - containing .json files with text examples and information about language used.The separate Collections for components with fonts and Collection Proxies to load and unload them are added to show good practices on handling fonts - usually, you only need the one font that user selected in the settings, so rest of the fonts should be unloaded from memory.
Therefore, we have in the example only one font that is defined in the GUI component, that is latin. The rest (Arabic noto_ar and Japanese noto_ja) are loaded using respective Collection Proxy components ar_proxy and ja_proxy.
Those collections contain the game object with component in order to assign there a Font resource - noto_ar and noto_ja.
A Collection Proxy in Defold is a special component that allows you to load and unload entire collections (groups of game objects, components and resources) dynamically at runtime. In this example, proxies are used to manage fonts, so that only the font needed by the user is kept in memory at any time.
Loading a proxy:
ar_proxy for Arabic, ja_proxy for Japanese, etc.).async_load message to the appropriate proxy, and Defold begins loading the target collection (lang_ar.collection, lang_ja.collection, etc.) asynchronously.proxy_loaded message, and can now activate the font for GUI text.Unloading a proxy:
unload message to the relevant proxy.proxy_unloaded message and may proceed to load or activate the next font as needed.lang_ar.collection, lang_ja.collection) constructed?This structure is a Defold best practice: the font is only referenced as long as the proxy is loaded. When the proxy is unloaded, Defold can fully release the font and its memory, keeping the application efficient. This is important for games with large multilingual font files; only the currently active font consumes RAM, even when switching languages at runtime.
The localized text strings are loaded from disk (text_en.json, text_ar.json, text_pt.json, text_ja.json) using sys.load_resource().
The logic is split into two small helpers to keep the GUI script concise and focused on flow:
localization_helper.lua: Handles the language switch flow (load/unload proxies, attach runtime fonts, prewarm glyphs, finalize switch). It owns the small state machine around proxies and fonts and exposes a simple API to the GUI script.ui_helper.lua: Handles GUI node lookup, button states and visuals, LTR/RTL layout changes, and input handling details. It keeps GUI operations in one place so the core localization logic stays easy to follow.This example intentionally trades robustness for clarity:
on_message does not verify which proxy sent proxy_loaded / proxy_unloaded.sys.load_resource() and json.decode(). For larger or frequent loads, caching should be demonstrated in a separate example.languages table is assumed to be correct and complete (including json, layout, proxy, and ttf_hash where required). The JSON is assumed to contain the expected fields (title, text).These choices keep the example readable and focused on the key idea.