Localizing with Scripting

You can use localization APIs for specialized translation tasks that are not automatically handled by adding translations to the localization table. Roblox provides a LocalizationService to handle all localization scripting needs. Use the LocalizationService for the following tasks:

If you use any localization APIs when translating your experience, listen for any changes to the user's LocaleID to react to users switching their language while in an experience.

When reusing translation code, you should use a TranslationHelper ModuleScript to handle errors and missing translations.

Localizing Images and Sounds

Add localization beyond text in your experience by providing unique images and sounds based off of a user's locale. To localize assets, first add the source and target asset IDs to your experience's localization table then use the localization API to fetch the different assets.

English (Source) - rbxassetid://2957093606
Spanish (es) - rbxassetid://2957093671
Portuguese (pt) - rbxassetid://2957093727

To start localizing images and sounds, add source and target asset IDs to your localization table. Asset ID entries on the localization table must include a Key as an identifier to be called by the API. The following is an example entry on a localization table using asset IDs:

Key Source es pt
Key_JewelsImage 2957093606 2957093671 2957093727

The following code will replace the asset ID of an ImageLabel with the Spanish asset ID provided in the localization table:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local LocalizationService = game:GetService("LocalizationService")
3
4-- Local variables
5local localizedImageID
6local localizedImage = Instance.new("ImageLabel")
7
8-- Load Translator for "es". Wrap the function within a pcall() to protect against failures.
9local res, translator = pcall(function()
10 return LocalizationService:GetTranslatorForLocaleAsync("es")
11end)
12
13if res then
14 -- Get asset ID from localization table by referencing the Key
15 localizedImageID = translator:FormatByKey("Key_JewelsImage")
16 -- Set the image
17 localizedImage.Image = "rbxassetid://" .. localizedImageID
18else
19 print('GetTranslatorForPlayerAsync failed: ' .. translator)
20end
21

Translating Individual Strings

In some circumstances, you may want to target individual strings for translation. Translator:Translate() can fetch individual entries on the localization table based on the source string.

In the next example, the following localization entry is used:

Source es es pt
Screen Pantalla 295093671 2957093727

The following script will print the Spanish translation of "Screen" to the Output window:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local LocalizationService = game:GetService("LocalizationService")
3
4-- Load Translator for "es". Wrap the function within a pcall() to protect against failures.
5local res, translator = pcall(function()
6 return LocalizationService:GetTranslatorForLocaleAsync("es")
7end)
8
9if res then
10 -- Use Translate function, providing object context and string
11 local sourceTranslation = translator:Translate(game, "Screen")
12 print(sourceTranslation) -- Expected Output: "Pantalla"
13else
14 print('GetTranslatorForPlayerAsync failed: ' .. translator)
15end
16

Using Context Overrides

There are some cases where the same string may have multiple meanings. For example, the word "Screen" can indicate both a computer screen and a window screen, but the Spanish translations are completely different.

The Context column of the localization table is for specifying translations through context overrides. Specify the in-game object on your localization table as in the following example:

Context Source es
workspace.WindowScreen.SurfaceGui.TextLabel Screen Mosquitero
Screen Pantalla

The following script uses a context override to prioritize a specific translation:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local LocalizationService = game:GetService("LocalizationService")
3
4-- Load Translator for "es". Wrap the function within a pcall() to protect against failures.
5local res, translator = pcall(function()
6 return LocalizationService:GetTranslatorForLocaleAsync("es")
7end)
8
9if res then
10 -- use Translate function, providing object context and string
11 local sourceTranslation = translator:Translate( workspace.WindowScreen.SurfaceGui.TextLabel, "Screen")
12 print(sourceTranslation) -- Expected Output: Mosquitero
13else
14 print('GetTranslatorForPlayerAsync failed: ' .. translator)
15end
16

Multiple Contexts

In the case of multiple contexts, the localization service compares object relationships in the Context field from right to left, using the closest match.

For example, a localization table in your experience may have the following shared Source strings entries:

