Localisation for libgdx projects

Warning: Libgdx now counts with localisation support, rendering this approach obsolete.

Edit: I just added UTF-8 support

Localization is a key aspect in games, specially if you want to reach a wider audience. I recently ported Freegemas to the libgdx platform and, as the original one, I wanted to ship it with multi-language support. There is no such a thing as gettext for Java and I didn’t see the Android internationalization system as a good fit in a multiplatform development. That’s why I developed my little own internationalization module.

Download LanguagesManager.java

Its usage is extremely simple, first we need a media/languages.xml file where all the strings in our project will be located. The syntax is pretty straight forward, we lay language sections identified with the code for each language. Inside every language, we provide a list of key value pairs with the localized strings.

< ?xml version="1.0" encoding="UTF-8"?>
<languages>
   <!-- English -->
   <language name="en_UK" >
      <!--  Menu  -->
      <string key="Timetrial mode" value="Timetrial mode" />
      <string key="How to play" value="How to play" />
      <string key="Exit" value="Exit" />
   </language>

<!-- Spanish -->
   <language name="es_ES" >
      <!--  Menu  -->
      <string key="Timetrial mode" value="Contrarreloj" />
      <string key="How to play" value="Ayuda" />
      <string key="Exit" value="Salir" />
   </language>
</languages>

We can retrieve localized strings in our project through the LanguagesManager class and its getString() method. It’s been implemented using the Singleton design pattern as we only need one instance accessible from, potentially, everywhere in the code. When we ask our manager for a certain string we will use its key, if it finds it within the current language, it’ll return it, otherwise it’ll return the key itself. That’s why using strings in a base language (English) as keys can be a good idea, those will be returned by default.

For now, it uses lazy initialization which means it’ll load the language the first time the getInstance() method is called but that might change in the future. It automatically detects the system language (no matter if we are on Android or a desktop environment) and it fallsback to English if the system language is not among the available ones in the data/languages.xml file. However, you can explicitly specify the language you want to load through the loadLanguage() method.

LanguagesManager lang;

lang = LanguagesManager.getInstance();

String option1 = lang.getString("Timetrial mode");
String option2 = lang.getString("How to play");
String option3 = lang.getString("Exit");

