{"id":13440,"date":"2021-02-10T22:38:43","date_gmt":"2021-02-10T20:38:43","guid":{"rendered":"https:\/\/phrase.com\/blog\/?p=13440"},"modified":"2023-09-26T11:40:19","modified_gmt":"2023-09-26T09:40:19","slug":"localizing-unity-games-official-localization-package","status":"publish","type":"post","link":"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/","title":{"rendered":"Localizing Unity Games Step by Step"},"content":{"rendered":"<p>Unity is <a href=\"https:\/\/www.statista.com\/statistics\/321059\/game-engines-used-by-video-game-developers-uk\/\">arguably one of the most popular<\/a> off-the-shelf engines for independent game developers. Breakout indies like <a href=\"https:\/\/en.wikipedia.org\/wiki\/Cuphead\">Cuphead<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Overcooked\">Overcooked<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hollow_Knight\">Hollow Knight<\/a>, <a href=\"https:\/\/en.wikipedia.org\/wiki\/Ori_and_the_Blind_Forest\">Ori and the Blind Forest<\/a>, and <a href=\"https:\/\/en.wikipedia.org\/wiki\/Monument_Valley_(video_game)\">Monument Valley<\/a> all have Unity at the heart of their technology. Even some AAA goliaths like Blizzard\u2019s <a href=\"https:\/\/en.wikipedia.org\/wiki\/Hearthstone\">Hearthstone<\/a> are made with the engine.<br \/>\n\ud83d\uddd2\u00a0<em>Note \u00bb<\/em> Have you heard of the no-strings-attached alternative to Unity, Godot? Here&#8217;s <a href=\"https:\/\/phrase.com\/blog\/posts\/godot-game-localization\/\">how to go about game localization in Godot<\/a>.<br \/>\nIf you\u2019re making commercial games with Unity, and have been kind enough to land on our little article here, you\u2019re probably looking at expanding your game\u2019s global reach through internationalization (i18n) and localization (l10n). So how do you go about internationalizing and localizing a Unity game?<br \/>\nYou could roll your own solution, use an open-source library, or maybe pay for a package from the Unity Asset Store. Another option: the good people at Unity Technologies have been hard at work on a <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/index.html\">first-party localization package<\/a>. It\u2019s in preview as we write this, but it\u2019s <a href=\"https:\/\/forum.unity.com\/threads\/any-idea-on-rough-release-dates.1051058\/#post-6797840\">not far from being released<\/a> according to the Unity team, so we think it\u2019s one to consider.<br \/>\nIn this article, we\u2019ll go through how to use the official Unity package to localize our games. We\u2019ll build a small demo, primarily focused on UI and text, and proceed to install, set up, and utilize the package to localize this demo.<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_69_1 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Overview<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#our-demo-project\" title=\"Our Demo Project\">Our Demo Project<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#versions-of-unity-packages-used\" title=\"Versions of Unity &amp; Packages Used\">Versions of Unity &amp; Packages Used<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#a-note-on-addressables\" title=\"A Note On Addressables\">A Note On Addressables<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#installation-and-setup\" title=\"Installation and Setup\">Installation and Setup<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#creating-the-localization-settings-asset\" title=\"Creating the Localization Settings Asset\">Creating the Localization Settings Asset<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#adding-supported-locales\" title=\"Adding Supported Locales\">Adding Supported Locales<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#active-locale-resolution\" title=\"Active Locale Resolution\">Active Locale Resolution<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#setting-the-default-locale\" title=\"Setting the Default Locale\">Setting the Default Locale<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#managing-translations\" title=\"Managing Translations\">Managing Translations<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#creating-a-strings-table-collection\" title=\"Creating a Strings Table Collection\">Creating a Strings Table Collection<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#adding-translated-strings\" title=\"Adding Translated Strings\">Adding Translated Strings<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#right-to-left-text\" title=\"Right-to-Left Text\">Right-to-Left Text<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#installing-rtl-text-mesh-pro\" title=\"Installing RTL Text Mesh Pro\">Installing RTL Text Mesh Pro<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#the-rtl-text-mesh-pro-component\" title=\"The RTL Text Mesh Pro Component\">The RTL Text Mesh Pro Component<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#localizing-textmesh-pro-text\" title=\"Localizing TextMesh Pro Text\">Localizing TextMesh Pro Text<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#interpolation\" title=\"Interpolation\">Interpolation<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#plurals\" title=\"Plurals\">Plurals<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#number-formatting\" title=\"Number Formatting\">Number Formatting<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#date-formatting\" title=\"Date Formatting\">Date Formatting<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#global-variables\" title=\"Global Variables\">Global Variables<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#creating-a-global-variables-group\" title=\"Creating a Global Variables Group\">Creating a Global Variables Group<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#adding-global-variables-to-localization-settings\" title=\"Adding Global Variables to Localization Settings\">Adding Global Variables to Localization Settings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-23\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#using-global-variables-in-translation-strings\" title=\"Using Global Variables in Translation Strings\">Using Global Variables in Translation Strings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-24\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#updating-global-variables-from-scripts\" title=\"Updating Global Variables from Scripts\">Updating Global Variables from Scripts<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-25\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#accessing-localized-strings-from-scripts\" title=\"Accessing Localized Strings from Scripts\">Accessing Localized Strings from Scripts<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-26\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#interpolating-values-in-scripts\" title=\"Interpolating Values in Scripts\">Interpolating Values in Scripts<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-27\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#previewing-building\" title=\"Previewing &amp; Building\">Previewing &amp; Building<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-28\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#fallback\" title=\"Fallback\">Fallback<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-29\" href=\"https:\/\/phrase.com\/blog\/posts\/localizing-unity-games-official-localization-package\/#gg-wp\" title=\"GG WP\">GG WP<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"our-demo-project\"><\/span>Our Demo Project<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Our demo starts with some UI that represents some messages we might typically display in a game.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13445 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-demo-ui-before-i18n.png\" alt=\"Demo project game UI | Phrase\" width=\"1016\" height=\"952\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-demo-ui-before-i18n.png 1016w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-demo-ui-before-i18n-300x281.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-demo-ui-before-i18n-768x720.png 768w\" sizes=\"(max-width: 1016px) 100vw, 1016px\" \/><br \/>\nHere\u2019s a look at our hierarchy. Nothing too crazy going on here: we\u2019re using TextMeshPro (TMP) for our text UI rendering.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13446 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-hierarchy-before-i18n.png\" alt=\"Demo project hierarchy | Phrase\" width=\"404\" height=\"652\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-hierarchy-before-i18n.png 404w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-hierarchy-before-i18n-186x300.png 186w\" sizes=\"(max-width: 404px) 100vw, 404px\" \/><\/p>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> Grab <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\">the Unity project<\/a> from our GitHub repo. The <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\/tree\/start\">start branch<\/a> has the demo as it is here, before localizing. The <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\">main branch<\/a> has the completed project after localization.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"versions-of-unity-packages-used\"><\/span>Versions of Unity &amp; Packages Used<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Here are the versions of Unity and packages we\u2019re using in this article:<\/p>\n<ul>\n<li>Unity 2019.4.21f1<\/li>\n<li><a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/index.html\">Localization 0.10.0-preview<\/a> (official Unity i18n package)<\/li>\n<li><a href=\"https:\/\/github.com\/pnarimani\"><span style=\"font-weight: 400;\">Peyman Narimani<\/span><\/a>\u2019s <a href=\"https:\/\/github.com\/mnarimani\/RTLTMPro\">RTL Text Mesh Pro<\/a> 3.3.1 (for right-to-left rendering of TMPro components)<\/li>\n<\/ul>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> We\u2019re using the <a href=\"https:\/\/mounirtohami.itch.io\/pixel-art-gui-elements\">Pixel Art GUI Elements<\/a> provided by the talented <a href=\"https:\/\/mounirtohami.itch.io\/\">Mounir Tohami<\/a>. Two Google Fonts are utilized in our project as well: <a href=\"https:\/\/fonts.google.com\/specimen\/Jost?sort=date&amp;preview.text_type=custom\">Jost<\/a> for Latin alphabets (English and French) and <a href=\"https:\/\/fonts.google.com\/specimen\/Cairo?sort=date&amp;preview.text_type=custom&amp;query=cairo\">Cairo<\/a> for Arabic.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"a-note-on-addressables\"><\/span>A Note On Addressables<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>The Unity localization package is built on <a href=\"https:\/\/docs.unity3d.com\/Manual\/com.unity.addressables.html\">Addressables<\/a>, a system that allows us to load assets asynchronously, locally or from the network. Covering addressables is a bit outside the scope of this guide, and the localization package is designed so we don\u2019t need to understand addressables fully before we start localizing. In those cases where we need to interact with the addressable system directly, we\u2019ll be sure to mention it.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"installation-and-setup\"><\/span>Installation and Setup<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Ok, let\u2019s install the localization package. In Unity\u2019s main menu, we\u2019ll go to <em>Window \u279e Package Manager<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13447 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager.png\" alt=\"Unity Main Window Package Manager | Phrase\" width=\"2152\" height=\"1530\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager.png 2152w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager-300x213.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager-1024x728.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager-768x546.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager-1536x1092.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-package-manager-2048x1456.png 2048w\" sizes=\"(max-width: 2152px) 100vw, 2152px\" \/><br \/>\nYou\u2019ll be utterly shocked to realize that this opens the <em>Package Manager<\/em> window. On this window, let\u2019s click the plus sign and select <em>Add package from git URL<\/em>. In the ensuing text field, we\u2019ll enter <code>com.unity.localization<\/code> and click the <em>Add<\/em> button to install the package.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13448 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-i18n-package.png\" alt=\"Package Manager URL Window | Phrase\" width=\"641\" height=\"185\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-i18n-package.png 641w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-i18n-package-300x87.png 300w\" sizes=\"(max-width: 641px) 100vw, 641px\" \/><\/p>\n<h3><span class=\"ez-toc-section\" id=\"creating-the-localization-settings-asset\"><\/span>Creating the Localization Settings Asset<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Once the package is installed we\u2019ll need to create our project\u2019s localization settings. We can do this by navigating to <em>Edit \u279e Project Settings \u279e Localization<\/em> and clicking the <em>Create<\/em> button.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13449 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings.png\" alt=\"Localization Project Settings | Phrase\" width=\"1738\" height=\"782\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings.png 1738w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings-300x135.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings-1024x461.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings-768x346.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-localization-settings-1536x691.png 1536w\" sizes=\"(max-width: 1738px) 100vw, 1738px\" \/><br \/>\nThis will both create the settings asset and activate it in our project. If you\u2019re organizing your Unity project by asset type, you might want to create a <code>Localization<\/code> folder to keep your settings assets file, as well as future localization assets we\u2019ll be creating.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"adding-supported-locales\"><\/span>Adding Supported Locales<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Let\u2019s generate the locales our game will support. We can always change this later, but for now, we\u2019ll support Arabic (ar), English (en), and French (fr). After making sure we\u2019re at the <em>Edit \u279e Project Settings \u279e Localization<\/em> window, we can click the <em>Locale Generator<\/em> button to create our locale assets.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13450 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn.png\" alt=\"Locale Generator\" width=\"1722\" height=\"1128\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn.png 1722w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn-300x197.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn-1024x671.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn-768x503.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-btn-1536x1006.png 1536w\" sizes=\"(max-width: 1722px) 100vw, 1722px\" \/><br \/>\nWe\u2019ll be presented with a list of locales; we can check the ones we want to support and click <em>Generate<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13451 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-window.png\" alt=\"Selected Locales | Phrase\" width=\"1092\" height=\"1238\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-window.png 1092w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-window-265x300.png 265w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-window-903x1024.png 903w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-generator-window-768x871.png 768w\" sizes=\"(max-width: 1092px) 100vw, 1092px\" \/><br \/>\nThis will create locale assets for us, which we can place in our <code>Localization<\/code> folder.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"active-locale-resolution\"><\/span>Active Locale Resolution<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The localization package will attempt to resolve the active locale at runtime depending on the <em>Locale Selectors<\/em> order in our <em>Localization Settings<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13452 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-selectors.png\" alt=\"Locale Selectors | Phrase\" width=\"826\" height=\"222\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-selectors.png 826w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-selectors-300x81.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-locale-selectors-768x206.png 768w\" sizes=\"(max-width: 826px) 100vw, 826px\" \/><br \/>\nBy default, the package will:<\/p>\n<ol>\n<li>look for a locale specified with a command-line flag (this could be useful for automated testing, for example), and if that fails<\/li>\n<li>attempt to determine the operating system locale (<em>System Locale<\/em>) and use that, and if that fails<\/li>\n<li>use an explicitly-set locale, which we need to provide as our default locale.<\/li>\n<\/ol>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> The package will fall back on more generalized locales if it needs to. For example, if the locale resolution settles on <code>en-CA<\/code> (Canadian English) as the active locale, and doesn\u2019t find that exact locale in the list of supported locales, it will attempt to fall back to the more general <code>en<\/code> if <code>en<\/code> is supported.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"setting-the-default-locale\"><\/span>Setting the Default Locale<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>We can specify the default locale the package will use when it can\u2019t determine the locale another way by going expanding the <em>Specific Locale Selector<\/em> section under <em>Locale Selectors<\/em>. From there, we can click the search target circle at the end of the <em>Locale Id<\/em> field and select one of our supported locales.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13453 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale.png\" alt=\"Default Locale Setup | Phrase\" width=\"1796\" height=\"1318\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale.png 1796w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale-300x220.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale-1024x751.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale-768x564.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-select-default-locale-1536x1127.png 1536w\" sizes=\"(max-width: 1796px) 100vw, 1796px\" \/><br \/>\nWe\u2019ll select English for our project. Now, if all other locale-resolution strategies fail, our game will default to English as the default runtime locale.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> You can alter the order of the resolution strategies by dragging their rows in the <em>Localization Settings<\/em> window. We&#8217;ll use this later to force a default locale instead of using the one set in the user\u2019s operating system when testing our production builds.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"managing-translations\"><\/span>Managing Translations<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The official localization package will have us creating string table collections and populating them with translatable strings that we can then use in our components.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"creating-a-strings-table-collection\"><\/span>Creating a Strings Table Collection<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>To create a new collection, we can go to <em>Window \u279e Asset Management \u279e Localization Tables<\/em> and click the <em>New Table Collection<\/em> button.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13454 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection.png\" alt=\"Strings Table Collection | Phrase\" width=\"1892\" height=\"1334\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection.png 1892w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection-300x212.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection-1024x722.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection-768x541.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-create-string-table-collection-1536x1083.png 1536w\" sizes=\"(max-width: 1892px) 100vw, 1892px\" \/><br \/>\nAfter selecting which locales will be covered by the table, we can give our table a name and click <em>Create String Table Collection<\/em>. I\u2019ve called my table <code>UI<\/code> and, when prompted, opted to save it under <code>Localizations\/Table Collections\/UI<\/code>. A handful of files related to this table will now live in that folder.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> You may have noticed a <em>Create Asset Table Collection<\/em> button on the <em>Localization Tables<\/em> window. This is because the official localization package can localize not only strings, but textures, audio, ScriptableObjects, and more. Check out the official <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/QuickStartGuide.html\">Quick Start Guide<\/a> for more info.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"adding-translated-strings\"><\/span>Adding Translated Strings<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>With our strings table collection in place, we can now start adding our translations to it.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13455 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key.png\" alt=\"Adding Translated Strings | Phrase\" width=\"1892\" height=\"1334\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key.png 1892w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-300x212.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1024x722.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-768x541.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1536x1083.png 1536w\" sizes=\"(max-width: 1892px) 100vw, 1892px\" \/><br \/>\nClicking <em>Add New Entry<\/em> creates a new row in our table. We should give our row a <code>Key<\/code>, which we\u2019ll use to refer to this entry in our components. And we can add a translation string for each of our supported locales.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> You can open localized table collections at any time by going to <em>Window \u279e Asset Management \u279e Localization Tables<\/em>.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"right-to-left-text\"><\/span>Right-to-Left Text<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Before we go further, I want to make a short stop and tackle right-to-left (RTL) text rendering using TextMeshPro in Unity. TMP currently has no official support for RTL. The Unity team are working on it, but in the meantime, we have to use third-party packages for RTL rendering. I\u2019ve opted to use <a href=\"https:\/\/github.com\/pnarimani\"><span style=\"font-weight: 400;\">Peyman Narimani<\/span><\/a>\u2019s open-source <a href=\"https:\/\/github.com\/mnarimani\/RTLTMPro\">RTL Text Mesh Pro<\/a> since it worked well for me. Let\u2019s go over how to use it in our project.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> If you\u2019re not supporting a RTL language in your game, feel free to skip this section.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"installing-rtl-text-mesh-pro\"><\/span>Installing RTL Text Mesh Pro<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>To get started with RTL Text Mesh Pro (RTLTMP), we can head over to the library\u2019s <a href=\"https:\/\/github.com\/mnarimani\/RTLTMPro\/releases\">releases page<\/a> and grab the latest release. The <code>.unitypacakge<\/code> file associated with the release makes for easy installation into our project.<br \/>\nWith the <code>.unitypackage<\/code> file on hand, we can head over to Unity and go to <em>Assets \u279e Import Package \u279e Custom Package<\/em>. We can then select the <code>.unitypackage<\/code> file, keep all the folders and files checked, and click <em>Import<\/em>. This should install the package, creating a new folder in our project called <code>RTLTMPro<\/code>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"the-rtl-text-mesh-pro-component\"><\/span>The RTL Text Mesh Pro Component<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Ok, let\u2019s add our RTLTMP components so that we can get RTL text rendered in our game. In our hierarchy, we can right-click the game object we want to add our component to, and select one of the new <code>UI\/* - RTLTMP<\/code> components.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13456 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component.png\" alt=\"RTL Text Mesh Pro Component | Phrase\" width=\"874\" height=\"1658\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component.png 874w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component-158x300.png 158w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component-540x1024.png 540w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component-768x1457.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-adding-rtltmp-component-810x1536.png 810w\" sizes=\"(max-width: 874px) 100vw, 874px\" \/><br \/>\nYou\u2019ll notice that the RTLTMP package has added a corresponding RTL component for each native TextMeshPro component. Let\u2019s add a <code>Text - RTLTMP<\/code> component.<br \/>\nThat\u2019s about it. The new text component can be used exactly like a normal TextMeshPro component. We just need to make sure to provide an RTL font asset under the <em>Font Asset<\/em> field. RTLTMP comes with some RTL font assets that we can use in our projects. They reside in <code>Assets\/RTLTMPro\/Fonts<\/code> and support at least Arabic and Farsi. We also need to add our RTL text to the <em>RTL Text Input Box<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13457 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-rtl-text.png\" alt=\"Translated UI | Phrase\" width=\"824\" height=\"162\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-rtl-text.png 824w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-rtl-text-300x59.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-rtl-text-768x151.png 768w\" sizes=\"(max-width: 824px) 100vw, 824px\" \/><br \/>\nWorks like a charm. \u201cWhat about localization,\u201d I hear you asking? Localizing RTLTMP components is exactly like localizing TextMeshPro components, and we\u2019ll cover that next.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> Instead of using the font assets that come with RTLTMP, we could <a href=\"https:\/\/github.com\/mnarimani\/RTLTMPro#how-to-use\">make our own<\/a>. I\u2019ve created a font asset based on the Cairo Google font and added it to <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\/tree\/main\/Assets\/_Project\/Fonts\">our GitHub repo<\/a>. I should mention that I found creating my own usable RTL font to be a bit tricky, and needed to tweak the font asset settings to make it render with the Arabic characters looking correctly connected (kind of \ud83d\udc94). If you want me to dive deeper into custom RTL font creation, let me know in the comments below.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"localizing-textmesh-pro-text\"><\/span>Localizing TextMesh Pro Text<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We\u2019ve done enough setup methinks. Let us localize, fellow devs. First, we\u2019ll create either a TMP or RTLTMP component, depending on whether or not we\u2019re supporting RTL text (see the previous section if you are). We localize the component by adding a <em>Localize String Event<\/em> component to the game object.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13458 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-localized-string-event-component.png\" alt=\"Localize String Event component | Phrase\" width=\"1231\" height=\"1360\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-localized-string-event-component.png 1231w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-localized-string-event-component-272x300.png 272w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-localized-string-event-component-927x1024.png 927w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-localized-string-event-component-768x848.png 768w\" sizes=\"(max-width: 1231px) 100vw, 1231px\" \/><br \/>\nThe <em>Localized String Event<\/em> component is provided by the official Unity localization package. It allows us to use a translation entry from one of our string table collections, providing it to one of our other components. We do this by hooking into the <em>Update String<\/em> event of the component.<br \/>\nFirst, we\u2019ll make sure we have a translation in our previously created string table collection. We can head over to <em>Window \u279e Asset Management \u279e Localization Tables<\/em> and make sure that the <em>Selected Table Collection<\/em> is the one we created previously (I called mine <code>UI<\/code>).<br \/>\nWe can then click the <em>Add New Entry<\/em> button at the bottom of the window, and enter a <em>Key<\/em> and translation for our entry. I\u2019m adding a <code>new_ability_discovered<\/code> key to my table.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13459 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1.png\" alt=\"Adding Translated Strings | Phrase\" width=\"1892\" height=\"1334\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1.png 1892w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1-300x212.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1-1024x722.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1-768x541.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-add-string-key-1-1536x1083.png 1536w\" sizes=\"(max-width: 1892px) 100vw, 1892px\" \/><br \/>\nNow we can head back over to our hierarchy and provide the key we just added to the <em>String Reference<\/em> field on our <em>Localized String Event<\/em> component.<br \/>\nWe should also add an item to the <em>Update String<\/em> list. This works like a normal Unity event: we drag the game object that we want to update to the object field. In our case, this is the object that houses our TMP component. We then use the function dropdown to select <em>TextMeshPro \u279e Text<\/em> (or <em>RTLTextMeshPro \u279e Text<\/em>).<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13460 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-update-localized-tmp-text.png\" alt=\"Update String list | Phrase\" width=\"718\" height=\"650\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-update-localized-tmp-text.png 718w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-update-localized-tmp-text-300x272.png 300w\" sizes=\"(max-width: 718px) 100vw, 718px\" \/><br \/>\nNow, when the locale changes (or when the localization system initializes), our TMP text will render its text in the active locale. We can run our game and use the debugging locale switcher in the top-right of the <em>Game<\/em> view to test this.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13461 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher.png\" alt=\"Game view | Phrase\" width=\"1702\" height=\"564\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher.png 1702w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-300x99.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-1024x339.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-768x254.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-1536x509.png 1536w\" sizes=\"(max-width: 1702px) 100vw, 1702px\" \/><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13462 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-translated-basic-strings.png\" alt=\"Overview Localized UI | Phrase\" width=\"1162\" height=\"577\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-translated-basic-strings.png 1162w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-translated-basic-strings-300x149.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-translated-basic-strings-1024x508.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-translated-basic-strings-768x381.png 768w\" sizes=\"(max-width: 1162px) 100vw, 1162px\" \/><br \/>\nOur first translation. Take pride, friends. As per usual with Unity, there\u2019s a bit of setup and learning to get localization working, but the system is quite powerful and flexible as we\u2019ll see.<\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> A handy shortcut: instead of adding the <em>Localized String Event<\/em> component manually, we can also right-click the TMP (or RTLTMP) component and select <em>Localize<\/em>. This adds the localizing component and wires it to the update event automatically. We just have to select our translation key and we\u2019re off and running.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"interpolation\"><\/span>Interpolation<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>We often want to include dynamic text in our translated strings. Something like \u201cAxion55 stole the flag!\u201d, where \u201cAxion55\u201d is a username that can change at runtime. Let\u2019s see how we can use <em>Smart Strings<\/em> to achieve this with Unity localization.<br \/>\nWe\u2019ll add a new entry to our string table collection.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13463 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings.png\" alt=\"String table collection | Phrase\" width=\"1862\" height=\"278\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings.png 1862w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings-300x45.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings-1024x153.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings-768x115.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-setting-strings-1536x229.png 1536w\" sizes=\"(max-width: 1862px) 100vw, 1862px\" \/><br \/>\nI\u2019m adding a string that reads \u201c{Character} has leveled up!\u201d. We have to check the <em>Smart<\/em> checkbox above each translation that will use interpolation. Notice that <code>{Character}<\/code> is a special sequence that will be replaced at runtime. We need to use the same <code>{VariableName}<\/code> sequence in all the entry\u2019s translations to have it swapped for the actual value at runtime.<br \/>\nWe can use the <em>Debug<\/em> toggle next to a translation to see if we\u2019ve formatted our text correctly for the <em>Smart Strings<\/em> system. We\u2019ll get syntax highlighting in debug mode that should indicate whether our text is correct or not.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13464 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug.png\" alt=\"Smart Strings Formatting | Phrase\" width=\"1858\" height=\"252\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug.png 1858w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug-300x41.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug-1024x139.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug-768x104.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-smart-string-debug-1536x208.png 1536w\" sizes=\"(max-width: 1858px) 100vw, 1858px\" \/><br \/>\nNow we can provide the actual value to our <em>Localized String Event<\/em> component so that it will be used at runtime. First, let\u2019s create a trivial MonoBehaviour to house our value.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"93668402-1a12-4e2a-b615-2e24bd745c74\" data-enlighter-title=\"Assets\/_Project\/Scripts\/Values.cs\">using UnityEngine;\npublic class Values : MonoBehaviour\n{\n    public string Character = \"Tinka\";\n}\n<\/pre>\n<p>Next, let\u2019s wire this to our <em>Localized String Event<\/em> component.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13465 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-providing-values.png\" alt=\"Localized String Event | Phrase\" width=\"714\" height=\"838\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-providing-values.png 714w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolation-providing-values-256x300.png 256w\" sizes=\"(max-width: 714px) 100vw, 714px\" \/><br \/>\nWe can add the <code>Values<\/code> script as a component to our game object and drag it into the <em>Format Arguments<\/em> collection in our <em>Localized String Event<\/em> component. Of course, we also need to make sure that we\u2019ve selected the correct key in the <em>String Reference<\/em> field of our <em>Localized String Event<\/em>. Now our TMP component will show our translations with the <code>Values.Character<\/code> value interpolated.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13466 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolated-text.png\" alt=\"Translated UI interpolated | Phrase\" width=\"1154\" height=\"544\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolated-text.png 1154w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolated-text-300x141.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolated-text-1024x483.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-interpolated-text-768x362.png 768w\" sizes=\"(max-width: 1154px) 100vw, 1154px\" \/><\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> The string in the value-providing component must have the exact same name as the variable in our translation string (<code>Character<\/code> in the previous example).<\/p><\/blockquote>\n<p>This gives us basic interpolation, but it won\u2019t update the TMP text if <code>Values.Character<\/code> changes at runtime. We\u2019ll explore how to update translated text when its variable dependencies change when we discuss global variables a bit later.<del><br \/>\n<\/del><\/p>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> If you\u2019re using RTLTMP (see above), make sure to select the <em>Force Fix<\/em> option on the component if your text begins with left-to-right text. Otherwise all the text the component renders will be left-to-right.<\/p><\/blockquote>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> Unity\u2019s localization package uses a fork of the popular C# <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/SmartStrings.html\"><em>Smart Strings<\/em><\/a> library for its dynamic string formatting. <em>Smart Strings<\/em> is a drop-in replacement for the native .NET <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.string.format?view=net-5.0\">string.Format()<\/a>. This means that any <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.string.format?view=net-5.0#Starting\">format strings<\/a> that we can use with <code>string.Format<\/code> can also be used with <em>Smart Strings<\/em>. We go into this a bit later when we cover number and date formatting.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"plurals\"><\/span>Plurals<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>\u201cYou have earned 3 gold coin!\u201d Oops. We can do better with our plurals. Luckily, <em>Smart Strings<\/em> have excellent support for dynamic plural strings. Let\u2019s add a new key to our string table collection to see this in action.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13467 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings.png\" alt=\"Adding new String to Smart Strings | Phrase\" width=\"1620\" height=\"210\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings.png 1620w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings-300x39.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings-1024x133.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings-768x100.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-setting-strings-1536x199.png 1536w\" sizes=\"(max-width: 1620px) 100vw, 1620px\" \/><br \/>\nWe\u2019re interpolating a count value in our translations. Let\u2019s take a look at the English format and break it down.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">Your party has {ComboPointCount:plural:{} combo point|{} combo points}.\n<\/pre>\n<p><code>ComboPointCount<\/code> is the integer value that we\u2019ll use to determine the plural format to use. English has two plural formats: <em>one<\/em> and <em>other<\/em>. We can add these to our translation in order, separated by a <code>|<\/code> character. <code>{}<\/code> is a placeholder that will be swapped out for the value of <code>ComboPointCount<\/code> at runtime. And we use the optional <code>:plural:<\/code> designation to make it clear what the intention of our format is. This will render as follows in English.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13468 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-en-forms.png\" alt=\"UI without plurals | Phrase\" width=\"895\" height=\"533\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-en-forms.png 895w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-en-forms-300x179.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plurals-en-forms-768x457.png 768w\" sizes=\"(max-width: 895px) 100vw, 895px\" \/><br \/>\nFrench, like English, has two plural forms, so its format is similar to the English one. Arabic, however, has six plural forms: <em>zero<\/em>, <em>one<\/em>, <em>two<\/em>, <em>few<\/em>, <em>many<\/em>, and <em>other<\/em>. As the figure above demonstrates, we provide these forms as we do in English, in order and separated by a <code>|<\/code>. Our Arabic translation then renders like so:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13469 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plural-ar-forms.png\" alt=\"Arabic UI plural forms | Phrase\" width=\"1200\" height=\"997\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plural-ar-forms.png 1200w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plural-ar-forms-300x249.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plural-ar-forms-1024x851.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-plural-ar-forms-768x638.png 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><br \/>\nNotice that <em>Smart Strings<\/em> is smart enough to know that Arabic has six plural forms. We don\u2019t have to do anything other than provide those forms.<\/p>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> For each translation, make sure to provide <em>all<\/em> the language\u2019s plural forms, or you\u2019ll get errors when the localization library can\u2019t find the form corresponding to the given count.<\/p><\/blockquote>\n<p>Of course, to get this rendering we need to add our new key to a <em>Localized String Event<\/em> that updates a TMP component. And just like we did in the previous <em>Interpolation<\/em> section, we must provide this component with a modified <code>Values<\/code> MonoBehaviour that looks like the following.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"d5c1981e-c123-469f-bcc4-6aeaf8b58a70\" data-enlighter-title=\"Assets\/_Project\/Scripts\/Values.cs\" data-enlighter-highlight=\"6\">using UnityEngine;\npublic class Values : MonoBehaviour\n{\n    public string Character = \"Tinka\";\n    public int ComboPointCount = 200;\n}\n<\/pre>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> The <a href=\"https:\/\/unicode-org.github.io\/cldr-staging\/charts\/latest\/supplemental\/language_plural_rules.html\">Unicode CLDR charts<\/a> are an excellent listing of per-language plural rules for your perusal.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"number-formatting\"><\/span>Number Formatting<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p><em>Smart Strings<\/em> can also be used to interpolate localized numbers. By default, numbers will get formatted per the rules of their locale. A new entry in our string table collection can help demonstrate.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13470 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings.png\" alt=\"Smart String localized numbers | Phrase\" width=\"1610\" height=\"208\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings.png 1610w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings-300x39.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings-1024x132.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings-768x99.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-number-formatting-setting-strings-1536x198.png 1536w\" sizes=\"(max-width: 1610px) 100vw, 1610px\" \/><br \/>\nIn addition to the normal <code>{VariableName}<\/code> specifier, notice the trailing <code>:C<\/code> in our format string. This is a standard .NET format specifier that results in a localized currency value. Once we\u2019ve wired up our <em>Localized String Event<\/em> to our TMP component and provided a <code>Values.StolenAmount<\/code> <code>float<\/code> for the runtime value, we\u2019ll see our translations rendered as follows.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13471 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-currency-en-ar-fr.png\" alt=\"Localized UI with plurals | Phrase\" width=\"1151\" height=\"529\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-currency-en-ar-fr.png 1151w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-currency-en-ar-fr-300x138.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-currency-en-ar-fr-1024x471.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-currency-en-ar-fr-768x353.png 768w\" sizes=\"(max-width: 1151px) 100vw, 1151px\" \/><br \/>\nNote that we\u2019re seeing the currency, thousands separator, and decimal separator in each locale. English (en) defaults to US English, so its currency is formatted as US dollars. French (fr) defaults to France French, so it gives us Euros. Arabic (ar) defaults to Saudi Arabian Arabic, so its currency is displayed as Saudi Riyals.<\/p>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> We have complete control over the formatting of our numbers because we can use all .NET format specifiers with <em>Smart Strings<\/em>. In the example above we\u2019ve used a <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/base-types\/standard-numeric-format-strings\">standard numeric format string<\/a> to specify currency. We can also use <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/base-types\/custom-numeric-format-strings\">custom numeric format strings<\/a> to exert more granular control over our number formatting.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"date-formatting\"><\/span>Date Formatting<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Similar to number formatting, we can control date formats with <em>Smart Strings<\/em> as well. Let\u2019s add a new entry to our string table collection that displays a date.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13472 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings.png\" alt=\"Smart string date formatting | Phrase\" width=\"1578\" height=\"214\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings.png 1578w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings-300x41.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings-1024x139.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings-768x104.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-setting-strings-1536x208.png 1536w\" sizes=\"(max-width: 1578px) 100vw, 1578px\" \/><br \/>\n<code>d MMM<\/code> is a <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/base-types\/custom-date-and-time-format-strings\">custom date format specifier<\/a> that results in the numeric day of the month, followed by the abbreviated name of the month, in the given date. We can update our <code>Values<\/code> MonoBehaviour with a <code>Date<\/code> value and wire everything up to a <em>Localized String Event<\/em> to see the translated rendering.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"0740b986-6332-470a-80da-7d17c80545ce\" data-enlighter-title=\"\/Assets\/_Project\/Scripts\/Values.cs\" data-enlighter-highlight=\"8\">using UnityEngine;\npublic class Values : MonoBehaviour\n{\n    public string Character = \"Tinka\";\n    public int ComboPointCount = 200;\n    public float StolenAmount = 1014.99f;\n    public DateTime Today = DateTime.Now;\n}\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13473 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-en-ar-fr.png\" alt=\"UI with localized date format | Phrase\" width=\"1165\" height=\"540\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-en-ar-fr.png 1165w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-en-ar-fr-300x139.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-en-ar-fr-1024x475.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-date-formatting-en-ar-fr-768x356.png 768w\" sizes=\"(max-width: 1165px) 100vw, 1165px\" \/><br \/>\nThe above dates are presented in the calendars of their respective locales. English and French are using the Gregorian calendar whereas Arabic is using the Hijri calendar. This is because English (en), French (fr) and Arabic (ar) use the USA, France, and Saudi Arabic locales by default.<\/p>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> In addition to custom date formats, we of course also have <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/standard\/base-types\/standard-date-and-time-format-strings\">standard date formats<\/a>.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"global-variables\"><\/span>Global Variables<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In the examples above we were able to provide dynamic values that are used in our translation strings at runtime. However, these values are a one-and-done deal: runtime changes to these values will not cause our translation strings to re-render. If we want reactive dynamic interpolation in our translation strings, we can use global variables.<br \/>\nGlobal variables are part of the official localization package, and they solve the reactivity problem for us. Let\u2019s create some global variables to see how they work.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"creating-a-global-variables-group\"><\/span>Creating a Global Variables Group<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In our project view, we can right-click and select <em>Create \u279e Localization \u279e Global Variables Group<\/em>. This will create a new global variables group asset in our project. I\u2019ve placed mine in a <code>Localization\/Global Variables<\/code> folder. Clicking the asset reveals a collection in the <em>Inspector<\/em> that we can add to.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13655 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-variables-inspector.png\" alt=\"Asset in Inspector | Phrase\" width=\"630\" height=\"398\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-variables-inspector.png 630w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-variables-inspector-300x190.png 300w\" sizes=\"(max-width: 630px) 100vw, 630px\" \/><br \/>\nLet\u2019s add a string variable by clicking the <em>\u2795<\/em> icon and selecting <em>String<\/em>. We can give our string a key of <code>character<\/code> and a value of <code>Awi<\/code>. We\u2019ll use this string in a translation shortly.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"adding-global-variables-to-localization-settings\"><\/span>Adding Global Variables to Localization Settings<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In order to expose our global variables to our translations, we have to wire them up to our settings. Let\u2019s open our <em>Localization Settings<\/em> and find the <em>\u2795<\/em> icon under <em>String Database \u279e Sources<\/em>. Clicking the <em>\u2795<\/em> reveals a menu, from which we can select <em>Global Variables Source<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13656 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-add-global-variables-source.png\" alt=\"Global Variables Source | Phrase\" width=\"1480\" height=\"754\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-add-global-variables-source.png 1480w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-add-global-variables-source-300x153.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-add-global-variables-source-1024x522.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-add-global-variables-source-768x391.png 768w\" sizes=\"(max-width: 1480px) 100vw, 1480px\" \/><br \/>\nNow, <em>within<\/em> the <em>Global Variables Source<\/em> is another <em>\u2795<\/em> icon. Let\u2019s click that to add an entry. We can leave the default entry name, <code>global<\/code>, as-is. Let\u2019s drag the global variables asset that we created above into the slot next to the name. That should have us all wired up.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"using-global-variables-in-translation-strings\"><\/span>Using Global Variables in Translation Strings<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Interpolating our global variables into our translation strings is straightforward. Let\u2019s head over to <em>Window \u279e Asset Management \u279e Localization Tables<\/em> to add a new translation.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13657 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation.png\" alt=\"Global variables in Smart Strings | Phrase\" width=\"1890\" height=\"210\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation.png 1890w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation-300x33.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation-1024x114.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation-768x85.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-using-globalized-string-in-translation-1536x171.png 1536w\" sizes=\"(max-width: 1890px) 100vw, 1890px\" \/><br \/>\nI\u2019ve added a new table entry with a key of <code>character_gained_ability<\/code>. Note that, just as before, we have to check the <em>Smart<\/em> checkbox to use interpolation in our translation strings.<br \/>\nTo designate the placeholder where our global variable will swap in, we use the <code>{group-name.variable-name}<\/code> syntax. The group name will be whatever we called the group when we registered it as a source in our <em>Localization Settings<\/em> (<code>global<\/code> in our case).<\/p>\n<h3><span class=\"ez-toc-section\" id=\"updating-global-variables-from-scripts\"><\/span>Updating Global Variables from Scripts<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>In order to see the reactivity of our global variable, we need to update it at runtime. We\u2019ll need a script to do this.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"fdff45b1-ce08-4c74-a64e-0db6725d45bb\" data-enlighter-title=\"Assets\/_Project\/Scripts\/GlobalValueUpdaters\/InterpolatedStringUpdater.cs\">using UnityEngine;\nusing UnityEngine.Localization.SmartFormat.Extensions;\nusing UnityEngine.Localization.SmartFormat.GlobalVariables;\nusing Random = UnityEngine.Random;\npublic class InterpolatedStringUpdater : MonoBehaviour\n{\n    [SerializeField] private string[] _characterNames;\n    private void Start()\n    {\n        \/\/ Get our GlobalVariablesSource\n        var source = LocalizationSettings\n            .StringDatabase\n            .SmartFormatter\n            .GetSourceExtension&lt;GlobalVariablesSource&gt;();\n        \/\/ Get the specific global variable\n        var characterName =\n            source[\"global\"][\"character\"] as StringGlobalVariable;\n        var randomCharacterName = _characterNames[\n            Random.Range(0, _characterNames.Length)\n        ];\n        \/\/ Update the global variable\n        characterName.Value = randomCharacterName;\n    }\n}\n<\/pre>\n<p>When our scene loads, our <code>InterpolatedStringUpdater<\/code> will find our <code>global.character<\/code> global variable and set it one of the random names we\u2019ve specified in <code>_characterNames<\/code>. This update will trigger a refresh in any localized string that uses it.<br \/>\nNow let\u2019s hook up our updater to a game object in our scene.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13658 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-add-updater.png\" alt=\"Game object updater in scene | Phrase\" width=\"1273\" height=\"650\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-add-updater.png 1273w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-add-updater-300x153.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-add-updater-1024x523.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-add-updater-768x392.png 768w\" sizes=\"(max-width: 1273px) 100vw, 1273px\" \/><br \/>\nFinally, let\u2019s update one of our Localized String Events associated with a TextMeshPro text label to use our new localized string.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13659 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-connect-to-tmp.png\" alt=\"Localized String Events with a TextMeshPro | Phrase\" width=\"788\" height=\"650\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-connect-to-tmp.png 788w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-connect-to-tmp-300x247.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-var-connect-to-tmp-768x634.png 768w\" sizes=\"(max-width: 788px) 100vw, 788px\" \/><br \/>\nWith that in place, every time we run our game, our UI will show a randomized character name.<\/p>\n<p style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13660 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-vars-randomized-name-fr.png\" alt=\"UI with global variable | Phrase\" width=\"781\" height=\"141\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-vars-randomized-name-fr.png 781w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-vars-randomized-name-fr-300x54.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-vars-randomized-name-fr-768x139.png 768w\" sizes=\"(max-width: 781px) 100vw, 781px\" \/><em>Who will it be? Marm, Awi, or Tanta?<\/em><\/p>\n<p>And just to drive home the reactivity of global variables, we created a little countdown updater.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13661 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-global-vars-w-countdown-en.gif\" alt=\"UI with global variables countdown | Phrase\" width=\"858\" height=\"532\" \/><\/p>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> Get <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\/blob\/main\/Assets\/_Project\/Scripts\/GlobalValueUpdaters\/PluralValueUpdater.cs\">the code for the countdown updater<\/a> from our GitHub repo.<\/p><\/blockquote>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> Global variables are serializable and will persist when you update them, much like ScriptableObjects.<\/p><\/blockquote>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> There is much more we can do with global variables. Get the skinny from <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/GlobalVariables.html\">the official docs<\/a>.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"accessing-localized-strings-from-scripts\"><\/span>Accessing Localized Strings from Scripts<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>At some point, we&#8217;ll likely need to use translated values directly in our scripts. This isn\u2019t too hard and can be done with the following recipe.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"e03411e4-965b-4031-a8a6-bdc52c179429\" data-enlighter-title=\"Assets\/_Project\/Scripts\/LocalizedStringUser.cs\">using System.Collections;\nusing UnityEngine;\nusing UnityEngine.Localization;\nusing UnityEngine.Localization.Tables;\npublic class LocalizedStringUser : MonoBehaviour\n{\n    \/\/ 1. Get a reference to the localized string table\n    [SerializeField]\n    private LocalizedStringTable _localizedStringTable;\n    private StringTable _currentStringTable;\n    private IEnumerator Start()\n    {\n        \/\/ 2. Wait for the table to load asynchronously\n        var tableLoading = _localizedStringTable.GetTable();\n        yield return tableLoading;\n        _currentStringTable = tableLoading.Result;\n        \/\/ At this point _currentStringTable can be used to\n        \/\/ access our strings\n        \/\/ 3. Retrieve the localized string\n        var str =\n            _currentStringTable[\"new_ability_discovered\"]\n                .LocalizedValue;\n         Debug.Log(str);\n    }\n}\n<\/pre>\n<p>We need a reference to the string table housing our strings. By exposing the <code>LocalizedStringTable<\/code> field above in the Unity editor, we get a familiar UI to set the table.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13662 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-use-localized-str-add-table.png\" alt=\"Localized String Table field in Unity editor | Phrase\" width=\"790\" height=\"550\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-use-localized-str-add-table.png 790w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-use-localized-str-add-table-300x209.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-use-localized-str-add-table-768x535.png 768w\" sizes=\"(max-width: 790px) 100vw, 790px\" \/><br \/>\nIn the <em>Inspector<\/em>, we can select the <code>UI<\/code> table in we created earlier. If we then access the <code>new_ability_discovered<\/code> string from it as we\u2019re doing in the code above, our <code>Debug.Log(str)<\/code> will show:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-linenumbers=\"false\">Simple string: New ability discovered!       \/\/ locale = en\nSimple string: Nouvelle capacit\u00e9 d\u00e9couverte! \/\/ locale = fr\nSimple string: \u0627\u0643\u062a\u0634\u0641\u062a \u0642\u062f\u0631\u0629 \u062c\u062f\u064a\u062f\u0629!            \/\/ locale = ar\n<\/pre>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> We\u2019re using the Coroutine version of the <code>Start<\/code> Unity event method above. This is because loading a localized string table is an asynchronous operation, and we have to <code>yield<\/code> until it completes before we can use our table.<\/p><\/blockquote>\n<h3><span class=\"ez-toc-section\" id=\"interpolating-values-in-scripts\"><\/span>Interpolating Values in Scripts<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>We can swap dynamic values into our localized strings in code almost as easily as we can with localized string events in the Unity editor. Let\u2019s demonstrate using the \u201cThief stole X from you!\u201d string we created earlier.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"1a721aa4-48b7-4150-8300-2ca930458024\" data-enlighter-title=\"Assets\/_Project\/Scripts\/LocalizedStringUser.cs\" data-enlighter-highlight=\"4,12,23,24,25,26\">using System.Collections;\nusing UnityEngine;\nusing UnityEngine.Localization;\nusing UnityEngine.Localization.Settings;\nusing UnityEngine.Localization.Tables;\npublic class LocalizedStringUser : MonoBehaviour\n{\n    [SerializeField]\n    private LocalizedStringTable _localizedStringTable;\n    [SerializedField] private Values _values;\n    private StringTable _currentStringTable;\n    private IEnumerator Start()\n    {\n        var tableLoading = _localizedStringTable.GetTable();\n        yield return tableLoading;\n        _currentStringTable = tableLoading.Result;\n        var str =\n            _currentStringTable[\"thief_stole\"].GetLocalizedString(\n                LocalizationSettings.SelectedLocale.Formatter,\n                _values);\n        Debug.Log(str);\n    }\n}\n<\/pre>\n<p>Just like we did when we introduced interpolation before, we need to wire up our <code>Values<\/code> object in the inspector. Once we do, we should get the following logs.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-linenumbers=\"false\">Interpolated string: A thief stole $1,014.99 from you! \/\/ locale = en\nInterpolated string: Un voleur vous a vol\u00e9 1 014,99 \u20ac! \/\/ locale = fr\nInterpolated string: \u0642\u062f \u0633\u0631\u0642 \u0644\u0635 \u0645\u0646\u0643 \u0631.\u0633.\u200f 1,014.99 !     \/\/ locale = ar\n<\/pre>\n<p>Of course, you can interpolate more than just float values when using localized strings in code. In fact, you can use any format that works with <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/SmartStrings.html\">Smart Formats<\/a>.<br \/>\nJust for a spot of fun, we used localized strings in code to make a little Dialog scene.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13663 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/03\/unityi18n2021p2-dialog-fr.gif\" alt=\"Translated dialog scene | Phrase\" width=\"950\" height=\"616\" \/><br \/>\nYou can get the dialog system code from <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\">our GitHub repo<\/a>. Find the scene in <code>Assets\/_Project\/Scenes<\/code>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"previewing-building\"><\/span>Previewing &amp; Building<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We\u2019ve already touched upon the locale game view menu dropdown that we can use to preview different translations in play mode. This can be quite handy when developing.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13461 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher.png\" alt=\"Drop down locale menu | Phrase\" width=\"1702\" height=\"564\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher.png 1702w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-300x99.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-1024x339.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-768x254.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-debugging-locale-switcher-1536x509.png 1536w\" sizes=\"(max-width: 1702px) 100vw, 1702px\" \/><\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> You can turn the locale game view menu dropdown on or off in Unity preferences under <em>Localization<\/em>.<\/p><\/blockquote>\n<p>What about standalone builds? Well the simplest solution to preview translations in standalone builds is to force a locale from our <em>Locale Settings<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13474 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-forcing-locale.png\" alt=\"Locale selector | Phrase\" width=\"976\" height=\"665\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-forcing-locale.png 976w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-forcing-locale-300x204.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-forcing-locale-768x523.png 768w\" sizes=\"(max-width: 976px) 100vw, 976px\" \/><br \/>\nLet&#8217;s set the <em>Locale Id<\/em> in the <em>Specific Locale Selector<\/em> and move the selector to the top of the list. This will ensure that our set locale will resolve as the active one at runtime.<br \/>\nBecause the localization package uses addressables, we have to build our addressables groups before we can get our updated translations in our standalone builds. To do this, we head over to <em>Window \u279e Asset Management \u279e Addressables \u279e Groups<\/em>. From there, we can click <em>Build \u279e New Build \u279e Default Build Script<\/em> to build our addressables groups.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13475 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups.png\" alt=\"Addressables groups | Phrase\" width=\"1908\" height=\"1188\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups.png 1908w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups-300x187.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups-1024x638.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups-768x478.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-building-addressable-groups-1536x956.png 1536w\" sizes=\"(max-width: 1908px) 100vw, 1908px\" \/><br \/>\nWe can now build for our target platform to test our translations for production.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13476 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr.png\" alt=\"UI forced French translations | Phrase\" width=\"2284\" height=\"2140\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr.png 2284w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr-300x281.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr-1024x959.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr-768x720.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr-1536x1439.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-standalone-build-fr-2048x1919.png 2048w\" sizes=\"(max-width: 2284px) 100vw, 2284px\" \/><\/p>\n<p style=\"text-align: center;\"><em>A standalone build with forced French translations<\/em><\/p>\n<blockquote><p>\u270b\ud83c\udffd <em>Heads up \u00bb<\/em> During my research I experienced a <a href=\"https:\/\/forum.unity.com\/threads\/addressables-not-loading-in-build.925982\/\">known issue<\/a> with translations not appearing when I was using the addressables package v1.16.16. Reverting the package back to v1.16.15 seemed to resolve the issue.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"fallback\"><\/span>Fallback<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Sometimes we will have missing translations in our projects. There a few ways to deal with this, and we can set our chosen strategy in <em>Localization Settings<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13477 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-control-missing-translation-appearance.png\" alt=\"Missing Translation State field | Phrase\" width=\"962\" height=\"248\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-control-missing-translation-appearance.png 962w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-control-missing-translation-appearance-300x77.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-control-missing-translation-appearance-768x198.png 768w\" sizes=\"(max-width: 962px) 100vw, 962px\" \/><br \/>\nThe <em>Missing Translation State<\/em> field can be set to show a warning message instead of the translated string (default). This warning will appear in production as well. Another option is to <em>Print Warning<\/em>, which will show the warning in the console and render an empty string for the translation.<br \/>\nWe can also check the <em>Use Fallback<\/em> checkbox to use locale fallbacks for the whole project. This will cause a translation missing in say, French, to \u201cfall back\u201d to its English counterpart. If we go this route we need to make sure to set our fallback locales on each local we want to fall back. Selecting one of the locale assets in our project reveals its details in the <em>Inspector<\/em>. From there we can find the <em>Metadata<\/em> collection and add a <em>Fallback locale<\/em> to it.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13478 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-fallback.png\" alt=\"Fallback locale | Phrase\" width=\"808\" height=\"794\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-fallback.png 808w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-fallback-300x295.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-fallback-768x755.png 768w\" sizes=\"(max-width: 808px) 100vw, 808px\" \/><br \/>\nNow when we have a missing French translation, its less-cool English cousin will be shown to the player instead.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13479 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-missing-fr-translation-w-fallback.png\" alt=\"UI with fallback locale | Phrase\" width=\"1018\" height=\"956\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-missing-fr-translation-w-fallback.png 1018w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-missing-fr-translation-w-fallback-300x282.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/02\/unityi18n2021p1-missing-fr-translation-w-fallback-768x721.png 768w\" sizes=\"(max-width: 1018px) 100vw, 1018px\" \/><\/p>\n<blockquote><p>\ud83d\uddd2 <em>Note \u00bb<\/em> We don\u2019t have to set the <em>Fallback<\/em> option on a per-project level. We can choose to set it on individual <em>Localized String Event<\/em>s instead.<\/p><\/blockquote>\n<h2><span class=\"ez-toc-section\" id=\"gg-wp\"><\/span>GG WP<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>We hope you\u2019ve enjoyed this guide to using the official Unity localization package to localize your Unity games. Kudos to the Unity team for constantly developing the engine and empowering developers to make awesome games. And we\u2019ve only scratched the surface of what you can do with Unity\u2019s first-party localization package. Check out <a href=\"https:\/\/docs.unity3d.com\/Packages\/com.unity.localization@0.10\/manual\/index.html\">the official docs<\/a> for more. And if you want us to dive deeper into any topic we covered here, or to cover any other Unity i18n topic, let us know in the comments below.<\/p>\n<blockquote><p>\ud83d\udd17 <em>Resource \u00bb<\/em> Get the project we\u2019ve built here from <a href=\"https:\/\/github.com\/PhraseApp-Blog\/unity-i18n-2021\">our GitHub repo<\/a>.<\/p><\/blockquote>\n<p>And if you\u2019re looking for a professional localization platform for your growing team, check out <a href=\"https:\/\/phrase.com\">Phrase<\/a>. Built by developers for developers, Phrase features a powerful API, flexible CLI, GitHub\/Bitbucket\/GitLab sync, webhooks, machine translation, and a rich web-based translation console for your translation team. Check out all of <a href=\"https:\/\/phrase.com\/roles\/developers\/\">Phrase\u2019s features<\/a> to let Phrase do the heavy lifting in your localization process, keeping you focused on the creative code you love.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Learn all the tricks to using Unity\u2019s first-party localization package to make your games available to the world.<\/p>\n","protected":false},"author":41,"featured_media":2612,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_stopmodifiedupdate":false,"_modified_date":"","_searchwp_excluded":"","footnotes":""},"categories":[40],"class_list":["post-13440","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-software-localization"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/13440"}],"collection":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/comments?post=13440"}],"version-history":[{"count":6,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/13440\/revisions"}],"predecessor-version":[{"id":65269,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/posts\/13440\/revisions\/65269"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media\/2612"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/media?parent=13440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/wp-json\/wp\/v2\/categories?post=13440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}