Supporting Mutliple Languages

I was speaking with @Ali_RS recently about jME-TrueTypeFont and happened to mention that one of the goals there was creating an environment that was more conducive to supporting multiple languages and it reminded me of a more general Java library I wrote a while ago and figured I’d share here.

JLing is a library that I created to help facilitate the creation of Java applications with support for more than one language. Inspired by the way localization is done in Android JLing is actually incredibly simple. You can find it on my Google Drive at JLing.zip - Google Drive

The sources and javadoc are included in the jar. Basic usage is quite simple, first, rather than directly include Strings in your game you write them into an XML file that contains multiple translations of the same string, each Translation is given the same identifier name. So, for example:

<Languages>
    <English>
        <entry name="language">We speak english.</entry>
    </English>

    <French>
        <entry name="language">Nous parlons français.</entry>
    </French>
</Languages>

Then in your application you instantiate a JLing object and set it to the desired language:

JLing jl = new JLing("Resources/Lang/Example.xml");
try {
    jl.setLanguage("English");
} catch (SAXException e) {
    //A problem was encountered parsing the XML file.
} catch (IOException ioe) {
    //A problem was encountered opening the file.
}

Keep in mind that JLing was not created specifically for jME so it does not use the assetManager, to use this you must store your XML files in a package in your jar, not the Assets folder. In the above example the package Resources.Lang was created and Example.xml was placed in that package.

Once the language is set you reference your strings via the name attribute so when you want to print something to the screen in the selected language you use JLing.get("identifierString"):

Label label = new Label(jl.get("language"));


try {
    jl.setLanguage("French");
} catch (SAXException e) {
    //A problem was encountered parsing the XML file.
} catch (IOException ioe) {
    //A problem was encountered opening the file.
}

Label label = new Label(jl.get("language"));

Another good point to note, when JLing parses the XML it loads all of the text for a particular language into a HashMap. This is probably no big deal for arcade shooters and such, but RPGs and other text heavy games might not want to have every String ever displayed throughout the entire game all loaded into memory at the same time. For these cases it is probably best to maintain multiple xml files, for instance you might have one containing all the text for one region in your RPG game world and another for another region then load the proper XML file when the player enters the respective region in the game.

Since we’re just talking about Strings here this could also be used to load different textures or fonts:

<Languages>
    <English>
        <entry name="UITexture">Textures/UI/English/Title.png</entry>
    </English>

    <French>
        <entry name="UITexture">Textures/UI/French/Title.png</entry>
    </French>
</Languages>

try {
    jl.setLanguage("French");
} catch (SAXException e) {
    //A problem was encountered parsing the XML file.
} catch (IOException ioe) {
    //A problem was encountered opening the file.
}

Texture = assetManager.loadTexture(jl.get("UITexture"));

You do not have to use JLing.setLanguage(String) every time you want to get a String, you only set the language once at which point JLing parses the XML file and loads all the strings from the selected language. When you want to change to a different language then you just call JLing.setLanguage(String) again.

Also good to note, XML files need to be parsed so certain special characters in your Strings should be replaced with entity references, for instance < should be replaced with &lt;. Check out the entity reference section here: http://www.w3schools.com/XML/xml_syntax.asp

P.S. I also made one for C# called CSLing http://1337atr.weebly.com/scripts.html

2 Likes

Just curious on this…
Whats wrong with .properties and inbuilt localisation support in java?

1 Like

Thanks a lot for sharing. :grinning:
Very useful.

I was also wondering what sort of capabilities this gives over and above the built-in localization support that java has?

From the looks of it, the XML format adds considerable formatting overhead to what is essentially a flat data structure. Properties also generally have one language per file, which would be handy when the text in a program balloons. One program I work with has approximately 1,080 text keys for interface elements and internal messages, and it’s not all that huge a program ~ 143,000 LOC. I would not want to have to scroll through all of that to update the Spanish translation.

If you use information from http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle or similar to force java to handle the properties files as UTF-8, the only thing you will have to escape is equals signs.

1 Like

Also, many times translation is farmed out to different sets of people for different languages… so often it’s important to have one language per file.

You can do one language per file and then just load a different file whenever you switch languages. I mean it’s up to the developer to split up their XML files however they want. One language in each file, all languages in one file, Latin languages in one file, Arabic in another, etcetera…

I guess I didn’t know .properties existed, but it does beg the question why Android uses XML instead of properties.

In Android localization files look like this:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Title</string>
    <string name="cancel_button">Cancel</string>
    
</resources>

Which is actually one language per folder. You have to place a “Strings.xml” file in each folder each named appropriately such as “values-en” and “values-fr.” Which is essentially the same as what I wrote except that in Android you can only have one language per file whereas with JLing that is optional.

It does… I can’t explain it. :slight_smile: Maybe it was just a “not invented here” issue. Does Android do any processing of those XML files into another form at build time when creating the binary to send to the phone? That could be part of it, I suppose.

Some developers just have a hard-on for XML, I guess. Could be what happened here.

Java ResourceBundles are a pretty common thing and nicely integrate right with Java. So I don’t know why they went a different direction.

Using Java localization with a property resource bundle, your example above would look like:

app_name = Title
cancel_button = Cancel

When Lemur supports localization automatically it will be using Java’s ResourceBundles. At least that’s been the plan since the beginning.

Possibly, but I think Oracle already sued Google and lost.

The “not invented here” issue is not about legality. It’s about the very typical developer bias against code they didn’t write themselves. Every developer is a victim of this at some point or another, some more than others. The general idea that “I didn’t write it so it must be crap” accompanies that level of confidence every software developer reaches at some point.

Some time later, they usually figure out that getting to their end destination is actually more important than reinventing the universe one brick at a time. Still, by then the pattern is ingrained and something as simple as “Meh, I don’t really like properties files” ends up with “Hey, look, I’ve reinvented Java localization for Android! Now with XML!!!” (Never mind that I’m 95% sure that XML files would work as ResourceBundle backings anyway.)

Probably, I just didn’t know about ResourceBundles because my only experience with localization was on Android which used XML. I assumed Java didn’t have any solution itself because I figured if it did then Android would just use that so I wrote JLing mirroring the way it’s done on Android.

If you ever want to drill in kind of “from the beginning”… you can look at this Java 1.1-aged content:
https://docs.oracle.com/javase/tutorial/i18n/

…used be one of the old Sun ‘trail’ web pages and has changed very little other than Oracle rebranding.

Localization runs deep in Java. Even down at the level of Date.toString() and String.format() type of stuff that uses localization to decide how to format dates, currency, and so on.

And just to be clear, the “not invented here” thing wasn’t picking on you but the original Android dev who decided to chart a different path.

And anyway, I’m only speculating. They might have had some good technical reasons for doing it… I just don’t see them at the moment.

They might have, I looked in a couple of my Android APKs that used localization and found that the resource folders for drawables were present, but not for Strings suggesting you may be right that the Strings XML files are being compiled to some other format when the APK is created.