Tag Archives: JavaScript

Making of Anima: UNICO – Localization

Here I am again. Today I am going to address a tricky issue: localization, this is, translating the application to other languages. Just from the start, there are several issues with the process.

I can’t just translate every game term to other language: I have to find and use the word used in the official translation. Luckily, I count with the great help of Vincent ‘Moklo’ Bouscarle, corrector of the French edition of the game, who is translating A:U to French, and Andre ‘Dynaes’ Reich, from the English forum, who is translating to English. I want to use this chance to, again, thank both for their help.

As I have explained before, Anima: UNICO is designed mostly in three layers. Model layer organizes information. Controller layer knows the models and the views and manages the generakl workflow of the application. The View layer gets data from the Controller and shows what the user sees in the screen. Only this layer has to be translated.

My solution

function setIdiomaUI() {
   var lang = navigator.language || navigator.userLanguage;
   
   if ((lang.lastIndexOf("es") != -1) || (lang.lastIndexOf("spa") != -1)) {
      IDIOMA_UI = SPA;
   } else {
      IDIOMA_UI = ENG;
   }
}
function L(id, spa, eng) {
   this.id = id;
   this[SPA] = spa;
   this[ENG] = eng;
   if (!diccionario["ANIMAUNICO_"+this.id]) {
      diccionario["ANIMAUNICO_"+this.id] = this;
   } else {
      console.log("Clave de diccionario repetida: [" + this.id + " / " + this[SPA] + " / " + this[ENG] + "]");
      console.log("--Clave previa: [" + diccionario["ANIMAUNICO_"+this.id].id + " / " + diccionario["ANIMAUNICO_"+this.id][SPA] + " / " + diccionario["ANIMAUNICO_"+this.id][ENG] + "]");
   }
}
L.prototype = {
   constructor: L,
   toString : function() {
      return this[IDIOMA_UI];
   },
   getId : function() {
      return this.id;
   }
};
function _l(clave) {
   if (diccionario["ANIMAUNICO_"+clave]) {
      return diccionario["ANIMAUNICO_"+clave].toString();
   } else {
      return clave;
   }
}

A bit of explanation: I have a class, L, that will be instantiated with every string to translate and its translations. I also have a function, _l, that gets the id of a string and returns the translation to the current user interface language. The Model and Controller layers work only with the id of the strings, which are unique. When the View layer shows any string in screen, it does so through the _l function.

The initialization of strings is like this:

var UI_DAÑO_FINAL = (new L("UI_DAÑO_FINAL","Daño final","Final Dmg.")).getId();
var UI_VELOCIDAD = (new L("UI_VELOCIDAD","Velocidad","Speed")).getId();
var UI_TURNO_FINAL = (new L("UI_TURNO_FINAL","Turno final","Final Init.")).getId();

As you can see, this is only for spanish and english. When the french localization starts, I’ll just have to add another field to the class L and another argument to every string.

Obviously, this solution still has several problems. For example, it is not specially good to form sentences with several variable parts, as it does not account for sintactic differences between languages. But for a character sheet, that will mostly show isolated terms, it is working well enough for me.

 

Making of Anima: UNICO – General structure

In my last post I went through the tools I’m using to develop Anima: UNICO. I have to add another one: SourceTree, a graphical UI for Git very useful and nice, and which makes easier following the GitFlow pattern. Obviously, I don’t need to use GitFlow (and actually I don’t follow it fully), but I like it, as a base over which organize me.

Now, let’s start with the meat. First, how to organice a javaScript application the size of Anima: UNICO? After my initial investigations, I arrived to the following workflow:

  1. I create as many Javascript files as I want/need, usually one per class.
  2. To publish them, I use Grunt to concatenate them and then to minify and uglify them. This way I get only one JavaScript file to publish on the web.

Regarding the organization of the javascript files, I’ve been following (more or less) Model-View-Controller patterns.

  • js/ – General folder for javascript files.
    • controller/ – Controllers.
    • data/ – Data.
    • view/ – Views.
    • model/ – Models.
    • locale/ – Localization.
    • libs/ – Third party libraries
    • vendor/ – Third party libraries
  • sass/ – SASS files.
  • img/ – Image files
  • fonts/ – Fonts
  • css/ –  CSS files.
  • index.html – Main web.
  • indexLocal.html – Main web for local debug.
  • Gruntfile.js – Grunt script.

Controllers

They control the communication between models, prepare data for the user, and receive the user actions and act on them.

Data

The concrete instance data for every class. This is, the data for every Advantage, Spell, Martial Art, etc.

There are several ways of storing data. As I wanted my application to work offline, I could not use a database. In the end, I stored them in their own initialization. This really is a bad idea. I should have stored them in JSON format from the start. In the future I will make the change.

An example:

addVentaja(new Ventaja( VENT_APRENDIZAJE_INNATO_EN_UN_CAMPO, “”, VENT_APRENDIZAJE_INNATO_EN_UN_CAMPO_DESC, REPETIBLE_OPCIONES, [2,3], [], true, [LISTA_TIPOS_SECUNDARIAS], [aprendizajeInnatoCampo], GRUPO_SECUNDARIAS ));

This line of code initialices the advantage “Natural Learner, Field”.

Views

Views generate the UI and interact with the user.

Models

Models are the base classes. Character, Race, MartialArt, etc…

Localization

Localization is everything related to showing the application in several languages. Right now, this means spanish and english, and french is in the works. For this, I have the inestimable help of Andrew “Dynaes” Reich and Vincent “Moklo” Bouscarle.

In another post I’ll detail how I do the localization.