LocalizationModule - Mini-IT/SnipeWiki GitHub Wiki
The localization support in the Snipe server is built around the database tables. You can define the structure in the editor that adds a specific table from your project to the list of tables that need to have some fields localized. That structure also holds the list of localized fields. All localized strings are stored in a separate database table. You can download a generated .CSV file that contains all the base strings, localized strings in languages supported by your project, table row IDs and field names. The localization team can input the string translations into that .CSV and upload it again into the editor.
This table is then loaded into all slave servers at the server start, and can be reloaded by the trigger. The slave server has API to access it so you can send localized strings to the client. The client is expected to give a two-letter language ID during the login. This language ID will be used to return the appropriate strings.
When using the API to add table to the list of localized tables you can also set the flag to load the localization for it during the editor initialization. That way you will have access to the ingame localization in the editor if you need to have full editor localization for some purpose. Localizing the editor strings themselves is described in Editor Localization article.
Each string that has to be localized need to exist in some database table as a row field. Adding new tables to the list of localized tables is done through the snipe.edit.modules.LocaleEditCore
class with the addTables()
method. It accepts an array of structures defining the tables. The type definition for it is called snipe.edit.modules._LocaleTable
and contains the following fields:
Name | Description |
---|---|
editorLoadFull | If enabled, the editor will load this table in localization manager. |
fields | Database row fields to localize. |
hasUniqueID | If enabled, this table uses unique IDs. |
isCore | If enabled, marks this table as belonging to core. |
name | Table name. |
query | SQL query to select all rows from this table. |
Here's the usage example:
server.coreLocaleModule.addTables([
{
name: "Monsters",
fields: [ "name", "note" ],
query: "SELECT * FROM Monsters ORDER BY ID"
}]);
The link to the localization page is located in the bottom menu of the main page. On the localization module page you can see how many localized strings there are in the database, as well as a link to download the generated .CSV file and the form to upload it.
Note that the .CSV file will always be generated with at least one language column filled. This is the base database language and strings in it are taken from the tables that you want localized. Its two-symbol language ID needs to be written in the "database.lang" editor configuration variable.
The slave server localization code is located in snipe.slave.LocaleManager
class. It provides a single method getMap()
. The method returns a snipe.lib.LocaleMap
instance which is a parametric map with get()
method that takes language ID as a key and returns a localization row object. If that table does not have that row localized for that language, it returns the default row that needs to be supplied as an argument to getMap()
. So, why is this map parametric? Well, this allows us to receive the return type from the default row argument and use it in the get()
calls of the map. That way we don't have to check the returning value for null and we also get the strict type-checking in the process.
Let's take a look at the full module example:
import snipe.lib.LocaleMap;
class MonsterModule extends Module<Client, ServerTest>
{
var _map: Map<String, _Monster>;
public function new(srv: ServerTest)
{
super(srv);
// ...
}
override function loadTables()
{
_map = new Map<String, _Monster>();
var res = server.query("SELECT * FROM Monsters");
for (row in res)
{
var m: _Monster = {
id: row.id,
stringID: row.stringid,
name: row.name,
note: row.note,
locale: null
};
m.locale = server.localeManager.getMap("Monsters", row.id, {
name: row.name,
note: row.note,
});
_map.set("" + m.id, m);
}
}
public inline function getMonster(id: Int)
{
return _map.get("" + id);
}
}
typedef _Monster = {
var id: Int;
var stringID: String;
var name: String;
var note: String;
var locale: LocaleMap<{ name: String, note: String }>;
}
We load the monsters table in the loadTables()
server hook during the module initialization and we set the "locale" field to a map of localization rows for monsters table row with the given monster id.
So when you need to send monster info to the player, here's what you write:
public override function call(client: Client, type: String, params: Params): Dynamic
{
var response = null;
if (type == "monster.get")
response = get(client, params);
return response;
}
function get(c: Client, params: Params)
{
var id = params.getInt("id");
var m = getMonster(id);
if (m == null)
return { errorCode: "noSuchMonster" };
var loc = m.locale.get(c.lang);
return { errorCode: "ok", name: loc.name, note: loc.note };
}
Note that you don't need to check for loc == null
and the compiler will show you an error if you try to access any other fields in "loc" variable except name and note.