How to Translate Your Game Using the Unity Translation Package

Welcome to the wild world of localization, where Veggie Gladiators are about to prove that vegetables aren’t just for salads, but for speaking multiple languages too! Picture this: your game is a hit in Tokyo, and suddenly the Veggie Gladiators have to fight in a sushi bar. Without localization, they’ll be lost in translation faster than a potato in a fruit salad. So, let’s arm our Veggie Gladiators with languages and take over the global gaming arena, one veggie at a time! By Ben MacKinnon.

Leave a rating/review
Download materials
Save for later
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Importing Localization Files

Open the Project window and navigate to the RWLocalization folder. Right-click this folder and choose CreateLocalizationGoogle Sheets Service. This will create a new asset, which you can leave with the default name.

Fill in the details for the Google Sheets Service:

  • Application Name: VeggieGladiators
  • Authentication: API Key
  • API Key: AIzaSyAReIYky0KA6RWtH3ESG5CGdCHMjutSX9w
Note: This is an API key for a specific sheet already set up for this tutorial. If you’d like to look into how to set up your own sheets, check out the Unity documentation.

You’ll use this service to import all the dialogue translations. Open the Localization Tables window again if it isn’t still open – WindowAsset ManagementLocalization Tables. Switch to the New Table Collection tab, and create a new table called DialogueTable. Save it in a new folder at RWLocalizationGame.

Select the DialogueTable asset, and under Extensions, add a Google Sheets Extension.

Add the Google Sheets Extension

Fill in the new options with the following values:

  • Sheets Service Provider: Select the file you set up in the last section.
  • Spreadsheet ID: 1BXL7r1BX2PzyhSyg9zP11Vys-u4ryIpeWK9Cm3S3g2E
  • Sheet ID: 2022142460

With the spreadsheet ID filled in, the extension should recognize the referenced file, and you should see the DialogueTable option under Select Sheet.

Under the Mapped Columns, click the + button and select Add Default Columns. This is how you connect the data in the Google Sheet to the data in the String Table Collection. By default, it will create a Key Column and as many Locale Columns as you have Locales set up. The default values set here match what is provided in the Google Sheet already.

Mapped Columns

With all this setup, you’re now just a single click away from having ALL the translation strings for every dialogue in the DiningHall scene! Click Pull and watch the DialogueTable magically get populated.

Pulling from Google Sheets

You can see that the window also has buttons for Push, Push Selected and Pull Selected. As updates are made to either the Table Collection or the Google Sheet, you can keep the two in sync by pushing from Unity and pulling from Google.

Translating Dialogue

If you didn’t try walking around and triggering all the dialogue earlier, you should definitely try it now. Notice that some of the dialogues have multiple lines, some have a bit of back-and-forth conversation, and some even require some user input to progress.

Now that you have all the translated strings available, you need to actually bring those translations in at runtime. Fortunately, all the dialogues have been built into a system that can easily be updated to support translations!

Note: If you’d like to learn more about how the dialogue system was built, then definitely check out our book, Unity Apprentice, as this project comes from Chapter 8 – Scriptable Objects.

The dialogues are all stored in the folder RWConversations as Scriptable Objects. Select the Bored Warrior, and you can see an example of a single line of dialogue.

The Conversation scriptable object just holds an array of DialogueLines. The DialogueLine class consists of four fields:

  • A string for the speaker.
  • Another string for the text.
  • A Bool to determine if it’s a question.
  • A DialogueQuestion for when it is a question.

Strings mean one thing. Translations!

Open RWScriptsDialogueDialogueLine in your script editor. The first thing to change is the text variable. Currently, it’s a string with a TextArea attribute.

[TextArea(2, 3)]  
public string text;
Note: The TextArea attribute just makes the editor window have a large input field for typing into in the Inspector window.

Add a new import to the top of the file to bring in the localization options:

using UnityEngine.Localization;

Next, remove the TextArea attribute, and add a new field:

public LocalizedString localizedString;

Finally, change the text field to make it an accessor to the GetLocalizedString() method of localizedString. The class should look like this in the end:

using System;  
using UnityEngine;  
using UnityEngine.Localization;  

public class DialogueLine  
    public string speaker;  

    public LocalizedString localizedString;  
    public string text => localizedString.GetLocalizedString();  

    public bool thisIsAQuestion;  
    public DialogueQuestion dialogueQuestion;

Save the script and go back to Unity. Notice the Inspector view of the Bored Warrior dialogue has updated to a familiar view from the early steps of this tutorial.

In the Localized String option, search for and select the Bored Warrior string from the DialogueTable.

Bored Warrior Translation

This conversation is now translated! Go through each of the conversations and pick the key that matches the name of the conversation. Where a conversation has more than one line of dialogue, there’ll be a Key2 etc. for additional lines.

Note: The one exception is the Boss conversation. The key for this is Boss Convo. You’ll find out why in a moment!

You can play the game now, switch the language to German in the Title scene, start a new game and walk around to initiate some conversations. You’ll see that all the NPCs respond to you in German, but there are still a couple of things missing.

Translating the Interaction System

First is the prompt that appears when you get close to any of the NPCs. These are set up around the scene, but fortunately, you don’t need to edit the scene to add translations for them.

Open the InteractableObject script. Similar to the DialogueLine script, it has a few simple fields and an abstract method you don’t need to worry about.

public abstract class InteractableObject : MonoBehaviour  
    public string interactionName;  
    public string interactionVerb;  
    public bool canBeInteractedWith = true;  

    public abstract void Interact(PlayerAvatar playerAvatar);  

First, add a new using to the top of the script.

using UnityEngine.Localization.Settings;

Next, change the two public strings to [SerializeField] private strings instead.

[SerializeField] private string interactionName;  
[SerializeField] private string interactionVerb;

Finally, add two new public accessor strings that use LocalizationSettings.StringDatabase.GetLocalizedString to return the translated value of the private strings.

public string InteractionName => LocalizationSettings.StringDatabase.GetLocalizedString(interactionName);  
public string InteractionVerb => LocalizationSettings.StringDatabase.GetLocalizedString(interactionVerb);

Each of the interactionName and interactionVerb values are already present as keys in the Dialogue Table, so these two lines will look up the table for the given keys and return the translated value.

The final script will look like this:

using UnityEngine;  
using UnityEngine.Localization.Settings;  

public abstract class InteractableObject : MonoBehaviour  
    [SerializeField] private string interactionName;  
    [SerializeField] private string interactionVerb;  
    public bool canBeInteractedWith = true;  

    public string InteractionName => LocalizationSettings.StringDatabase.GetLocalizedString(interactionName);  
    public string InteractionVerb => LocalizationSettings.StringDatabase.GetLocalizedString(interactionVerb);  

    public abstract void Interact(PlayerAvatar playerAvatar);  

Save the script and go back to Unity. You should notice now that you have an error in the console. That’s because the InteractionSystem was referencing those two strings that you just made private.

Open the RWScriptsInteractionInteractionSystem script and find the error at line 81. Change the references to point at your new public variables:

interactionText.text = interactionTarget.InteractionVerb + " " + interactionTarget.InteractionName;


Ben MacKinnon

Author and Topics Master

Gijs Bannenberg

Tech Editor

Adriana Kutenko


Toby Flint

Final Pass Editor

Over 300 content creators. Join our team.