Add Multiple Language Support to Your Unity Projects

After writing a couple of Android applications I thought it would be nice if one could implement support for multiple languages in their Unity projects as easily as in an Android project. I had this idea a few months ago and finally got around to writing it.

With Unity Multiple Language Support you can easily include multi-lingual support in your Unity projects through XML. Simply create one or more XML files with the strings that have multiple translations and then reference those strings in your scripts with a common identifier. XML format is as follows:

<?xml version="1.0" encoding="utf-8"?>
<languages>
    <English>
         <string name="app_name">Some Game</string>
         <string name="score_text">Score: </string>
    </English>

    <French>
        <string name="app_name">Certains Jeux</string>
        <string name="score_text">Score: </string>
    </French>

    <German>
        <string name="app_name">Einige Spiele</string>
        <string name="score_text">Ergebnis: </string>
    </German>
</languages>

Once the Lang Class has been initialized to a particular language you can reference the strings stored in your XML file as follows:

var scoreText : String = langClass.getString("score_text") + newScore.ToString();

Furthermore you can reset the language on the fly with the following line:

langClass.setLanguage(Path.Combine(Application.dataPath, "lang.xml"), "French");

The text stored in your XML resource is read as a string so any rich text formatting will remain intact, but you’ll need to read up on how to format the XML file for special characters. For the most part characters such as quotes and carats need an escape character.

The main difference between this implementation and Android’s is that Android requires each language to have it’s own separate XML file while UMLS leaves it up to the developer to decide whether to throw it all into one XML file or split it up into multiple files. For smaller games a single XML file should do just fine, but since all strings from the selected language are stored in RAM larger games might find it useful to use multiple XML resources such as LVL_01.xml, LVL_02.xml, etcetera. RPGs could even split their resources per conversation such as Adam_01.xml and Jenny_07.xml.

Feel free to grab Unity Multiple Language Support off of my Google Drive for free:
https://docs.google.com/file/d/0B6BscJ4Cq-K7WjhTM1B1N1FWSDA/edit?usp=sharing

P.S. Google Drive opens the zip file so you can download individual items. To download the whole zip file just select File → Download.

P.P.S. UMLS provides support for XML resources stored on the local system and resources stored over the web, however; I have not tested UMLS with web based resources so feel free to contact me if you’re having trouble.

4 Likes

Thank youuuuu so muuuch ! it’s awesome :smile:

Ammmm I have an error :confused:

Could you please help me ?

Lang.js(55,27): BCE0018: The name ‘XmlDocument’ does not denote a valid type (‘not found’).

Edit : By the way I’m in API compatibility Level .net 2.0 (with no subset) into the player settings.
Maybe this cause the problem ?

Hmm. I’m taking a look at msdn.microsoft.com and it indicates that the XmlDocument class is supported as far back as .net 1.0. Check out http://msdn.microsoft.com/en-us/library/system.xml.xmldocument%28v=vs.110%29.aspx for more information about the XmlDocument class.

I’m noticing in the error that you’re receiving it states that it doesn’t recognize the XmlDocument type and then references line 55, I’ve pulled up my script and UniSciTE indicates that the first reference to the XmlDocument type is on line 42 and no reference is made on line 55. Did you modify the script at all? If so make sure you still have the following line at the top:

import System.Xml;

This is to load it from resources folder directly, there seems to be no other way of using local storage outside of the editor.

    var xmlLang : TextAsset  = Resources.Load("lang") as TextAsset;
    langClass = new Lang(xmlLang.text, currentLang, true);

And to change it

        var xmlLang: TextAsset  = Resources.Load("lang") as TextAsset;
        langClass.setLanguageWeb(xmlLang.text, currentLang);

Is there a Csharp version of this?

I want to write Gujarati language , please tell me how to do this. Thank you!.

Hi, here is the C# version:

Lang.cs

/*
The Lang Class adds easy to use multiple language support to any Unity project by parsing an XML file
containing numerous strings translated into any languages of your choice.  Refer to UMLS_Help.html and lang.xml
for more information.

Created by Adam T. Ryder
C# version by O. Glorieux

*/

using System;
using System.Collections;
using System.IO;
using System.Xml;

using UnityEngine;

public class Lang
{
    private Hashtable Strings;
 
    /*
    Initialize Lang class
    path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    language = language to use example:  "English"
    web = boolean indicating if resource is local or on-line example:  true if on-line, false if local
 
    NOTE:
    If XML resource is on-line rather than local do not supply the path to the path variable as stated above
    instead use the WWW class to download the resource and then supply the resource.text to this initializer
 
    Web Example:
    var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    yield wwwXML;
     
    var LangClass : Lang = new Lang(wwwXML.text, currentLang, true)
    */
    public Lang ( string path, string language, bool web) {
        if (!web) {
            setLanguage(path, language);
        } else {
            setLanguageWeb(path, language);
        }
    }
 
    /*
    Use the setLanguage function to swap languages after the Lang class has been initialized.
    This function is called automatically when the Lang class is initialized.
    path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    language = language to use example:  "English"
 
    NOTE:
    If the XML resource is stored on the web rather than on the local system use the
    setLanguageWeb function
    */
    public void setLanguage ( string path, string language) {
        var xml = new XmlDocument();
        xml.Load(path);
     
        Strings = new Hashtable();
        var element = xml.DocumentElement[language];
        if (element != null) {
            var elemEnum = element.GetEnumerator();
            while (elemEnum.MoveNext()) {
                var xmlItem = (XmlElement)elemEnum.Current;
                Strings.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
            }
        } else {
            Debug.LogError("The specified language does not exist: " + language);
        }
    }
 
    /*
    Use the setLanguageWeb function to swap languages after the Lang class has been initialized
    and the XML resource is stored on the web rather than locally.  This function is called automatically
    when the Lang class is initialized.
    xmlText = String containing all XML nodes
    language = language to use example:  "English"
 
    Example:
    var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    yield wwwXML;
     
    var LangClass : Lang = new Lang(wwwXML.text, currentLang)
    */
    public void setLanguageWeb ( string xmlText, string language) {
        var xml = new XmlDocument();
        xml.Load(new StringReader(xmlText));
     
        Strings = new Hashtable();
        var element = xml.DocumentElement[language];
        if (element != null) {
            var elemEnum = element.GetEnumerator();
            while (elemEnum.MoveNext()) {
                var xmlItem = (XmlElement)elemEnum.Current;
                Strings.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
            }
        } else {
            Debug.LogError("The specified language does not exist: " + language);
        }
    }
 
    /*
    Access strings in the currently selected language by supplying this getString function with
    the name identifier for the string used in the XML resource.
 
    Example:
    XML file:
    <languages>
        <English>
            <string name="app_name">Unity Multiple Language Support</string>
            <string name="description">This script provides convenient multiple language support.</string>
        </English>
        <French>
            <string name="app_name">Unité Langue Soutien Multiple</string>
            <string name="description">Ce script fournit un soutien multilingue pratique.</string>
        </French>
    </languages>
 
    JavaScript:
    var appName : String = langClass.getString("app_name");
    */
    public string getString (string name) {
        if (!Strings.ContainsKey(name)) {
            Debug.LogError("The specified string does not exist: " + name);
         
            return "";
        }
 
        return (string)Strings[name];
    }

}

TestGui.cs

/*
This example script demonstrates how to use the Unity Multiple Language Support Lang class in a simple GUI.
The accompanying lang.xml file should be placed into your project's Assests folder.

-Adam T. Ryder
C# version by O. Glorieux
*/

using System.IO;
using UnityEditor;

using UnityEngine;

public class NewMonoBehaviour : Editor
{

    private Lang LMan;
    private string currentLang = "English";

    public void OnEnable()
    {
        /*
    Initialize the Lang class by providing a path to the desired language XML file, a default language
    and a boolean to indicate if we are operating on an XML file located from a downloaded resource or local.
    True if XML resource is on the web, false if local
 
    If initializing from a web based XML resource you'll need to supply the text of the downloaded resource in placed
    of the path.
 
    web example:
    var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    yield wwwXML;
     
    LMan = new Lang(wwwXML.text, currentLang, true);
    */
        LMan = new Lang(Path.Combine(Application.dataPath, "lang.xml"), currentLang, false);
    }

    public void OnGUI()
    {
        /*
    To access a string in the currently set language use the Lang class' getString function with the string name identifier supplied to it.
    */
        GUI.Label(new Rect(0, 0, 800, 450), LMan.getString("app_name") + "\n" + LMan.getString("description"));

        if (GUI.Button(new Rect(0, 450 - 24, 800, 24), "Language:  " + currentLang))
        {
            if (currentLang == "English")
            {
                currentLang = "French";
            }
            else if (currentLang == "French")
            {
                currentLang = "German";
            }
            else
            {
                currentLang = "English";
            }

            /*
        To switch languages after the Lang class has been initialized call the setLanguage function
        and provide a path to the desired XML resource and the desired language.
     
        If the XML resource is located on the web you'll need to use the WWW class to download the resource
        and then supply the text of the downloaded resource in place of the path to the Lang class' setLanguageWeb function.
     
        web example:
        var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
        yield wwwXML;
     
        LMan.setLanguageWeb(wwwXML.text, currentLang);
        */
            LMan.setLanguage(Path.Combine(Application.dataPath, "lang.xml"), currentLang);
        }
    }
}
5 Likes

I just wanted to share the script im using with the new UI system in order to handle static text elements.

