WoW:Localizing an addon
Cut-n-pasted from http://forums.curse-gaming.com/showthread.php?t=259 thanks to Islorgris.
Here is a "small" post to explain how basic localization for addons can be done (translated from the post on the WoW french UI customization forum).
Overall, it's pretty simple, I hope this give authors some ideas of what is needed for localization and users some ideas of what kind of information is needed in order to make addon localization possible.
The locale
The locale is what makes it possible to know what language the interface is using and thus determine which specific code is going to be executed in a localized addon.
typically, this is used in a GetLocale block:
Code:
if (GetLocale() == "frFR") then
-- things for the french client
else
-- for the rest, usually english since it's the default language
end
"frFR": french "deDE": german "usEN": english "koKR": korean
Variables
The whole deal doing a successful addon localization is simply using the translated interface texts (as translated ingame) in the language you want to enable for the element you want to use (texts, item names, spells, etc.).
So, whenever texts (well almost) are used, they should be replaced by variables which will be set in a GetLocale block in order to give them the correct value for each locale
Currently, it is best to put these in a file separate from the main code (usually name localization.lua for easy reference but any name will do).
that file must then be declared in the xml part of the addon, juste before the other scripts that compose it, example:
Code:
<Script file="localization.lua"/> <Script file="GatherIcons.lua"/>
If this is a modification on an existing addon and you want to submit it to the author, it's better to use english for the variables names and to prefix them with the addon name (to prevent conflicts with existing variables from the game or from other addons), keep the original strings and put them in variables too so that the author can match them with his original code (don't forget to comment).
Example:
Code:
if (skillName == "Herbalism") then
GatherSkills.herbs = skillRank;
elseif (skillName == "Mining") then
GatherSkills.mining = skillRank;
end
becomes:
Code:
if (skillName == GATHERER_TRADE_HERBALISM) then
GatherSkills.herbs = skillRank;
elseif (skillName == GATHERER_TRADE_MINING) then
GatherSkills.mining = skillRank;
end
the GATHERER_TRADE_HERBALISM and GATHERER_TRADE_MINING variables are declared in the localization.lua file as follow:
Code:
if( GetLocale() == "frFR" ) then
-- french part
GATHERER_TRADE_HERBALISM="Botanique";
GATHERER_TRADE_MINING="Minage";
else
-- default, english
GATHERER_TRADE_HERBALISM="Herbalism";
GATHERER_TRADE_MINING="Mining";
end
As you could see in the example, you simply replace the original string between double quotes by the corresponding variable.
Warning: If you need to use a localized string in the xml files, you need to keep the double quotes around the variable name.
Example:
Code:
[FontString name="bcTM_PopupTitle" inherits="GameFontHighlight" text="TRACKMENU_TOOLTIP_MENU_TITLE"]
will allow to use the content of the TRACKMENU_TOOLTIP_MENU_TITLE variable for this xml element.
Grammar and case sensitivity
This part is usually only useful if the addon has to process sentences (extracted from the chat windows), such as in processing to keep specific parts of the string. In that case it can be necessary to add a GetLocale block since word are not always ordered in the same manner in various languages.
Example:
Quote:
copper vein => veine de cuivre
another thing linked to this is that since word placement may be different, uppercases may be applied on different words.
Examples:
Quote:
Damaged chest => Coffre endommagé Small damaged chest => Petit coffre endommagé
Accents
This is somewhat delicate, the lua scripting language in wow deals with accents directly as unicode which means 2 things:
First, it will not recognize an accent in a localized text if it's not in unicode and thus will not be able to match it to the accent that can be seen in the game interface.
In the previous example, if you try to match "endommagé" with the same string provided by the game, it will fail.
Second, since these are unicode char, they're actually coded on several distinct characters (usually 2), which has to be taken into account for string manipulations based on length.
The use of and UTF-8 compatible editor is a must if you're dealing with accented characters, otherwise they probably be converted to the local charset equivalent which will not match the ingame data.
For a list of codes corresponding to various accentuated characters see http://www.allegro-c.de/unicode/zcodes.htm (page is in german but the table allows to find what's needed quite easily).
For our earlier chest example, a string that will match the ingame data would look like:
Quote:
Coffre endommag\195\169
Unicode
WOW can recognize unicode charactor IF .lua file is saved in unicode format.
Check .lua file format:
The first two bytes of unicode file is "FF FE".
Open .lua file with UltraEdit(My favorite binary editor in windows). Change to binary mode (Use Ctrl-H or use menu Edit->Hex Edit). It should be "FF FE" at the beginning of the file if it is a unicode file, and almost every second byte is "00"
Save file in unicode format:
Open notepad, then open your file. Click File->Save As...
Select Unicode Encoding At the bottom of popup windows.
Put it anythere you want.
The single quote case
Single quote is a bit of a special case, it also has it's equivalent in unicode but this is actually not always the case ingame, has to be checked experimentally.
Examples:
Quote:
D\195\169couverte d'herbes ==> that match with game data Veine d'argent ==> this one used not to match, not true anymore in 1.2.2-4196 though.
As a guideline, especially check anything coming from chat windows since that's where the special coding seems (might not be true anymore for 1.2.2-4196 versions and up) to be used most often instead of the standard single quote.
Note: the unicode equivalent of the single quote seems to be coded on 3 characters
Check the GlobalStrings.lua
for some strings, Blizzard do the job for you, check the contents of the GlobalStrings.lua file (extracted from the Interface.mpq for the basis and from the patch.mpq for the latest up to date). This file contains predifined variables whose value are directly in the client's language.
A word on table ordering
Most tables in WoW are organized alphabetically which means that the order the entries appear in the table depends on the translation of the individual items that compose it.
Example: zone names in english clients (UK and US) for Kalimdor continent:
Ashenvale, Azshara, Darkshore, etc.
in the french client you have the following order:
Ashenvale, Azshara, Un'Goro Crater (translated as "Cratère d'Un'Goro"), etc.
3rd entry represent a different zone.
A static table supplying, say scaling values for the minimap based on zone order, would have to be "localized" in the sense that the table need to be sorted differently according to the client's locale to give correct values.
Moderate yourself
Not everything must have a translation, some things will not work anymore if they are translated. A classical example would be lua objects name (variables usually, functions occasionally) or xml objects (components names defined in the .xml file) that are reconstructed in order to be accessed.
Example:
getglobal(EN_DUR_FRAME..FrameName.."SlotLeft"):Show();
Here, we're getting an XML object to display it, the object name itself being rebuilt by appending together the variables EN_DUR_FRAME, FrameName and the "SlotLeft" character string.
Since the objects names are hard-coded in the .xml file, a translation in one of the variable used will result in a failure getting the objet in localized clients.
Final touch, the .toc file
The .toc file allows localization by adding entries postfixed by the locale they should appear on:
Example:
Quote:
- Title: Gatherer
- Title-frFR: Gatherer (en francais, in french)
- Notes: Gatherer, displays stuff you gather in your minimap
- Notes-frFR: Gatherer, affiche les objets recoltes dans la minicarte
The -frFR postfix indicate to a french localized client that a translation is available and should be prefered to the default (which most of the time correspond to english), if no "localized" entry exists for a specific client, the default one is displayed.
Addendum (patch 1.4.0): in patch 1.4.0 a slightly cryptic comment from Slouken on the US board announce that they left the decimal point to the european value (ie a coma). The impact of this is that table index that uses a strings containing a dot do not work anymore, since that behaviour didn't exist before patch 1.4.0 on european version, caution would be avoid using dots in text index for table.
Exemple: prior to patch this table was fine.
["FR 1.4.0"] = ...
Post patch, trying get the index content would result in an error because it was translated by the game engine to "FR 1,4,0" which of course doesn't match the index up there.