Minecraft Modding: Localization

Background

Like any video game, Minecraft contains various places where text is displayed on the client. This is things such as the loading messages, any of the GUIs, in-game commands, tool-tips, advancement "toast" messages, and so forth. For users in different regions that speak different languages, all this text needs to be translated (called "localization").

Localization is done with  .lang files which are text resource assets that map unlocalized "names" to your language. For example, the Amercian english text would be in the en_US.lang file.

Tip: Check out the list of supported languages.

Tip: The various .lang files should be in a package named assets.<modid>.lang (where you replace <modid> with the actual mod id for your mod.

Warning: Make sure you capitalize the file name properly: en_us.lang is correct for resource format 3 (introduced in 1.11 and indicated in your pack.mcmeta file) and en_US.lang is correct for resource format 2 (earlier versions of Minecraft or if you have no pack.mcmeta file).

Warning: If you save the .lang file as UTF-8 make sure you choose option to save with BOM (byte-order mapping) or it won't be read properly.


Where Are The Other .lang Files Located?


If you look at the Referenced Libraries in your Eclipse project you'll find that the Minecraft assets only contain the en_us.lang file. So where are the other language files?

Thanks to Choonster for explaining this: Mojang distribute the sounds and alternative language files through a separate resource repository system, these are stored with hashed names in .minecraft/assets (outside of the development environment) or ~/.gradle/caches/minecraft/assets (inside of the development environment). 

Standard .lang File Key List


You can create your own custom types of localizations but there are also many standard ones. In the case of standard localizations, the unlocalized names are converted to keys by prepending the type (e.g. "item." or "tile.") to the front and in some cases (it is kind of inconsistent) postpending ".name" to the end.

Here are examples of the ones I'm aware of (replace <unlocalizedname> with unlocalized name that makes sense in your mod:
  • item.<unlocalizedname>.name for items
  • tile.<unlocalizedname>.name for blocks and ores
  • entity.<unlocalizedname>.name for entities (not sure why but sometimes it seems to want entity.<modid>.<unlocalizedname>.name
  • death.attack.<unlocalizedname> for what it says if you're killed by specified entity
  • itemGroup.<unlocalizedname> for name of creative tab
  • container.<unlocalizedname> for name of container
  • fluid. for name of fluid
Warning: For some reason the .lang file is strict about the assignment operator -- you cannot have any space after the equals sign.  (But you can have spaces in the text that follows.)

Key Point: Built in methods for setting unlocalized names (e.g. for Items) typically add some test to the string before doing the localization lookup. So if you set the unlocalized name of your item to "my_item" the lang file needs an entry for "item.my_item.name". However, for any other translations you might want to do you can simply reference the lang as is (see section below on custom translations).

Here is an example of one of my en_US.lang files:

entity.tiger.name=Tiger
entity.maneatingtiger.name=Man-Eating Tiger
entity.lion.name=Lion
entity.jaguar.name=Jaguar
entity.lynx.name=Lynx
entity.python.name=Python
entity.elephant.name=Elephant

tile.tomatoes.name=Tomatoes
tile.blueberries.name=Blueberries
tile.stove.name=Stove
tile.stove_lit.name=Stove
tile.pantry.name=Pantry

item.tomato.name=Tomato
item.blueberry.name=Blueberry

itemGroup.Recipe+=Recipe+

container.stove=Stove
container.pantry=Pantry


Referencing Custom .lang File Entries


In addition to the standard localizations, you can create your own. For example, maybe you are creating a HUD that displays some extra text, or maybe you have special messages you want to send. In that case you can use the I18n.format() method to look up the localization string.

For example, you could create a lang file entry in your en_us.lang called test.my_message.hello=Hello, world and in your fr_fr.lang called test.my_message.hello=Bonjour, la monde then you could print out that message by getting the translated string with I18n.format("test.my_message.hello"). If the language was English it would return "Hello, world" and if the language was French it would return "Bonjour, la monde".

Tip: It is recommended that every text string you display uses lang files for possible translation.

Making A Lang File That Contains Escape Characters


Thanks to diesieben07 for this tip.

In strings, sometimes you want to include special things like newline or color codes. These are usually represented by some character that is unlikely to be in a real string followed by a code. These are called "escape characters".

By default, FML will ignore escape characters in the lang file. However, it is possible to make FML process them by marking your language file as "special" by placing "#PARSE_ESCAPES" in the first line of the file. FML will then load the language file as if it were a standard Java properties file.

Checking What Language Is Currently Loaded From Client Side


Thanks to diesieben07 for this tip.

The game may be played in various languages (called "localization"), and if you want your mod to be international you might want any text resources to have translations.  Many text fields (like names of entities) are already translated via the .lang file mechanism, but there may be situations where you want to process the localization yourself.  Since languages are related to GUI, the language is a client-side value.

You can check the current language using the following (client-side!) method:

Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage()

If you're worried about the language changing during game play (a rare occurrence as most people would install Minecraft with language of choice) you can either poll the above method or you can use the IResourceManagerReloadListener interface to detect when the ResourceManager reloads (that happens when the language is changed, too).

Checking What Client Language Is From Server Side


If you're making a server-only mod, you may run into the situation where you want to send messages to the client but since the mod is not installed on the client you can't rely on the normal chat translation methods.

Apparently (I haven't tried this out), EntityPlayerMP has private String translator field (that gets set during the player joining with the C15PacketClientSettings packet, with values like "en_US";

It's private so you'd need to use Java reflection to get it, there's no getter method for it.

4 comments:

  1. In 1.11.2, use en_us.lang instead of en_US.lang!!!
    It took me hours to figure it out!

    ReplyDelete
    Replies
    1. thx i did the same before your comment.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. So it turns out that it depends on the pack.mcmeta file in your mod. If you look at the one in recent (1.11 and later) MDK distributions you'll see that it sets the "format" as "3" which apparently tells Forge to use the all-lower-case format. Otherwise, if you have an older pack.mcmeta or no pack.mcmeta then it will assume format 2 (mixed-case format)

      Delete