#pragma strict
private var Stats : GameStatics;
private var Init = false;
private var code : String;
private var text : UI.Text;

function Start ()
{
    var cam=GameObject.Find("MainCamera");
    Stats=cam.GetComponent(GameStatics); //The script where the langclass is

    text=this.transform.GetComponent(UI.Text);
    code=text.text;

    Init=true;
}

function Update ()
{
    if(Init) UpdateLang();
}

public function UpdateLang ()
{
    text.text=Stats.langClass.getString(code);
    Init=false;
}

just attach it to the text element.
BTW, there is not really a need to store the component in a variable, that just better for in-game lang changes, but

public function UpdateLang ()
{
    text.text=GameObject.Find("MainCamera").GetComponent(GameStatics).langClass.getString(code);
  Init=false;
}

should work just fine as well

Does not work on WebGL, ive not really when into finding out why.

Strings.Add(elemEnum.Current.GetAttribute("name"), elemEnum.Current.InnerText);

looks like “GetAttribute” and “InnerText” are not implemented.

Thanks to jonas echterhoff that helped me, i was able to fix this in order to work in WebGL platform.

#pragma strict
/*
The Lang Class adds easy to use multiple language support to any Unity project by parsing an XML file
containing numerous strings translated into any languages of your choice.  Refer to UMLS_Help.html and lang.xml
for more information.

Created by Adam T. Ryder

10/3/2015 (unofficial by shivansps)
Fixed for WebGL
*/

import System.Xml;

public class Lang
{
    private var Strings : Hashtable;
   
    /*
    Initialize Lang class
    path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    language = language to use example:  "English"
    web = boolean indicating if resource is local or on-line example:  true if on-line, false if local
   
    NOTE:
    If XML resource is on-line rather than local do not supply the path to the path variable as stated above
    instead use the WWW class to download the resource and then supply the resource.text to this initializer
   
    Web Example:
    var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    yield wwwXML;
       
    var LangClass : Lang = new Lang(wwwXML.text, currentLang, true)
    */
    function Lang ( path : String, language : String, web : boolean ) {
        if (!web) {
            setLanguage(path, language);
        } else {
            setLanguageWeb(path, language);
        }
    }
   
    /*
    Use the setLanguage function to swap languages after the Lang class has been initialized.
    This function is called automatically when the Lang class is initialized.
    path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    language = language to use example:  "English"
   
    NOTE:
    If the XML resource is stored on the web rather than on the local system use the
    setLanguageWeb function
    */
    public function setLanguage ( path : String, language : String) {
        var xml : XmlDocument = new XmlDocument();
        xml.Load(path);
       
        Strings = new Hashtable();
        var element : XmlElement = xml.DocumentElement.Item[language];
        if (element) {
            var elemEnum : IEnumerator = element.GetEnumerator();
            while (elemEnum.MoveNext()) {
                Strings.Add((elemEnum.Current as XmlElement).GetAttribute("name"), (elemEnum.Current as XmlElement).InnerText);
            }
        } else {
            Debug.LogError("The specified language does not exist: " + language);
        }
    }
   
    /*
    Use the setLanguageWeb function to swap languages after the Lang class has been initialized
    and the XML resource is stored on the web rather than locally.  This function is called automatically
    when the Lang class is initialized.
    xmlText = String containing all XML nodes
    language = language to use example:  "English"
   
    Example:
    var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    yield wwwXML;
       
    var LangClass : Lang = new Lang(wwwXML.text, currentLang)
   
    ADDED: 10/3/2015 (unofficial by shivansps)
    setLanguageWeb can also be used to load the xml file directly from the resources folder
   
    Example:
    var xmlLang: TextAsset  = Resources.Load("lang") as TextAsset;
    langClass.setLanguageWeb(xmlLang.text, currentLang);
    */
    public function setLanguageWeb ( xmlText : String, language : String) {
        var xml : XmlDocument = new XmlDocument();
        xml.Load(new StringReader(xmlText));
       
        Strings = new Hashtable();
        var element : XmlElement = xml.DocumentElement.Item[language];
        if (element) {
            var elemEnum : IEnumerator = element.GetEnumerator();
            while (elemEnum.MoveNext()) {
                Strings.Add((elemEnum.Current as XmlElement).GetAttribute("name"), (elemEnum.Current as XmlElement).InnerText);
            }
        } else {
            Debug.LogError("The specified language does not exist: " + language);
        }
    }
   