Freegemas libgdx is open source (GPL v3) as is this internationalization module which means you’re more than welcome to download it, use it and improve it. If you do the latest, make sure you distribute it the same way as me.

  • Peter Silie

    Unfortunately that implementation does not support UTF-8 :-(

    • http://siondream.com David Saltares

      I’m fairly new to Java, what would I need to include/modify to add UTF-8 support?

      Thanks!

    • Peter Silie

      I’m also fairly new to Java. I was looking for a way to localize my libgdx game and your implementation works very good except of the missing UTF-8 support.

      I think the problem is that the libgdx XmlReader class only support 8 bit character encoding. I think it should work with the Java XMLReader class, but I’m not sure how to use it.

      here is an example:

      http://stackoverflow.com/questions/3287726/to-read-xml-file-in-utf-8-format-string-using-android

  • Peter Silie

    ok .. I’ve read some tutorials to learn how to parse XML files on android. Obviously it’s possible to use SAX or DOM.

    I’ve replaced your loadLanguage-function with an UTF-8 compatible version and it works fine on my device.

    Maybe the following code isn’t perfect and could be improved … usually i’m coding in C# or C++ ;-)


    import java.io.InputStream;

    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;

    import org.w3c.dom.Document;
    import org.w3c.dom.Element;

    import org.w3c.dom.NamedNodeMap;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;


    public boolean loadLanguage(String languageName)
    {
    try
    {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

    DocumentBuilder builder = factory.newDocumentBuilder();

    InputStream is = Gdx.files.internal(LANGUAGES_FILE).read();

    Document dom = builder.parse(is);
    Element root = dom.getDocumentElement();

    NodeList languages = root.getElementsByTagName("language");

    // Iterate through every language to fetch the one we're interested in
    for (int i = 0; i < languages.getLength(); ++i)
    {
    Node languageElement = languages.item(i);

    NamedNodeMap attributeMap = languageElement.getAttributes();

    // If it's the language we're looking for
    if(attributeMap.getNamedItem("name").getTextContent().equals(languageName))
    {
    // Empty language
    language.clear();

    // Fetch every string for that language
    NodeList languageElementNodes = languageElement.getChildNodes();

    for (int j = 0; j < languageElementNodes.getLength(); ++j)
    {
    Node stringNode = languageElementNodes.item(j);

    if(stringNode.getNodeName().equals("string"))
    {
    NamedNodeMap attributes = stringNode.getAttributes();

    language.put(attributes.getNamedItem("key").getTextContent(), (attributes.getNamedItem("value").getTextContent()));
    }
    }

    return true;
    }
    }
    }
    catch (Exception e)
    {
    System.out.println("Error loading languages file " + LANGUAGES_FILE + " " + e.getMessage());
    }

    return false;
    }

  • http://siondream.com David Saltares

    Thanks a lot for your help, that, and doing a little bit of further research I’ve managed to get UTF-8 working with my system. I’ve basically replaced libgdx’s XmlReader for the Java classic DOM.

    You can get the new version using the same link :-D. I’m working on multi-line strings now [1]

    [1] http://stackoverflow.com/questions/10439274/parse-xml-multi-line-string-in-java

    • phil

      Hi David,

      did you solve the multi-line problem?
      and how did you implement it?

      bye
      phil

  • biobob

    Hi David. You’re reinventing the wheel. I don’t say that it is bad thing because your solution can bring something new.

    Look at standard i18n implementation included in Java:
    ResourceBundle
    MessageFormat
    Support for Eclipse IDE

    I do Java as my main work for quite long but I’m fairly new to libGDX. Standard i18n can be maybe overkill for simple games. Maybe there’re some problems to run it under all of libGDX backends but it should be possible. Inspire yourself by all handy features of standard i18n (UTF-8, custom file formats, custom loaders, formats, plural forms etc.)

    • jardo

      Hi biobob;
      I think, David is not reinventing the wheel. If you want to use ResourceBundle for other character set then 8859-1 then you will fail on android devices under API 9 as Control class is not supported for android below API 9 (check this post http://blog.gemserk.com/2012/05/23/android-and-desktop-games-internationalization-using-java-and-libgdx/) and PropertyResourceBundle do not support Reader only InputStream on android (at least under API 9 as far as I know). You are right only if u use libgdx for desktop only. So the post from David is still valuable, even if u need to adapt for other charset then 8859.

  • Eason

    When I look into the code of XMLReader,
    I found the creator of XMLReader already opened the door for UTF-8 support for XMLReader.
    There are several kinds of parse methods, one of them accepts InputStream attribute.
    So we can just pass in InputStreamReader with UTF-8 charset and get the result.
    That’s it!

    [code]
    xmlReader.parse(new InputStreamReader(Gdx.files.internal( [path] ).read(), "UTF8" ));
    [/code]

  • http://www.siondream.com David Saltares

    Will try, thanks a lot!!!

  • uni

    Thank you for article. Translating application that way is really easy.

  • Absurd Ninja

    I’ve read your links on GPLv3, but I haven’t understood this point – can I use this localization module in a closed source, commercial project, or does any software this is used in need to be open source?

  • Absurd Ninja

    Actually, I think I found the answer, and it’s a very clear “No.”

    “The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .”

  • ugosan

    Nice work, really handy!
    there is a typo:
    “among the available ones in the media/languages.xml file” its actually data/languages.xml

    thanks!

    • http://siondream.com/ David Saltares Márquez

      Thanks a lot for the heads up, it’s fixed now. Also, glad it’s of help!

  • Drew G

    If you need a good tool for the i18n of your website, you should keep in mind https://poeditor.com. It organizes files and translation strings in a very useful way for translators and has many facilities.

    • http://siondream.com/ David Saltares Márquez

      It’s not a tool for my website, it’s for Java games. AFAIK, gettext support for Java is not great, am I wrong? I could also use `ResourceBundles`.

  • ratalaika

    Hello, I would recommend to update the link of the LanguageManager from google code to GitHub (https://github.com/siondream/freegemas-gdx/blob/master/freegemas/src/com/siondream/freegemas/LanguagesManager.java)

    Cause is the one that is with UTF-8 support :)

    • http://siondream.com/ David Saltares Márquez

      Good point! Thanks :-).