5

I'm using Hogan.js, which is compatible with the Mustache spec. And im having trouble implementing a solid way of doing pluralization. I would like to keep using Hogan and use http://i18next.com/ for i18n handling

doing something like this works for the simple cases

tpl:

{{#plural(count)}}
  I have {{count}} apples!
{{/plural(count)}}

data:

{
  count: 2,
  'plural(count)': function () {
    return function () {
      return _t[arguments[0].trim()][this['count']]
    }
  }
}

this requires parsing/scanning/rendering in seperate steps to be able to generate all of the required plural methods (plural(key.val) etc.) but thats fine, it only needs to be done once, at server boot.

this breaks on things like

{{#plural(key.nested)}}

that would match if the data looked like

{
  'plural(key': {
    'val)': ...
  }
}

this also requires me to manually lookup the values from the context, not a major problem but there are some cases with lambda's/partials that might be impossible to resolve

for the default translation mappings, thing are a lot less complex, and thats easy to handle

Paul Scheltema
  • 1,993
  • 15
  • 25
  • Some Mustache implementations can handle this: https://github.com/groue/GRMustache/issues/50 – Gwendal Roué Dec 16 '13 at 16:29
  • @Gwendal Roué Thanks. I found it before posting also. Thats where my example code comes from. It is, however, hard to do without the renderer in the context of the lambda, and that lib isnt javascript (i will add javascript as a tag, to be more clear) – Paul Scheltema Dec 16 '13 at 17:38
  • A google search for "mustache template pluralization" yields a few other results as well... Won't you find a solution there? – Gwendal Roué Dec 17 '13 at 05:27
  • @Gwendal Roué I read all I could find, but none of the sollutions take pluralization into account. And if they do it results in re-rendering the processed template another (2) time(s) – Paul Scheltema Dec 17 '13 at 08:12
  • Looks like it's time for a feature request :-) – Gwendal Roué Dec 17 '13 at 10:36
  • @Gwendal Roué gonna put a bounty once its possible, hope that gives me some insights as to how. For now i've "quick-fixed" it by doing something as described, however more coplex variable resolving outisde of the current context isnt possible, so someday this will fail. – Paul Scheltema Dec 17 '13 at 17:07

1 Answers1

0

Ok found the way I think is best to handle this problem:

var tpl_data = fs.readFileSync('./tpl/test.hjs', 'utf8');
var scan = Hogan.scan(tpl_data);
var tree = Hogan.parse(scan);
var gen = Hogan.generate(tree, tpl_data, {asString:false});
var out = gen.render(data);

alter the tree, replacing all tag keys to i18n where the n matches your pattern /i18n .+/

I use {{#i18n {count: count, text: 'I have <%count%> apples!'} }} and the like to add the options for i18next so i match all n's starting with i18n

add the i18n to Hogan.codegen

Hogan.codegen.i18n = function (node, context) {
  context.code += 't.b(t.v(t.i18n("' + esc(node.n) + '",c,p,0)));';
}

add the i18n method to the prototype of Hogan.Template

Hogan.Template.prototype.i18n = function (key, ctx, partials, returnFound) {
  //here the ctx is an array with from right to left the render scopes
  // most right is the most inner scope, most left is the full render data
  //1. get the config from the key, 
  //2. get the values out of the scope
  //3. get the values for the translation
  //4. lookup the translation, and repleace the values in the translation
  //5. return the translated string
};

note that inside the Hogan.Template.prototype.i18n you can access all of the template's methods

Paul Scheltema
  • 1,993
  • 15
  • 25