    /*
    Access strings in the currently selected language by supplying this getString function with
    the name identifier for the string used in the XML resource.
   
    Example:
    XML file:
    <languages>
        <English>
            <string name="app_name">Unity Multiple Language Support</string>
            <string name="description">This script provides convenient multiple language support.</string>
        </English>
        <French>
            <string name="app_name">Unité Langue Soutien Multiple</string>
            <string name="description">Ce script fournit un soutien multilingue pratique.</string>
        </French>
    </languages>
   
    JavaScript:
    var appName : String = langClass.getString("app_name");
    */
    public function getString (name : String) : String
    {
        if (!Strings.ContainsKey(name))
        {
            Debug.Log("The specified string does not exist: " + name);
           
            return "Er:"+name;
        }
            return Strings[name];
    }

}

Hello,
I tried using the C# Version of this code on Android, but it does not seem to work, I always get this error:

InvalidCastException: Cannot cast from source type to destination type.
Lang.setLanguageWeb (System.String xmlText, System.String language) (at Lang.cs:97)

var xmlItem = (XmlElement)elemEnum.Current;

Im trying to write a xml according to your specifications, but I cant find a method to write a string like this:

<string name="app_name">

Both WriteElementString and WriteString gives me the exact same result. What should I be using to write a string as you provided on your lang.xml example?

Thanks!

Nevermind, figured it out. In case anyone need this in the future:

writer.WriteStartElement("string");
writer.WriteAttributeString("name", "app_name");
writer.WriteString("Unity Multiple Language Support");
writer.WriteEndElement();

Is it possible to add multi-line translations? “\n” doesn’t seem to work.

Hello, I made localization via xml. On some devices some languages is not recognized, I see question marks instead of
text.

Ever figure out that error? I’m getting it on a plain old PC, Linux, Standalone build, only its on line 65. Its the same corresponding line of code for the SetLanguage function rather than SetLanguageWeb function.

======EDIT======== AND GOOD NEWS!

I was able to solve this error by deleting the line in quesiton, and for the line immediately after, replace:

Strings.Add(xmlItem.GetAttribute(“name”), xmlItem.InnerText);

with:

Strings.Add((elemEnum.Current as XmlElement).GetAttribute(“name”),(elemEnum.Current as XmlElement).InnerText);

This was part of another solution to another problem further up in the thread, but it works here too. Oh and for future noobs reference, DO NOT put any empty lines, or commented out lines in your .xml files, or this script will not work.

1 Like

Not work

there are no errorson code and well done on computer. but in android, it doesn’t work!

using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class TestGui : MonoBehaviour

{

private Lang LMan;
private string currentLang = “English”;

public static TestGui S;
public string start;
public string restart;
public string stats;
public string copyright;
public string exit;

public void OnEnable()
{
LMan = new Lang(Path.Combine(Application.dataPath, “lang.xml”), currentLang, false);
}

void Start()
{

S = this;
currentLang = Application.systemLanguage.ToString ();
print (Application.systemLanguage.ToString ());

LMan.setLanguage (Path.Combine (Application.dataPath, “lang.xml”), currentLang);

start = LMan.getString (“Start”);
restart = LMan.getString (“ReStart”);
stats = LMan.getString (“Stats”);
copyright = LMan.getString (“Copyright”);
exit = LMan.getString (“Exit”);
LMan.setLanguage (Path.Combine (Application.dataPath, “lang.xml”), currentLang);
}

}

using System;
using System.Collections;
using System.IO;
using System.Xml;
using UnityEngine;

public class Lang
{
private Hashtable Strings;

public Lang ( string path, string language, bool web) {

if (!web) {

setLanguage(path, language);

} else {

setLanguageWeb(path, language);

}

}

public void setLanguage ( string path, string language) {

var xml = new XmlDocument();

xml.Load(path);

Strings = new Hashtable();

var element = xml.DocumentElement[language];

if (element != null) {

var elemEnum = element.GetEnumerator();

while (elemEnum.MoveNext()) {

Strings.Add((elemEnum.Current as XmlElement).GetAttribute(“name”),(elemEnum.Current as XmlElement).InnerText);

}

} else {

Debug.LogError("The specified language does not exist: " + language);

}

}

public void setLanguageWeb ( string xmlText, string language) {

var xml = new XmlDocument();

xml.Load(new StringReader(xmlText));

Strings = new Hashtable();

var element = xml.DocumentElement[language];

if (element != null) {

var elemEnum = element.GetEnumerator();

while (elemEnum.MoveNext()) {

Strings.Add((elemEnum.Current as XmlElement).GetAttribute(“name”),(elemEnum.Current as XmlElement).InnerText);

}

} else {

Debug.LogError("The specified language does not exist: " + language);

}

}

public string getString (string name) {

if (!Strings.ContainsKey(name)) {

Debug.LogError("The specified string does not exist: " + name);

return “”;

}

return (string)Strings[name];

}

}

Hi!
I once needed good localization support for my Unity game. I wrote a simple system and thought I’d share it with you to solve multi language support problem for good now. It’s crossplatform, designed for the new ui and uses xml just like Android’s strings.xml. Check it out on AssetStore: