Last active
December 15, 2015 09:39
-
-
Save bugwelle/5239617 to your computer and use it in GitHub Desktop.
This is a simple directive for AngularJS to use i18next.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* | |
* There is now an Angular directive, filter and provider! | |
* It can be found here: https://github.com/i18next/ng-i18next | |
* ng-i18next is now part of the i18next rganization! | |
* | |
*/ | |
/* | |
* AngularJS directive for using i18next (http://jamuhl.github.com/i18next) | |
* Usage: | |
* - include i18next-1.x.x.js | |
* - include your language files | |
* - add 'i18n' to your dependencies of your module | |
* -> 'angular.module('MyApp', ['i18next']);' | |
* - anywhere in your code change $rootScope.i18nextOptions to your options. | |
* Best practise: in | |
* angular.module('MyApp', ['i18next']).run(function ($rootScope) { | |
* $rootScope.i18nextOptions = { | |
* lng: 'de-DE', | |
* ... | |
* }; | |
* }); | |
* (Because it will run before the directive is initialized) | |
* - use the 'ng-i18next' attribute on any element you want | |
* -> '<p ng-i18next="myStringToTranslate"></p>' | |
* - You can also listen for the 'i18nextInit' event. Then you can translate | |
* via i18n.t('Your String here'); | |
* -> $scope.$on('i18nextInit', function () { | |
* console.log(i18n.t('hello')); | |
* }); | |
*/ | |
angular.module('i18next', []).directive('ngI18next', function ($rootScope) { | |
'use strict'; | |
var | |
/** | |
* This will be our translation function (see code below) | |
*/ | |
t = null, | |
/** | |
* Default options for i18next | |
* @type {Object} | |
*/ | |
options = {}, | |
callbacks = [], | |
translated = []; | |
/** | |
* Translate the string given by the ng-i18next attribute and put it into the element. | |
* @param {DOMElement} element Element with the ng-i18next attribute | |
* @param {String} translateString The string we want to translate | |
* @param {Boolean} retranslate Whether it is the first time we translate the element or not | |
*/ | |
function setText (element, translateString, retranslate) { | |
if (!retranslate) { | |
translated[translated.length] = function () { | |
setText(element, translateString, true); | |
}; | |
} | |
if (t !== null) { | |
element.text(t(translateString)); | |
} else { | |
/* | |
* We have to wait for i18next to initialize, so we | |
* add the string (and element) we want to translate | |
* to the callback array. It will get executed when | |
* i18next is ready. | |
*/ | |
callbacks[callbacks.length] = function () { | |
setText(element, translateString); | |
}; | |
} | |
} | |
/** | |
* Initializes i18next | |
* @param {Boolean} reinitialization Have the options (in $rootScope) changed, so | |
* we have to translate every string again? | |
*/ | |
function init (reinitialization) { | |
window.i18n.init(options, function (tFunction) { | |
$rootScope.$broadcast('i18nextInit'); | |
$rootScope.i18nextLoaded = true; | |
var i; | |
t = tFunction; | |
if (!reinitialization) { | |
for (i = 0; i < callbacks.length; i++) { | |
callbacks[i](); | |
} | |
callbacks = []; | |
} else { | |
for (i = 0; i < translated.length; i++) { | |
translated[i](); | |
} | |
} | |
}); | |
} | |
$rootScope.$watch('i18nextOptions', function () { | |
options = $rootScope.i18nextOptions || options; | |
// Note: !! -> make i18nextOptions a boolean (true if it is defined) | |
init(!!$rootScope.i18nextOptions); | |
}); | |
return { | |
// 'A': only as attribute | |
restrict: 'A', | |
link: function postLink (scope, element, attrs) { | |
attrs.$observe('ngI18next', function (value) { | |
if (!value) { | |
// Well, seems that we don't have anything to translate... | |
return; | |
} | |
setText(element, value); | |
}); | |
} | |
}; | |
}); |
Want to show html in the inner element? Change line 58 to element.html(t(translateString));
if you wanna use count and context from i18next, put them into data attrs:
in the observer function, add:
attrs.$observe('ngI18next', function (value) {
var options = {};
if (!value) {
// Well, seems that we don't have anything to translate...
return;
}
if (attrs.count) {
options.count = parseInt(attrs.count, 10);
}
if (attrs.context) {
options.context = attrs.context;
}
setText(element, value, false, options);
});
extend the setText function like this:
function setText (element, translateString, retranslate, options) {
if (!retranslate) {
translated[translated.length] = function () {
setText(element, translateString, true, options);
};
}
if (t !== null) {
element.text(t(translateString, options));
} else {
/*
* We have to wait for i18next to initialize, so we
* add the string (and element) we want to translate
* to the callback array. It will get executed when
* i18next is ready.
*/
callbacks[callbacks.length] = function () {
setText(element, translateString, false, options);
};
}
}
use it like this:
<div ng-i18next="years" data-count="5"></div>
=> outputs "5 years"
<div ng-i18next="years" data-count="1"></div>
=> outputs "1 year"
with a translation like:
"year": "year",
"year_plural": "$t(year)s",
"years": "__count__ $t(year)",
just figured out sprintf support...
this also goes into the observer:
if (attrs.sprintf) {
options.postProcess = 'sprintf';
options.sprintf = JSON.parse(attrs.sprintf);
}
and use it like this:
<div ng-i18next="percent" data-sprintf='["{{ngScopeVar}}"]'></div>
in the translation json, the percent var defines a string output and an escaped percent sign:
"percent": "%s %%"
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
i18next relevant repositories/gist under one joint organisation
let's discuss this: i18next/i18next#99