diff --git a/modules/i18n/test/i18nSpec.js b/modules/i18n/test/i18nSpec.js new file mode 100644 index 00000000..dfd55679 --- /dev/null +++ b/modules/i18n/test/i18nSpec.js @@ -0,0 +1,39 @@ +/*describe('i18n', function() { + 'use strict'; + var uiI18n, element; + beforeEach(function(){ + uiI18n = angular.module('ui.i18n'); + uiI18n.add(['en', 'en-us'],{ + groupPanel:{ + testingMerge: 'some text', + otherText: 'some other group property text', + description:'Drag a column header here and drop it to group by that column.' + }, + example: 'I speak English', + anotherExample: 'I speak A Different Language' + }); + uiI18n.add('de',{ + groupPanel:{ + otherText: 'eine andere gruppe eigenschaft text', + description:'Ziehen Sie eine Spaltenuberschrift hierhin um nach dieser Spalte zu gruppieren.' + }, + example: 'Ich spreche Deutsch' + }); + uiI18n.add('de',{ + groupPanel:{ + testingMerge: 'falaffels are spelled horribly...', + }, + anotherExample: 'I speak A Different Language' + }); + uiI18n.set('en-us'); + }); + + it('should translate', function () { + inject(function ($rootScope, $compile) { + element = $compile('

')($rootScope); + console.log(element); + expect(element.html()).toBe('some other group property text'); + }); + }); +}); +*/ \ No newline at end of file diff --git a/modules/i18n/ui-i18n.js b/modules/i18n/ui-i18n.js new file mode 100644 index 00000000..294d950d --- /dev/null +++ b/modules/i18n/ui-i18n.js @@ -0,0 +1,290 @@ +/** + * ui-i18n Created by Tim Sweet on 2/1/14. + * https://github.com/timothyswt + * MIT License + */ + /** + * @ngdoc directive + * @name ui-i18n + * @requires $parse + * + * @description + * Allows you to localize your project by being able to specify a language on any root-ish element + * this can be a bindable property or the string. + * if bound it will automatically update all children when update. + * @example + + + + + + + + */ + +(function(deepExtend){ + 'use strict'; + var MISSING = '[MISSING]: ', + UPDATE_EVENT = '$uiI18n', + FILTER_ALIASES = ['t', 'translate'], + DIRECTIVE_ALIASES = ['uiT', 'uiTranslate'], + LOCALE_DIRECTIVE_ALIAS = 'uiI18n', + // default to english + DEFAULT_LANG = 'en-US', + langCache = { + _langs: {}, + current: null + }, + uiI18n = angular.module('ui.i18n', []); + + langCache.get = function(lang){ + return langCache._langs[lang.toLowerCase()]; + }; + langCache.add = function(lang, strings){ + var lower = lang.toLowerCase(); + var cache = langCache._langs; + cache[lower] = deepExtend(cache[lower] || {}, strings); + }; + langCache.setCurrent = function(lang){ + langCache.current = lang.toLowerCase(); + }; + langCache.getCurrent = function(){ + return langCache.get(langCache.current); + }; + + uiI18n._cache = langCache; + uiI18n.$broadcast = function(lang){ + if (lang && this.$root){ + uiI18n.$root.$broadcast(UPDATE_EVENT, lang); + } + }; + uiI18n.add = function(langs, strings){ + if (typeof(langs) === 'object'){ + angular.forEach(langs, function(lang){ + if (lang){ + langCache.add(lang, strings); + } + }); + } else { + langCache.add(langs, strings); + } + }; + uiI18n.set = function(lang){ + if (lang){ + langCache.setCurrent(lang); + uiI18n.$broadcast(lang); + } + }; + + var localeDirective = function() { + return { + compile: function(){ + return { + pre: function($scope, $elm, $attrs) { + var alias = LOCALE_DIRECTIVE_ALIAS; + if (!uiI18n.$root){ + uiI18n.$root = $scope.$root; + } + // check for watchable property + var lang = $scope.$eval($attrs[alias]); + if (lang){ + $scope.$watch($attrs[alias], uiI18n.set); + } else if ($attrs.$$observers){ + $scope.$on('$destroy', $attrs.$observe(alias, uiI18n.set)); + } else { + // fall back to the string value + lang = $attrs[alias]; + } + uiI18n.set(lang || DEFAULT_LANG); + } + }; + } + }; + }; + uiI18n.directive(LOCALE_DIRECTIVE_ALIAS, localeDirective); +/** + * * @ngdoc directive + * @name ui-t,ui-Translate + * @requires $parse + * + * @description + * specify the i18n string to use + * this can be a bindable property, expression/partial expression, or the object token. + * @example + + +
+
+ + +
+ +

+ +

groupPanel.testingMerge

+ +

example

+ +

+ +

invalid.path

+ +

invalid.translation.again

+ + +

Using element:

+ example +
+ groupPanel.description +
+ invalid.path +
+ invalid.translation.again + +

Using Translate Filters:

+ +

{{"groupPanel.description" | t}}

+ +

{{"example" | t}}

+

{{"invalid.path" | t}}

+ +

{{"invalid.translation.again" | translate}}

+
+
+ + var app = angular.module('app', ['ui.i18n']); + + app.controller('main', ['$scope', function($scope){ + $scope.language = "en"; + $scope.hello = "ui-i18n Example"; + $scope.desc = "description"; + $scope.changeLanguage = function(){ + $scope.language = $scope.language == "de" ? "en" : "de"; + }; + $scope.changeDesc = function(){ + $scope.desc = $scope.desc == "description" ? "otherText" : "description"; + }; + }]); + //Declare your i18n strings, this is enclosed in order to show that this can be done anywhere in the application + (function(){ + var uiI18n = angular.module('ui.i18n'); + uiI18n.add(["en", "en-us"],{ + groupPanel:{ + testingMerge: 'some text', + otherText: 'some other group property text', + description:'Drag a column header here and drop it to group by that column.' + }, + example: "I speak English", + anotherExample: "I speak A Different Language" + }); + })(); + + (function(){ + var uiI18n = angular.module('ui.i18n'); + uiI18n.add("de",{ + groupPanel:{ + otherText: 'eine andere gruppe eigenschaft text', + description:'Ziehen Sie eine Spaltenüberschrift hierhin um nach dieser Spalte zu gruppieren.' + }, + example: "Ich spreche Deutsch" + }); + })(); + + (function(){ + var uiI18n = angular.module('ui.i18n'); + uiI18n.add("de",{ + groupPanel:{ + testingMerge: 'falaffels are spelled horribly...', + }, + anotherExample: "I speak A Different Language" + }); + })(); + +
+ **/ + // directive syntax + var uitDirective = function($parse) { + return { + restrict: 'EA', + compile: function(){ + return { + pre: function($scope, $elm, $attrs) { + if (!uiI18n.$root){ + uiI18n.$root = $scope.$root; + } + var alias1 = DIRECTIVE_ALIASES[0], + alias2 = DIRECTIVE_ALIASES[1]; + var token = $attrs[alias1] || $attrs[alias2] || $elm.html(); + var missing = MISSING + token; + var observer; + if ($attrs.$$observers){ + var prop = $attrs[alias1] ? alias1 : alias2; + observer = $attrs.$observe(prop, function(result){ + if (result){ + $elm.html($parse(result)(langCache.getCurrent()) || missing); + } + }); + } + var getter = $parse(token); + var listener = $scope.$on(UPDATE_EVENT, function(evt, lang){ + if (observer){ + observer($attrs[alias1] || $attrs[alias2]); + } else { + // set text based on i18n current language + $elm.html(getter(langCache.get(lang)) || missing); + } + }); + $scope.$on('$destroy', listener); + } + }; + } + }; + }; + + // optional filter syntax + var uitFilter = function($parse) { + return function(data) { + var getter = $parse(data); + // set text based on i18n current language + return getter(langCache.getCurrent()) || MISSING + data; + }; + }; + + angular.forEach(DIRECTIVE_ALIASES, function(alias){ + uiI18n.directive(alias,['$parse', uitDirective]); + }); + angular.forEach(FILTER_ALIASES, function(alias){ + uiI18n.filter(alias,['$parse', uitFilter]); + }); + uiI18n.service('$i18nService', function(){ + var uii18nService = { + getCache: function(){ + return uiI18n._cache; + }, + $broadcast: function(){ + uiI18n.$broadcast(arguments); + }, + add: function(langs, strings){ + uiI18n.add(langs, strings); + }, + set: function(lang){ + uiI18n.set(lang); + } + }; + return uii18nService; + }); +})(function deepExtend(destination, source) { + 'use strict'; + // adding deep copy method until angularjs supports deep copy like everyone else. + // https://github.com/angular/angular.js/pull/5059 + for (var property in source) { + if (source[property] && source[property].constructor && + source[property].constructor === Object) { + destination[property] = destination[property] || {}; + deepExtend(destination[property], source[property]); + } else { + destination[property] = source[property]; + } + } + return destination; +}); \ No newline at end of file