Hello tools-l10n,

Below you'll find a summary of my thought process behind the next 
revision of the L20n API.  I split it into three emails for your 
reading convenience:

 Email #1: Design goals and constraints (this email)
 Email #2: Language registration
 Email #3: Specifying and modifying the supported languages
 Email #4: Getting translations

* * *

L20n API versions 1.0 and 2.0 (see [1] for the story behind versions 
and how they map to branches) were based on a concept of a single 
localization context which held the state of language negotiation and 
resource loading.  These contexts also had a synchronous 'get' method 
for retrieving translations which in case of errors internally made use 
of sync XHR calls to fetch resources in fallback languages.

For the past year of working on Gaia's l10n.js (L20n API 2.0), we have 
learned a lot about what a good localization framework should look 
like.  Here are some high-level design criteria for API 3.0:

Design goals:

 G1. when translations fail to load or format the fallback should be 
     graceful,
 G2. apps can be available in more langs than they're bundled with,
 G3. it should be easy to create multiple contexts per document.

Design constraints:

 C1. user language preferences are an array in which ordering matters,
 C2. resources can only be fetch asynchronously

Note that G1 has already been achieved in API 2.0 to some extent.  
However, to achieve other goals and keep within the constraints, we 
need to make a number of breaking changes to the API. Following is the 
run-down, based on the goals that we want to meet.

Consequences:

 G1. There's a chain of languages negotiated between the user's 
     preferred languages (see C1) and the app's available ones;  I'll 
     call them supported languages.

     When a translation in one supported language errors out, the next 
     supported language is fetched to fall back on;  this means that 
     the 'get' method needs to be asynchronous.

 G2. An app can register a number of languages with the l10n framework 
     to say 'here are the languages I'm available in';  this list can 
     be extended by a language package service, so the registration 
     needs to be asynchronous.

 G3. Multiple contexts per document can still share the state of 
     language negotiation.  It should be possible then to abstract the 
     language negotiation into a higher-level object.

     In the rest of this thread, this higher-level object will be 
     called a localization environment (env for short).  Envs spawn 
     contexts.

We end up with two classes: environment and context, which interact 
with each other and which primarily use async methods.  This 
interaction is interesting: since all contexts share a common parent 
env, we can use the env as a cache to store localization resources.  
This way, creating new contexts which want to re-use resources is fast 
and easy.  In fact, all the information a context should have about 
itself is the order of resources in which to look translations up.  
Take the following for instance:

  var ctx1 = env.require(['res1.{locale}.l20n', 'res2.{locale}.l20n']);
  var ctx2 = env.require(['res2.{locale}.l20n', 'res3.{locale}.l20n']);

Actual localization files are fetched and stored by the env.  Res2 is 
fetched only once.  When ctx1.get(id) is called, we first look for the 
identifier in res1 and then in res2.  We don't even have to store flat 
AST for each context: we can simply iterate over the cached resources 
in the env.

The exact API of this will be the topic of my next email.  To know 
which files to fetch, the env has to already have negotiated its 
supported languages.  This is also where things become a bit tricky :)

Stay tuned,
-stas


[1] https://groups.google.com/forum/#!topic/mozilla.tools.l10n/MJ_sMgqOKT4


-- 
@stas
_______________________________________________
tools-l10n mailing list
[email protected]
https://lists.mozilla.org/listinfo/tools-l10n

Reply via email to