Add Multiple Language Support to Your Unity Projects

Discussion in 'Scripting' started by Tryder, Oct 21, 2013.

  1. Tryder

    Tryder

    Joined:
    Mar 26, 2012
    Messages:
    89
    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:

    Code (csharp):
    1. <?xml version="1.0" encoding="utf-8"?>
    2. <languages>
    3.     <English>
    4.          <string name="app_name">Some Game</string>
    5.          <string name="score_text">Score: </string>
    6.     </English>
    7.  
    8.     <French>
    9.         <string name="app_name">Certains Jeux</string>
    10.         <string name="score_text">Score: </string>
    11.     </French>
    12.  
    13.     <German>
    14.         <string name="app_name">Einige Spiele</string>
    15.         <string name="score_text">Ergebnis: </string>
    16.     </German>
    17. </languages>
    Once the Lang Class has been initialized to a particular language you can reference the strings stored in your XML file as follows:

    Code (csharp):
    1. var scoreText : String = langClass.getString("score_text") + newScore.ToString();
    Furthermore you can reset the language on the fly with the following line:

    Code (csharp):
    1. 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.
     
    Last edited: Oct 22, 2013
  2. rattlesnake

    rattlesnake

    Joined:
    Jul 18, 2013
    Messages:
    32
    Thank youuuuu so muuuch ! it's awesome :D
     
  3. rattlesnake

    rattlesnake

    Joined:
    Jul 18, 2013
    Messages:
    32
    Ammmm I have an error :/

    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 ?
     
    Last edited: Nov 25, 2013
  4. Tryder

    Tryder

    Joined:
    Mar 26, 2012
    Messages:
    89
    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:

    Code (csharp):
    1. import System.Xml;
     
  5. shivansps

    shivansps

    Joined:
    Feb 26, 2014
    Messages:
    42
    This is to load it from resources folder directly, there seems to be no other way of using local storage outside of the editor.

    Code (JavaScript):
    1.     var xmlLang : TextAsset  = Resources.Load("lang") as TextAsset;
    2.     langClass = new Lang(xmlLang.text, currentLang, true);
    And to change it
    Code (JavaScript):
    1.         var xmlLang: TextAsset  = Resources.Load("lang") as TextAsset;
    2.         langClass.setLanguageWeb(xmlLang.text, currentLang);
     
  6. rodv27

    rodv27

    Joined:
    Nov 17, 2013
    Messages:
    10
    Is there a Csharp version of this?
     
  7. NareshKhandla

    NareshKhandla

    Joined:
    Aug 6, 2013
    Messages:
    24
    I want to write Gujarati language , please tell me how to do this. Thank you!.
     
  8. sGlorz

    sGlorz

    Joined:
    Dec 4, 2013
    Messages:
    17
    Hi, here is the C# version:

    Lang.cs

    Code (CSharp):
    1. /*
    2. The Lang Class adds easy to use multiple language support to any Unity project by parsing an XML file
    3. containing numerous strings translated into any languages of your choice.  Refer to UMLS_Help.html and lang.xml
    4. for more information.
    5.  
    6. Created by Adam T. Ryder
    7. C# version by O. Glorieux
    8.  
    9. */
    10.  
    11. using System;
    12. using System.Collections;
    13. using System.IO;
    14. using System.Xml;
    15.  
    16. using UnityEngine;
    17.  
    18. public class Lang
    19. {
    20.     private Hashtable Strings;
    21.  
    22.     /*
    23.     Initialize Lang class
    24.     path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    25.     language = language to use example:  "English"
    26.     web = boolean indicating if resource is local or on-line example:  true if on-line, false if local
    27.  
    28.     NOTE:
    29.     If XML resource is on-line rather than local do not supply the path to the path variable as stated above
    30.     instead use the WWW class to download the resource and then supply the resource.text to this initializer
    31.  
    32.     Web Example:
    33.     var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    34.     yield wwwXML;
    35.      
    36.     var LangClass : Lang = new Lang(wwwXML.text, currentLang, true)
    37.     */
    38.     public Lang ( string path, string language, bool web) {
    39.         if (!web) {
    40.             setLanguage(path, language);
    41.         } else {
    42.             setLanguageWeb(path, language);
    43.         }
    44.     }
    45.  
    46.     /*
    47.     Use the setLanguage function to swap languages after the Lang class has been initialized.
    48.     This function is called automatically when the Lang class is initialized.
    49.     path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    50.     language = language to use example:  "English"
    51.  
    52.     NOTE:
    53.     If the XML resource is stored on the web rather than on the local system use the
    54.     setLanguageWeb function
    55.     */
    56.     public void setLanguage ( string path, string language) {
    57.         var xml = new XmlDocument();
    58.         xml.Load(path);
    59.      
    60.         Strings = new Hashtable();
    61.         var element = xml.DocumentElement[language];
    62.         if (element != null) {
    63.             var elemEnum = element.GetEnumerator();
    64.             while (elemEnum.MoveNext()) {
    65.                 var xmlItem = (XmlElement)elemEnum.Current;
    66.                 Strings.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
    67.             }
    68.         } else {
    69.             Debug.LogError("The specified language does not exist: " + language);
    70.         }
    71.     }
    72.  
    73.     /*
    74.     Use the setLanguageWeb function to swap languages after the Lang class has been initialized
    75.     and the XML resource is stored on the web rather than locally.  This function is called automatically
    76.     when the Lang class is initialized.
    77.     xmlText = String containing all XML nodes
    78.     language = language to use example:  "English"
    79.  
    80.     Example:
    81.     var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    82.     yield wwwXML;
    83.      
    84.     var LangClass : Lang = new Lang(wwwXML.text, currentLang)
    85.     */
    86.     public void setLanguageWeb ( string xmlText, string language) {
    87.         var xml = new XmlDocument();
    88.         xml.Load(new StringReader(xmlText));
    89.      
    90.         Strings = new Hashtable();
    91.         var element = xml.DocumentElement[language];
    92.         if (element != null) {
    93.             var elemEnum = element.GetEnumerator();
    94.             while (elemEnum.MoveNext()) {
    95.                 var xmlItem = (XmlElement)elemEnum.Current;
    96.                 Strings.Add(xmlItem.GetAttribute("name"), xmlItem.InnerText);
    97.             }
    98.         } else {
    99.             Debug.LogError("The specified language does not exist: " + language);
    100.         }
    101.     }
    102.  
    103.     /*
    104.     Access strings in the currently selected language by supplying this getString function with
    105.     the name identifier for the string used in the XML resource.
    106.  
    107.     Example:
    108.     XML file:
    109.     <languages>
    110.         <English>
    111.             <string name="app_name">Unity Multiple Language Support</string>
    112.             <string name="description">This script provides convenient multiple language support.</string>
    113.         </English>
    114.         <French>
    115.             <string name="app_name">Unité Langue Soutien Multiple</string>
    116.             <string name="description">Ce script fournit un soutien multilingue pratique.</string>
    117.         </French>
    118.     </languages>
    119.  
    120.     JavaScript:
    121.     var appName : String = langClass.getString("app_name");
    122.     */
    123.     public string getString (string name) {
    124.         if (!Strings.ContainsKey(name)) {
    125.             Debug.LogError("The specified string does not exist: " + name);
    126.          
    127.             return "";
    128.         }
    129.  
    130.         return (string)Strings[name];
    131.     }
    132.  
    133. }
    TestGui.cs

    Code (CSharp):
    1. /*
    2. This example script demonstrates how to use the Unity Multiple Language Support Lang class in a simple GUI.
    3. The accompanying lang.xml file should be placed into your project's Assests folder.
    4.  
    5. -Adam T. Ryder
    6. C# version by O. Glorieux
    7. */
    8.  
    9. using System.IO;
    10. using UnityEditor;
    11.  
    12. using UnityEngine;
    13.  
    14. public class NewMonoBehaviour : Editor
    15. {
    16.  
    17.     private Lang LMan;
    18.     private string currentLang = "English";
    19.  
    20.     public void OnEnable()
    21.     {
    22.         /*
    23.     Initialize the Lang class by providing a path to the desired language XML file, a default language
    24.     and a boolean to indicate if we are operating on an XML file located from a downloaded resource or local.
    25.     True if XML resource is on the web, false if local
    26.  
    27.     If initializing from a web based XML resource you'll need to supply the text of the downloaded resource in placed
    28.     of the path.
    29.  
    30.     web example:
    31.     var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    32.     yield wwwXML;
    33.      
    34.     LMan = new Lang(wwwXML.text, currentLang, true);
    35.     */
    36.         LMan = new Lang(Path.Combine(Application.dataPath, "lang.xml"), currentLang, false);
    37.     }
    38.  
    39.     public void OnGUI()
    40.     {
    41.         /*
    42.     To access a string in the currently set language use the Lang class' getString function with the string name identifier supplied to it.
    43.     */
    44.         GUI.Label(new Rect(0, 0, 800, 450), LMan.getString("app_name") + "\n" + LMan.getString("description"));
    45.  
    46.         if (GUI.Button(new Rect(0, 450 - 24, 800, 24), "Language:  " + currentLang))
    47.         {
    48.             if (currentLang == "English")
    49.             {
    50.                 currentLang = "French";
    51.             }
    52.             else if (currentLang == "French")
    53.             {
    54.                 currentLang = "German";
    55.             }
    56.             else
    57.             {
    58.                 currentLang = "English";
    59.             }
    60.  
    61.             /*
    62.         To switch languages after the Lang class has been initialized call the setLanguage function
    63.         and provide a path to the desired XML resource and the desired language.
    64.      
    65.         If the XML resource is located on the web you'll need to use the WWW class to download the resource
    66.         and then supply the text of the downloaded resource in place of the path to the Lang class' setLanguageWeb function.
    67.      
    68.         web example:
    69.         var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    70.         yield wwwXML;
    71.      
    72.         LMan.setLanguageWeb(wwwXML.text, currentLang);
    73.         */
    74.             LMan.setLanguage(Path.Combine(Application.dataPath, "lang.xml"), currentLang);
    75.         }
    76.     }
    77. }
    78.  
     
    gn.gametorque likes this.
  9. shivansps

    shivansps

    Joined:
    Feb 26, 2014
    Messages:
    42
    I just wanted to share the script im using with the new UI system in order to handle static text elements.

    Code (JavaScript):
    1. #pragma strict
    2. private var Stats : GameStatics;
    3. private var Init = false;
    4. private var code : String;
    5. private var text : UI.Text;
    6.  
    7. function Start ()
    8. {
    9.     var cam=GameObject.Find("MainCamera");
    10.     Stats=cam.GetComponent(GameStatics); //The script where the langclass is
    11.  
    12.     text=this.transform.GetComponent(UI.Text);
    13.     code=text.text;
    14.  
    15.     Init=true;
    16. }
    17.  
    18. function Update ()
    19. {
    20.     if(Init) UpdateLang();
    21. }
    22.  
    23. public function UpdateLang ()
    24. {
    25.     text.text=Stats.langClass.getString(code);
    26.     Init=false;
    27. }
    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
    Code (JavaScript):
    1. public function UpdateLang ()
    2. {
    3.     text.text=GameObject.Find("MainCamera").GetComponent(GameStatics).langClass.getString(code);
    4.   Init=false;
    5. }
    should work just fine as well
     
    Last edited: Jan 21, 2015
  10. shivansps

    shivansps

    Joined:
    Feb 26, 2014
    Messages:
    42
    Does not work on WebGL, ive not really when into finding out why.

    Code (JavaScript):
    1. Strings.Add(elemEnum.Current.GetAttribute("name"), elemEnum.Current.InnerText);
    looks like "GetAttribute" and "InnerText" are not implemented.
     
  11. shivansps

    shivansps

    Joined:
    Feb 26, 2014
    Messages:
    42
    Thanks to jonas echterhoff that helped me, i was able to fix this in order to work in WebGL platform.

    Code (JavaScript):
    1. #pragma strict
    2. /*
    3. The Lang Class adds easy to use multiple language support to any Unity project by parsing an XML file
    4. containing numerous strings translated into any languages of your choice.  Refer to UMLS_Help.html and lang.xml
    5. for more information.
    6.  
    7. Created by Adam T. Ryder
    8.  
    9. 10/3/2015 (unofficial by shivansps)
    10. Fixed for WebGL
    11. */
    12.  
    13. import System.Xml;
    14.  
    15. public class Lang
    16. {
    17.     private var Strings : Hashtable;
    18.    
    19.     /*
    20.     Initialize Lang class
    21.     path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    22.     language = language to use example:  "English"
    23.     web = boolean indicating if resource is local or on-line example:  true if on-line, false if local
    24.    
    25.     NOTE:
    26.     If XML resource is on-line rather than local do not supply the path to the path variable as stated above
    27.     instead use the WWW class to download the resource and then supply the resource.text to this initializer
    28.    
    29.     Web Example:
    30.     var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    31.     yield wwwXML;
    32.        
    33.     var LangClass : Lang = new Lang(wwwXML.text, currentLang, true)
    34.     */
    35.     function Lang ( path : String, language : String, web : boolean ) {
    36.         if (!web) {
    37.             setLanguage(path, language);
    38.         } else {
    39.             setLanguageWeb(path, language);
    40.         }
    41.     }
    42.    
    43.     /*
    44.     Use the setLanguage function to swap languages after the Lang class has been initialized.
    45.     This function is called automatically when the Lang class is initialized.
    46.     path = path to XML resource example:  Path.Combine(Application.dataPath, "lang.xml")
    47.     language = language to use example:  "English"
    48.    
    49.     NOTE:
    50.     If the XML resource is stored on the web rather than on the local system use the
    51.     setLanguageWeb function
    52.     */
    53.     public function setLanguage ( path : String, language : String) {
    54.         var xml : XmlDocument = new XmlDocument();
    55.         xml.Load(path);
    56.        
    57.         Strings = new Hashtable();
    58.         var element : XmlElement = xml.DocumentElement.Item[language];
    59.         if (element) {
    60.             var elemEnum : IEnumerator = element.GetEnumerator();
    61.             while (elemEnum.MoveNext()) {
    62.                 Strings.Add((elemEnum.Current as XmlElement).GetAttribute("name"), (elemEnum.Current as XmlElement).InnerText);
    63.             }
    64.         } else {
    65.             Debug.LogError("The specified language does not exist: " + language);
    66.         }
    67.     }
    68.    
    69.     /*
    70.     Use the setLanguageWeb function to swap languages after the Lang class has been initialized
    71.     and the XML resource is stored on the web rather than locally.  This function is called automatically
    72.     when the Lang class is initialized.
    73.     xmlText = String containing all XML nodes
    74.     language = language to use example:  "English"
    75.    
    76.     Example:
    77.     var wwwXML : WWW = new WWW("http://www.exampleURL.com/lang.xml");
    78.     yield wwwXML;
    79.        
    80.     var LangClass : Lang = new Lang(wwwXML.text, currentLang)
    81.    
    82.     ADDED: 10/3/2015 (unofficial by shivansps)
    83.     setLanguageWeb can also be used to load the xml file directly from the resources folder
    84.    
    85.     Example:
    86.     var xmlLang: TextAsset  = Resources.Load("lang") as TextAsset;
    87.     langClass.setLanguageWeb(xmlLang.text, currentLang);
    88.     */
    89.     public function setLanguageWeb ( xmlText : String, language : String) {
    90.         var xml : XmlDocument = new XmlDocument();
    91.         xml.Load(new StringReader(xmlText));
    92.        
    93.         Strings = new Hashtable();
    94.         var element : XmlElement = xml.DocumentElement.Item[language];
    95.         if (element) {
    96.             var elemEnum : IEnumerator = element.GetEnumerator();
    97.             while (elemEnum.MoveNext()) {
    98.                 Strings.Add((elemEnum.Current as XmlElement).GetAttribute("name"), (elemEnum.Current as XmlElement).InnerText);
    99.             }
    100.         } else {
    101.             Debug.LogError("The specified language does not exist: " + language);
    102.         }
    103.     }
    104.    
    105.     /*
    106.     Access strings in the currently selected language by supplying this getString function with
    107.     the name identifier for the string used in the XML resource.
    108.    
    109.     Example:
    110.     XML file:
    111.     <languages>
    112.         <English>
    113.             <string name="app_name">Unity Multiple Language Support</string>
    114.             <string name="description">This script provides convenient multiple language support.</string>
    115.         </English>
    116.         <French>
    117.             <string name="app_name">Unité Langue Soutien Multiple</string>
    118.             <string name="description">Ce script fournit un soutien multilingue pratique.</string>
    119.         </French>
    120.     </languages>
    121.    
    122.     JavaScript:
    123.     var appName : String = langClass.getString("app_name");
    124.     */
    125.     public function getString (name : String) : String
    126.     {
    127.         if (!Strings.ContainsKey(name))
    128.         {
    129.             Debug.Log("The specified string does not exist: " + name);
    130.            
    131.             return "Er:"+name;
    132.         }
    133.             return Strings[name];
    134.     }
    135.  
    136. }
     
  12. ITGeist

    ITGeist

    Joined:
    Dec 5, 2012
    Messages:
    63
    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;
     
  13. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Messages:
    23
    Im trying to write a xml according to your specifications, but I cant find a method to write a string like this:
    Code (CSharp):
    1. <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!
     
  14. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Messages:
    23
    Nevermind, figured it out. In case anyone need this in the future:

    Code (CSharp):
    1. writer.WriteStartElement("string");
    2. writer.WriteAttributeString("name", "app_name");
    3. writer.WriteString("Unity Multiple Language Support");
    4. writer.WriteEndElement();