Context Source es
workspace.WindowScreen.SurfaceGui.TextLabel Screen Mosquitero
playerGui.ScreenGui.TextButton Screen Pantalla

If the string "Screen" is added to a playerGui.ScreenGui.TextLabel object in your experience, the localization service displays "Mosquitero" as the Spanish translation as the closest context match.

Substituting Parameters

When using parameters to translate dynamic content, set the values to a table and pass the table as an argument through the API.

In this example, the experience has a localization table with the following entries:

Key Source es
Key_Prize_1 {1:int} jewels {1:int} joyas
Key_Prize_2 ${AmountCash:fixed} cash and {NumJewels:int} jewels ${AmountCash:fixed} dinero y {NumJewels:int} joyas

Use the following code sample to translate these strings with parameter values:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local LocalizationService = game:GetService("LocalizationService")
3
4-- Load Translator for "es". Wrap the function within a pcall() to protect against failures.
5local res, translator = pcall(function()
6 return LocalizationService:GetTranslatorForLocaleAsync("es")
7end)
8
9if res then
10 -- Set the parameter value in "Key_Prize_1" to 100
11 local keyTranslation1 = translator:FormatByKey("Key_Prize_1", {100})
12 print(keyTranslation1) -- Expected Output: 100 joyas
13
14 -- Set multiple parameters to 500 and 100 by name
15 local keyTranslation2 = translator:FormatByKey("Key_Prize_2", {AmountCash=500, NumJewels=100})
16 print(keyTranslation2) -- Expected Output: $500.00 dinero y 100 joyas
17else
18 print('GetTranslatorForPlayerAsync failed: ' .. translator)
19end
20

Switching Languages

In some cases, you may want to display translations of other languages in your experience. You can set a new translator with a different country code using LocalizationService:GetTranslatorForLocaleAsync().

The following code sample sets one translator with a manual country code and an additional translator based off of the user's global locale settings:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2local LocalizationService = game:GetService("LocalizationService")
3local Players = game:GetService("Players")
4
5-- Local variables
6local player = Players.LocalPlayer
7
8-- Load Translator for "pt". Wrap translator functions within a pcall() to protect against failures.
9local res1, translator = pcall(function()
10 return LocalizationService:GetTranslatorForLocaleAsync("pt")
11end)
12
13-- Load second Translator with Player's locale, in this example "es"
14local res2, fallbackTranslator = pcall(function()
15 return LocalizationService:GetTranslatorForPlayerAsync(player)
16end)
17
18-- Use Translate function with first Translator
19if res1 then
20 local translate1 = translator:Translate(game, "jewels")
21 print(translate1) -- Expected Output in pt: joyas
22else
23 print('GetTranslatorForPlayerAsync failed: ' .. translator)
24end
25
26-- Use Translate function with second Translator
27if res2 then
28 local translate2 = fallbackTranslator:Translate(game, "jewels")
29 print(translate2) -- Expected Output in if user is set to 'es': jóias
30else
31 print('GetTranslatorForPlayerAsync failed: ' .. fallbackTranslator)
32end
33

Reacting to Users Switching Languages

Users can change their language settings at any time using their in-experience Settings menu. This user setting change automatically updates non-scripting localization assets, such as strings handled by automatic translation, but may not update scripted localization changes that have already rendered, such as GUI images or sounds.

In-Experience Language Setting
Users can choose available languages set in the experience

To ensure that your scripted localized assets update correctly, listen to the GetPropertyChangedSignal event for changes in the LocaleID property of the Translator instance returned by LocalizationService.GetTranslatorForPlayerAsync. When using LocalizationService.GetTranslatorForPlayerAsync, wrap the function within a pcall in case of errors.

The following code sample prints the Locale ID of the user and the Locale ID of the Translator instance for the user when the user switches languages:


1local LocalizationService = game:GetService("LocalizationService")
2local Players = game:GetService("Players")
3local player = Players.LocalPlayer
4
5-- If GetTranslatorForPlayerAsync succeeds, it will return a Translator for player's current locale
6local res, translator = pcall(function()
7 return LocalizationService:GetTranslatorForPlayerAsync(player)
8end)
9
10-- Function that gets called when change in player's locale ID is detected
11local function OnLocaleIdChanged()
12 print("Translator has changed to: " .. translator.LocaleId)
13 -- You should re-translate any assets translated with Localization APIs to the player's new language here
14end
15
16-- Check if GetTranslatorForPlayerAsync succeeded
17if res then
18 -- If succeeded, translate assets here using translator
19 -- Listen for a change in player's locale ID
20 translator:GetPropertyChangedSignal("LocaleId"):Connect(OnLocaleIdChanged)
21else
22 print('GetTranslatorForPlayerAsync failed: ' .. translator)
23end
24

Creating a TranslationHelper Module

When you load translators based on the player's default locale, you might reuse code. To reuse code, set up a helper ModuleScript that safely loads translators based on the player's default locale and includes functions for providing specific translations and switching languages.

The following code sample implements a TranslationHelper which you can copy into your own project as a ModuleScript in ReplicatedStorage:


1local TranslationHelper = {}
2
3local LocalizationService = game:GetService("LocalizationService")
4local Players = game:GetService("Players")
5
6-- Local variables
7local player = Players.LocalPlayer
8local sourceLanguageCode = "en"
9
10-- Get translators
11local playerTranslator, fallbackTranslator
12local foundPlayerTranslator = pcall(function()
13 playerTranslator = LocalizationService:GetTranslatorForPlayerAsync(player)
14end)
15local foundFallbackTranslator = pcall(function()
16 fallbackTranslator = LocalizationService:GetTranslatorForLocaleAsync(sourceLanguageCode)
17end)
18
19-- Create a method TranslationHelper.setLanguage to load a new translation for the TranslationHelper
20function TranslationHelper.setLanguage(newLanguageCode)
21 if sourceLanguageCode ~= newLanguageCode then
22 local success, newPlayerTranslator = pcall(function()
23 return LocalizationService:GetTranslatorForLocaleAsync(newLanguageCode)
24 end)
25
26 --Only override current playerTranslator if the new one is valid (fallbackTranslator remains as experience's source language)
27 if success and newPlayerTranslator then
28 playerTranslator = newPlayerTranslator
29 return true
30 end
31 end
32 return false
33end
34
35-- Create a Translate function that uses a fallback translator if the first fails to load or return successfully. You can also set the referenced object to default to the generic game object
36
37function TranslationHelper.translate(text, object)
38 if not object then
39 object = game
40 end
41 local translation = ""
42 local foundTranslation = false
43 if foundPlayerTranslator then
44 return playerTranslator:Translate(object, text)
45 end
46 if foundFallbackTranslator then
47 return fallbackTranslator:Translate(object, text)
48 end
49 return false
50end
51
52-- Create a FormatByKey() function that uses a fallback translator if the first fails to load or return successfully
53
54function TranslationHelper.translateByKey(key, arguments)
55 local translation = ""
56 local foundTranslation = false
57
58 -- First tries to translate for the player's language (if a translator was found)
59 if foundPlayerTranslator then
60 foundTranslation = pcall(function()
61 translation = playerTranslator:FormatByKey(key, arguments)
62 end)
63 end
64 if foundFallbackTranslator and not foundTranslation then
65 foundTranslation = pcall(function()
66 translation = fallbackTranslator:FormatByKey(key, arguments)
67 end)
68 end
69 if foundTranslation then
70 return translation
71 else
72 return false
73 end
74end
75
76return TranslationHelper
77

Once the module is in ReplicatedStorage, require it from a LocalScript to call the module's functions. The following code uses this module's helper function to translate an individual string:


1local ReplicatedStorage = game:GetService("ReplicatedStorage")
2
3-- Require translation module
4local TranslationHelper = require(ReplicatedStorage:WaitForChild("TranslationHelper"))
5
6-- Use the functions provided in TranslationHelper
7TranslationHelper.setLanguage("es")
8local sourceTranslation = TranslationHelper.translate("Screen")
9print(sourceTranslation) -- Expected Output in 'es': "Pantalla"
10