DEV Community

Discussion on: Speed-up your internationalization calls up to 5-1000 times

 
vince_tblt profile image
Vincent Thibault

Ok, I note the suggestion, I'll try to implement it this week end, something like the onMissingKey is working :

frenchkiss.onMissingVariable((value, key, lang) => {
  // report it
  sendReport(`variable "${value}" in ${lang}->${key} is missing.`);

  // the value you want to use instead
  return `[${value}]`;
});
Thread Thread
 
vince_tblt profile image
Vincent Thibault • Edited

Just saw your comment about SELECT optimization.

I already did some tests with it working using an object mapping to values, but it doesn’t work well with nested expressions.

With nested expressions, you can’t really pre-cache objects and it will execute all the possible branches code before doing the resolution leading to performance issue.

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

With nested expressions you can have functions for some branches and strings for some. :v
Don't know about performance, but it is usually very compact, and you just need one helper:

const e = (table, x, p) => {
  const val = table[p]
  return typeof val === "function" ? val(x) : val
}
const a = { a: "A", b: "chungus" }
const b = { a: "B", b: x => `<${e(a, x, x.a)}>` }
const c = { a: "Cfunction b(x) {", b: x => `[${e(b, x, x.b)}]` }
const rule = x => `Yo, ${e(c, x, x.c)}`

const prop = { a: "b", b: "b", c: "b" }
console.log(rule(prop))
prop.a = "a"
console.log(rule(prop))
prop.b = "a"
console.log(rule(prop))
prop.c = "a"
console.log(rule(prop))
Thread Thread
 
vince_tblt profile image
Vincent Thibault

Not really so compact if you transpile it to ES5.
Here is an example of a complete solution (if I don't miss a thing ?).

The translation :

Updated: {minutes, plural,
  easteregg {never}
  =0 {just now}
  =1 {one minute ago}
  other {
    {minutes} minutes ago by {gender, select,
      male {male}
      female {female}
      other {other}
    }
  }
}

The global functions

// Global SELECT
function getBranchData(
  branch,
  prop,
  params,
  getPluralCategory,
  onMissingVariable,
  key,
  language
) {
  var data = branch.hasOwnProperty(prop) ? branch[prop] : branch.other; // fallback to 'others'

  return typeof data === "function"
    ? data(params, getPluralCategory, onMissingVariable, key, language)
    : data;
}

// Global PLURAL
function getBranchPluralData(
  branch,
  prop,
  params,
  getPluralCategory,
  onMissingVariable,
  key,
  language,
) {
  var category = getPluralCategory && getPluralCategory(params[prop]);
  var data;

  if (branch.hasOwnProperty(prop)) {
    // direct assignment
    data = branch[prop];
  } else if (category && branch.hasOwnProperty(category)) {
    // category check (easter egg)
    data = branch[category];
  } else {
    // default to other
    data = branch.other;
  }

  return typeof data === "function"
    ? data(params, getPluralCategory, onMissingVariable, key, language)
    : data;
}

// Global Interpolation
function handleInterpolation(params, prop, onMissingVariable, key, language) {
  return !params.hasOwnProperty(prop)
    ? onMissingVariable(prop, key, language)
    : typeof params[prop] === "number"
    ? params[prop]
    : params[prop] || "";
}

The generated function demo:

function functionGenerator() {
  // Closure to avoid re-defining branches at each call
  var branchA = {
    0: "just now",
    1: "one minute ago",
    other: function(params, getPluralCategory, onMissingVariable, key, language) {
      return (
        handleInterpolation(params, "minutes", onMissingVariable, key, language) +
        " minutes ago by " +
        getBranchData(
          branchB,
          params.gender,
          params,
          getPluralCategory,
          onMissingVariable,
          key,
          language
        )
      );
    }
  };

  var branchB = {
    male: "male",
    female: "female",
    other: "other"
  };

  return function(params, getPluralCategory, onMissingVariable, key, language) {
    return (
      "Updated: " +
      getBranchPluralData(
        branchA,
        params.minutes,
        params,
        getPluralCategory,
        onMissingVariable,
        key,
        language
      )
    );
  };
}

var fn = functionGenerator();
fn({
  minutes: 5,
  gender: "male"
});

I'll probably do a branch to see if it's a good candidate.

Thread Thread
 
qm3ster profile image
Mihail Malo
        params,
        getPluralCategory,
        onMissingVariable,
        key,
        language

should probably be an object, passed by reference instead of individually through arguments?