Skip to content

Instantly share code, notes, and snippets.

@kaneel
Last active December 20, 2015 01:49
Show Gist options
  • Select an option

  • Save kaneel/6052331 to your computer and use it in GitHub Desktop.

Select an option

Save kaneel/6052331 to your computer and use it in GitHub Desktop.
Simple i18n requireJS module for your simple architectures™
/*
You "should" define dict in requireJS path config so you're able, at load, to get the
right lang from wherever you want (lang attribute on <html> tag for example?)
Also, you'll need both text and json plugins for requires.
var config = {
paths: {
dict: "ur/path/to/dictionnary",
i18n: "ur/path/to/i18n"
text: "ur/path/to/plugins/text",
json: "ur/path/to/plugins/json"
}
});
*/
// usage
define["i18n"], function(i18n) {
/*
i18n has been made for using the same dictionnary that is used by the backend.
Hence, we have some strings containing variables (declared with $1, $2) so we
can generate the strings passing values (as numbers).
Calling i18n will return either a variable or a function.
The function has a toString method that will simply return the translated string at his
actual state (idea from Stefan Grinsted, hi there :)
Let say that "that/stuff/inside/json" => "$1 and $2"
*/
var test = i18n("that/stuff/inside/json"); // "$1 and $2"
test([10,12]); // "10 and 12"
// the i18n method has been curried so...
test = i18n("that/stuff/inside/json", 10); // "10 and $2"
test(12); // "10 and 12"
// Or
test = i18n("that/stuff/inside/json", [null, 12]); // "$1 and 12"
test(10); // "10 and 12"
// Or, just because all the things you can see up there are not so useful
i18n("that/stuff/inside/json", [10, 12]); // "10 and 12"
})
// The module in itself, depends on your dictionnary.
define(["json!dict"], function(dict) {
var regexp = /\$\d/g; // regexp for search $ variables in a string
/*
Function for currying the translating method
Will take:
match => Array for matched elements
replaced => String (that may have already been modified)
Will return:
Returns of the execution of replacer. (l.48)
*/
function curry(match, replaced) {
function stringer(/* arguments */) {
var replacing = arguments,
toReplace = replaced;
if (replacing.length == 1 && replacing[0] instanceof Array) {
replacing = replacing[0];
}
return replacer(toReplace, replacing, match);
}
stringer.toString = function() {
return replaced;
}
return stringer;
}
/*
Replacing function.
Will loop on match (Array) and
Takes:
toReplace: Array
replacing: Array
match: Array
Return:
Function if there's still some variables to replace
String if there's no more variables to replace
*/
function replacer(toReplace, replacing, match) {
var toRemove = [];
// loop on matches
for (var i = 0, max = match.length; i < max; i++) {
// if there's a replacement for it
if(replacing[i]) {
// replace
toReplace = toReplace.replace(match[i], replacing[i]);
// push to array for later removal
toRemove.push(i);
}
}
// remove used matches
for (var i = 0, max = toRemove.length; i < max; i++) {
match.splice(toRemove[i], 1);
}
// if there's still matches
if (match.length) {
return curry(match, toReplace);
} else {
return toReplace;
}
}
/*
Main method.
Takes:
string: A string to translate
replacing: Array/String/Number for replacing $ variables.
Return:
If no need for "replacing", a String.
If all replacing arguments given, a String.
If partial arguments, a Function.
*/
function translate(string, replacing) {
var words = string.split("/"),
seq = dict,
replaced = "",
match = "";
// loop on splitted sequence
for (var i = 0, max = words.length; i < max; i++) {
// if not a string, go deeper
if (seq[words[i]] && typeof seq[words[i]] != "string") {
seq = dict[words[i]];
}
// if string, translate!
if (typeof seq[words[i]] == "string") {
replaced = seq[words[i]];
match = replaced.match(regexp);
// check if there's matches for variables
if (match) {
// if replacing array/number/string provided
if (replacing) {
// this will format a string or a number into an array.
// not perf savy but avoid condition-hell for dealing with many possible inputs
if(typeof replacing == "string" || typeof replacing == "number") {
replacing = [].concat(replacing);
}
// return what replace returns
// it's either a String or a Function
return replacer(replaced, replacing, match)
} else if (!replacing) {
// instantly return a curry
return curry(match, seq[words[i]]);
}
}
// not matches, simple translation
return seq[words[i]];
}
}
return words[words.length - 1]
}
return translate
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment