diff --git a/dist/angular-gettext.js b/dist/angular-gettext.js index b192bc8..5421130 100644 --- a/dist/angular-gettext.js +++ b/dist/angular-gettext.js @@ -10,8 +10,7 @@ angular.module('gettext').constant('gettext', function (str) { return str; }); -angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", "$cacheFactory", "$interpolate", "$rootScope", function (gettextPlurals, $http, $cacheFactory, $interpolate, $rootScope) { - var catalog; +angular.module('gettext').provider('gettextCatalog', ["gettextPlurals", function (gettextPlurals) { var noContext = '$$noContext'; // IE8 returns UPPER CASE tags, even though the source is lower case. @@ -20,27 +19,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", var test = 'test'; var isUpperCaseTags = (angular.element('' + test + '').html() !== test); - var prefixDebug = function (string) { - if (catalog.debug && catalog.currentLanguage !== catalog.baseLanguage) { - return catalog.debugPrefix + string; - } else { - return string; - } - }; - - var addTranslatedMarkers = function (string) { - if (catalog.showTranslatedMarkers) { - return catalog.translatedMarkerPrefix + string + catalog.translatedMarkerSuffix; - } else { - return string; - } - }; - - function broadcastUpdated() { - $rootScope.$broadcast('gettextLanguageChanged'); - } - - catalog = { + var provider = { debug: false, debugPrefix: '[MISSING]: ', showTranslatedMarkers: false, @@ -49,11 +28,9 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", strings: {}, baseLanguage: 'en', currentLanguage: 'en', - cache: $cacheFactory('strings'), setCurrentLanguage: function (lang) { this.currentLanguage = lang; - broadcastUpdated(); }, setStrings: function (language, strings) { @@ -83,8 +60,6 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", } this.strings[language][key] = val; } - - broadcastUpdated(); }, getStringForm: function (string, n, context) { @@ -92,38 +67,90 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", var contexts = stringTable[string] || {}; var plurals = contexts[context || noContext] || []; return plurals[n]; - }, + } + }; - getString: function (string, scope, context) { - string = this.getStringForm(string, 0, context) || prefixDebug(string); - string = scope ? $interpolate(string)(scope) : string; - return addTranslatedMarkers(string); - }, + angular.extend(this, provider); + + var self = this; + this.$get = /* @ngInject */ ["$injector", function ($injector) { + // lazily inject these to prevent circular dependecies + var $http; + var $interpolate; + var $rootScope; + + function Catalog(options) { + angular.extend(this, options); + var self = this; + + var prefixDebug = function (string) { + if (self.debug && self.currentLanguage !== self.baseLanguage) { + return self.debugPrefix + string; + } else { + return string; + } + }; - getPlural: function (n, string, stringPlural, scope, context) { - var form = gettextPlurals(this.currentLanguage, n); - string = this.getStringForm(string, form, context) || prefixDebug(n === 1 ? string : stringPlural); - if (scope) { - scope.$count = n; - string = $interpolate(string)(scope); + var addTranslatedMarkers = function (string) { + if (self.showTranslatedMarkers) { + return self.translatedMarkerPrefix + string + self.translatedMarkerSuffix; + } else { + return string; + } + }; + + function broadcastUpdated() { + $rootScope = $rootScope || $injector.get('$rootScope'); + $rootScope.$broadcast('gettextLanguageChanged'); } - return addTranslatedMarkers(string); - }, - loadRemote: function (url) { - return $http({ - method: 'GET', - url: url, - cache: catalog.cache - }).success(function (data) { - for (var lang in data) { - catalog.setStrings(lang, data[lang]); + this.setCurrentLanguage = function () { + options.setCurrentLanguage.apply(this, arguments); + broadcastUpdated(); + }; + + this.setStrings = function () { + options.setStrings.apply(this, arguments); + broadcastUpdated(); + }; + + this.getString = function (string, scope, context) { + $interpolate = $interpolate || $injector.get('$interpolate'); + + string = this.getStringForm(string, 0, context) || prefixDebug(string); + string = scope ? $interpolate(string)(scope) : string; + return addTranslatedMarkers(string); + }; + + this.getPlural = function (n, string, stringPlural, scope, context) { + $interpolate = $interpolate || $injector.get('$interpolate'); + + var form = gettextPlurals(this.currentLanguage, n); + string = this.getStringForm(string, form, context) || prefixDebug(n === 1 ? string : stringPlural); + if (scope) { + scope.$count = n; + string = $interpolate(string)(scope); } - }); + return addTranslatedMarkers(string); + }; + + this.loadRemote = function (url) { + $http = $http || $injector.get('$http'); + return $http({ + method: 'GET', + url: url, + cache: self.cache + }).success(function (data) { + for (var lang in data) { + self.setStrings(lang, data[lang]); + } + }); + }; } - }; - return catalog; + self.cache = self.cache || $injector.get('$cacheFactory')('strings'); + return new Catalog(self); + }]; }]); angular.module('gettext').directive('translate', ["gettextCatalog", "$parse", "$animate", "$compile", "$window", function (gettextCatalog, $parse, $animate, $compile, $window) { @@ -215,116 +242,117 @@ angular.module('gettext').filter('translate', ["gettextCatalog", function (gette }]); // Do not edit this file, it is autogenerated using genplurals.py! -angular.module("gettext").factory("gettextPlurals", function () { - return function (langCode, n) { - switch (langCode) { - case "ay": // Aymará - case "bo": // Tibetan - case "cgg": // Chiga - case "dz": // Dzongkha - case "fa": // Persian - case "id": // Indonesian - case "ja": // Japanese - case "jbo": // Lojban - case "ka": // Georgian - case "kk": // Kazakh - case "km": // Khmer - case "ko": // Korean - case "ky": // Kyrgyz - case "lo": // Lao - case "ms": // Malay - case "my": // Burmese - case "sah": // Yakut - case "su": // Sundanese - case "th": // Thai - case "tt": // Tatar - case "ug": // Uyghur - case "vi": // Vietnamese - case "wo": // Wolof - case "zh": // Chinese - // 1 form - return 0; - case "is": // Icelandic - // 2 forms - return (n%10!=1 || n%100==11) ? 1 : 0; - case "jv": // Javanese - // 2 forms - return n!=0 ? 1 : 0; - case "mk": // Macedonian - // 2 forms - return n==1 || n%10==1 ? 0 : 1; - case "ach": // Acholi - case "ak": // Akan - case "am": // Amharic - case "arn": // Mapudungun - case "br": // Breton - case "fil": // Filipino - case "fr": // French - case "gun": // Gun - case "ln": // Lingala - case "mfe": // Mauritian Creole - case "mg": // Malagasy - case "mi": // Maori - case "oc": // Occitan - case "pt_BR": // Brazilian Portuguese - case "tg": // Tajik - case "ti": // Tigrinya - case "tr": // Turkish - case "uz": // Uzbek - case "wa": // Walloon - case "zh": // Chinese - // 2 forms - return n>1 ? 1 : 0; - case "lv": // Latvian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); - case "lt": // Lithuanian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); - case "be": // Belarusian - case "bs": // Bosnian - case "hr": // Croatian - case "ru": // Russian - case "sr": // Serbian - case "uk": // Ukrainian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); - case "mnk": // Mandinka - // 3 forms - return (n==0 ? 0 : n==1 ? 1 : 2); - case "ro": // Romanian - // 3 forms - return (n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); - case "pl": // Polish - // 3 forms - return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); - case "cs": // Czech - case "sk": // Slovak - // 3 forms - return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; - case "sl": // Slovenian - // 4 forms - return (n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); - case "mt": // Maltese - // 4 forms - return (n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); - case "gd": // Scottish Gaelic - // 4 forms - return (n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3; - case "cy": // Welsh - // 4 forms - return (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3; - case "kw": // Cornish - // 4 forms - return (n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3; - case "ga": // Irish - // 5 forms - return n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4; - case "ar": // Arabic - // 6 forms - return (n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); - default: // Everything else - return n != 1 ? 1 : 0; - } +angular.module("gettext").constant("gettextPlurals", function (langCode, n) { + switch (langCode) { + case "ay": // Aymará + case "bo": // Tibetan + case "cgg": // Chiga + case "dz": // Dzongkha + case "fa": // Persian + case "id": // Indonesian + case "ja": // Japanese + case "jbo": // Lojban + case "ka": // Georgian + case "kk": // Kazakh + case "km": // Khmer + case "ko": // Korean + case "ky": // Kyrgyz + case "lo": // Lao + case "ms": // Malay + case "my": // Burmese + case "sah": // Yakut + case "su": // Sundanese + case "th": // Thai + case "tt": // Tatar + case "ug": // Uyghur + case "vi": // Vietnamese + case "wo": // Wolof + case "zh": // Chinese + // 1 form + return 0; + case "is": // Icelandic + // 2 forms + return (n%10!=1 || n%100==11) ? 1 : 0; + case "jv": // Javanese + // 2 forms + return n!=0 ? 1 : 0; + case "mk": // Macedonian + // 2 forms + return n==1 || n%10==1 ? 0 : 1; + case "ach": // Acholi + case "ak": // Akan + case "am": // Amharic + case "arn": // Mapudungun + case "br": // Breton + case "fil": // Filipino + case "fr": // French + case "gun": // Gun + case "ln": // Lingala + case "mfe": // Mauritian Creole + case "mg": // Malagasy + case "mi": // Maori + case "oc": // Occitan + case "pt_BR": // Brazilian Portuguese + case "tg": // Tajik + case "ti": // Tigrinya + case "tr": // Turkish + case "uz": // Uzbek + case "wa": // Walloon + case "zh": // Chinese + // 2 forms + return n>1 ? 1 : 0; + case "lv": // Latvian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); + case "lt": // Lithuanian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); + case "be": // Belarusian + case "bs": // Bosnian + case "hr": // Croatian + case "ru": // Russian + case "sr": // Serbian + case "uk": // Ukrainian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); + case "mnk": // Mandinka + // 3 forms + return (n==0 ? 0 : n==1 ? 1 : 2); + case "ro": // Romanian + // 3 forms + return (n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); + case "pl": // Polish + // 3 forms + return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); + case "cs": // Czech + case "sk": // Slovak + // 3 forms + return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; + case "csb": // Kashubian + // 3 forms + return (n==1) ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + case "sl": // Slovenian + // 4 forms + return (n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); + case "mt": // Maltese + // 4 forms + return (n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); + case "gd": // Scottish Gaelic + // 4 forms + return (n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3; + case "cy": // Welsh + // 4 forms + return (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3; + case "kw": // Cornish + // 4 forms + return (n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3; + case "ga": // Irish + // 5 forms + return (n==1) ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4; + case "ar": // Arabic + // 6 forms + return (n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); + default: // Everything else + return n != 1 ? 1 : 0; } }); diff --git a/dist/angular-gettext.min.js b/dist/angular-gettext.min.js index a7cb823..aac6b57 100644 --- a/dist/angular-gettext.min.js +++ b/dist/angular-gettext.min.js @@ -1 +1 @@ -angular.module("gettext",[]),angular.module("gettext").constant("gettext",function(a){return a}),angular.module("gettext").factory("gettextCatalog",["gettextPlurals","$http","$cacheFactory","$interpolate","$rootScope",function(a,b,c,d,e){function f(){e.$broadcast("gettextLanguageChanged")}var g,h="$$noContext",i="test",j=angular.element(""+i+"").html()!==i,k=function(a){return g.debug&&g.currentLanguage!==g.baseLanguage?g.debugPrefix+a:a},l=function(a){return g.showTranslatedMarkers?g.translatedMarkerPrefix+a+g.translatedMarkerSuffix:a};return g={debug:!1,debugPrefix:"[MISSING]: ",showTranslatedMarkers:!1,translatedMarkerPrefix:"[",translatedMarkerSuffix:"]",strings:{},baseLanguage:"en",currentLanguage:"en",cache:c("strings"),setCurrentLanguage:function(a){this.currentLanguage=a,f()},setStrings:function(a,b){this.strings[a]||(this.strings[a]={});for(var c in b){var d=b[c];if(j&&(c=angular.element(""+c+"").html()),angular.isString(d)||angular.isArray(d)){var e={};e[h]=d,d=e}for(var g in d){var i=d[g];d[g]=angular.isArray(i)?i:[i]}this.strings[a][c]=d}f()},getStringForm:function(a,b,c){var d=this.strings[this.currentLanguage]||{},e=d[a]||{},f=e[c||h]||[];return f[b]},getString:function(a,b,c){return a=this.getStringForm(a,0,c)||k(a),a=b?d(a)(b):a,l(a)},getPlural:function(b,c,e,f,g){var h=a(this.currentLanguage,b);return c=this.getStringForm(c,h,g)||k(1===b?c:e),f&&(f.$count=b,c=d(c)(f)),l(c)},loadRemote:function(a){return b({method:"GET",url:a,cache:g.cache}).success(function(a){for(var b in a)g.setStrings(b,a[b])})}}}]),angular.module("gettext").directive("translate",["gettextCatalog","$parse","$animate","$compile","$window",function(a,b,c,d,e){function f(a,b,c){if(!a)throw new Error("You should add a "+b+" attribute whenever you add a "+c+" attribute.")}var g=function(){return String.prototype.trim?function(a){return"string"==typeof a?a.trim():a}:function(a){return"string"==typeof a?a.replace(/^\s*/,"").replace(/\s*$/,""):a}}(),h=parseInt((/msie (\d+)/.exec(angular.lowercase(e.navigator.userAgent))||[])[1],10);return{restrict:"AE",terminal:!0,compile:function(e,i){f(!i.translatePlural||i.translateN,"translate-n","translate-plural"),f(!i.translateN||i.translatePlural,"translate-plural","translate-n");var j=g(e.html()),k=i.translatePlural,l=i.translateContext;return 8>=h&&""===j.slice(-13)&&(j=j.slice(0,-13)),{post:function(e,f,g){function h(){var b;k?(e=m||(m=e.$new()),e.$count=i(e),b=a.getPlural(e.$count,j,k,null,l)):b=a.getString(j,null,l);var g=angular.element(""+b+"");d(g.contents())(e);var h=f.contents(),n=g.contents();c.enter(n,f),c.leave(h)}var i=b(g.translateN),m=null;g.translateN&&e.$watch(g.translateN,h),e.$on("gettextLanguageChanged",h),h()}}}}}]),angular.module("gettext").filter("translate",["gettextCatalog",function(a){function b(b,c){return a.getString(b,null,c)}return b.$stateful=!0,b}]),angular.module("gettext").factory("gettextPlurals",function(){return function(a,b){switch(a){case"ay":case"bo":case"cgg":case"dz":case"fa":case"id":case"ja":case"jbo":case"ka":case"kk":case"km":case"ko":case"ky":case"lo":case"ms":case"my":case"sah":case"su":case"th":case"tt":case"ug":case"vi":case"wo":case"zh":return 0;case"is":return b%10!=1||b%100==11?1:0;case"jv":return 0!=b?1:0;case"mk":return 1==b||b%10==1?0:1;case"ach":case"ak":case"am":case"arn":case"br":case"fil":case"fr":case"gun":case"ln":case"mfe":case"mg":case"mi":case"oc":case"pt_BR":case"tg":case"ti":case"tr":case"uz":case"wa":case"zh":return b>1?1:0;case"lv":return b%10==1&&b%100!=11?0:0!=b?1:2;case"lt":return b%10==1&&b%100!=11?0:b%10>=2&&(10>b%100||b%100>=20)?1:2;case"be":case"bs":case"hr":case"ru":case"sr":case"uk":return b%10==1&&b%100!=11?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"mnk":return 0==b?0:1==b?1:2;case"ro":return 1==b?0:0==b||b%100>0&&20>b%100?1:2;case"pl":return 1==b?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"cs":case"sk":return 1==b?0:b>=2&&4>=b?1:2;case"sl":return b%100==1?1:b%100==2?2:b%100==3||b%100==4?3:0;case"mt":return 1==b?0:0==b||b%100>1&&11>b%100?1:b%100>10&&20>b%100?2:3;case"gd":return 1==b||11==b?0:2==b||12==b?1:b>2&&20>b?2:3;case"cy":return 1==b?0:2==b?1:8!=b&&11!=b?2:3;case"kw":return 1==b?0:2==b?1:3==b?2:3;case"ga":return 1==b?0:2==b?1:7>b?2:11>b?3:4;case"ar":return 0==b?0:1==b?1:2==b?2:b%100>=3&&10>=b%100?3:b%100>=11?4:5;default:return 1!=b?1:0}}}); \ No newline at end of file +angular.module("gettext",[]),angular.module("gettext").constant("gettext",function(a){return a}),angular.module("gettext").provider("gettextCatalog",["gettextPlurals",function(a){var b="$$noContext",c="test",d=angular.element(""+c+"").html()!==c,e={debug:!1,debugPrefix:"[MISSING]: ",showTranslatedMarkers:!1,translatedMarkerPrefix:"[",translatedMarkerSuffix:"]",strings:{},baseLanguage:"en",currentLanguage:"en",setCurrentLanguage:function(a){this.currentLanguage=a},setStrings:function(a,c){this.strings[a]||(this.strings[a]={});for(var e in c){var f=c[e];if(d&&(e=angular.element(""+e+"").html()),angular.isString(f)||angular.isArray(f)){var g={};g[b]=f,f=g}for(var h in f){var i=f[h];f[h]=angular.isArray(i)?i:[i]}this.strings[a][e]=f}},getStringForm:function(a,c,d){var e=this.strings[this.currentLanguage]||{},f=e[a]||{},g=f[d||b]||[];return g[c]}};angular.extend(this,e);var f=this;this.$get=["$injector",function(b){function c(c){function f(){g=g||b.get("$rootScope"),g.$broadcast("gettextLanguageChanged")}angular.extend(this,c);var h=this,i=function(a){return h.debug&&h.currentLanguage!==h.baseLanguage?h.debugPrefix+a:a},j=function(a){return h.showTranslatedMarkers?h.translatedMarkerPrefix+a+h.translatedMarkerSuffix:a};this.setCurrentLanguage=function(){c.setCurrentLanguage.apply(this,arguments),f()},this.setStrings=function(){c.setStrings.apply(this,arguments),f()},this.getString=function(a,c,d){return e=e||b.get("$interpolate"),a=this.getStringForm(a,0,d)||i(a),a=c?e(a)(c):a,j(a)},this.getPlural=function(c,d,f,g,h){e=e||b.get("$interpolate");var k=a(this.currentLanguage,c);return d=this.getStringForm(d,k,h)||i(1===c?d:f),g&&(g.$count=c,d=e(d)(g)),j(d)},this.loadRemote=function(a){return d=d||b.get("$http"),d({method:"GET",url:a,cache:h.cache}).success(function(a){for(var b in a)h.setStrings(b,a[b])})}}var d,e,g;return f.cache=f.cache||b.get("$cacheFactory")("strings"),new c(f)}]}]),angular.module("gettext").directive("translate",["gettextCatalog","$parse","$animate","$compile","$window",function(a,b,c,d,e){function f(a,b,c){if(!a)throw new Error("You should add a "+b+" attribute whenever you add a "+c+" attribute.")}var g=function(){return String.prototype.trim?function(a){return"string"==typeof a?a.trim():a}:function(a){return"string"==typeof a?a.replace(/^\s*/,"").replace(/\s*$/,""):a}}(),h=parseInt((/msie (\d+)/.exec(angular.lowercase(e.navigator.userAgent))||[])[1],10);return{restrict:"AE",terminal:!0,compile:function(e,i){f(!i.translatePlural||i.translateN,"translate-n","translate-plural"),f(!i.translateN||i.translatePlural,"translate-plural","translate-n");var j=g(e.html()),k=i.translatePlural,l=i.translateContext;return 8>=h&&""===j.slice(-13)&&(j=j.slice(0,-13)),{post:function(e,f,g){function h(){var b;k?(e=m||(m=e.$new()),e.$count=i(e),b=a.getPlural(e.$count,j,k,null,l)):b=a.getString(j,null,l);var g=angular.element(""+b+"");d(g.contents())(e);var h=f.contents(),n=g.contents();c.enter(n,f),c.leave(h)}var i=b(g.translateN),m=null;g.translateN&&e.$watch(g.translateN,h),e.$on("gettextLanguageChanged",h),h()}}}}}]),angular.module("gettext").filter("translate",["gettextCatalog",function(a){function b(b,c){return a.getString(b,null,c)}return b.$stateful=!0,b}]),angular.module("gettext").constant("gettextPlurals",function(a,b){switch(a){case"ay":case"bo":case"cgg":case"dz":case"fa":case"id":case"ja":case"jbo":case"ka":case"kk":case"km":case"ko":case"ky":case"lo":case"ms":case"my":case"sah":case"su":case"th":case"tt":case"ug":case"vi":case"wo":case"zh":return 0;case"is":return b%10!=1||b%100==11?1:0;case"jv":return 0!=b?1:0;case"mk":return 1==b||b%10==1?0:1;case"ach":case"ak":case"am":case"arn":case"br":case"fil":case"fr":case"gun":case"ln":case"mfe":case"mg":case"mi":case"oc":case"pt_BR":case"tg":case"ti":case"tr":case"uz":case"wa":case"zh":return b>1?1:0;case"lv":return b%10==1&&b%100!=11?0:0!=b?1:2;case"lt":return b%10==1&&b%100!=11?0:b%10>=2&&(10>b%100||b%100>=20)?1:2;case"be":case"bs":case"hr":case"ru":case"sr":case"uk":return b%10==1&&b%100!=11?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"mnk":return 0==b?0:1==b?1:2;case"ro":return 1==b?0:0==b||b%100>0&&20>b%100?1:2;case"pl":return 1==b?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"cs":case"sk":return 1==b?0:b>=2&&4>=b?1:2;case"csb":return 1==b?0:b%10>=2&&4>=b%10&&(10>b%100||b%100>=20)?1:2;case"sl":return b%100==1?1:b%100==2?2:b%100==3||b%100==4?3:0;case"mt":return 1==b?0:0==b||b%100>1&&11>b%100?1:b%100>10&&20>b%100?2:3;case"gd":return 1==b||11==b?0:2==b||12==b?1:b>2&&20>b?2:3;case"cy":return 1==b?0:2==b?1:8!=b&&11!=b?2:3;case"kw":return 1==b?0:2==b?1:3==b?2:3;case"ga":return 1==b?0:2==b?1:7>b?2:11>b?3:4;case"ar":return 0==b?0:1==b?1:2==b?2:b%100>=3&&10>=b%100?3:b%100>=11?4:5;default:return 1!=b?1:0}}); \ No newline at end of file diff --git a/genplurals.py b/genplurals.py index c28e54e..1890a18 100755 --- a/genplurals.py +++ b/genplurals.py @@ -110,9 +110,8 @@ def handle_entityref(self, name): rules.sort(key = lambda rule: (str(rule[1][0][2]) + rule[0])) print('// Do not edit this file, it is autogenerated using genplurals.py!'); -print('angular.module("gettext").factory("gettextPlurals", function () {'); -print(' return function (langCode, n) {') -print(' switch (langCode) {') +print('angular.module("gettext").constant("gettextPlurals", function (langCode, n) {'); +print(' switch (langCode) {') for rule, langs in rules: last_forms = 0 langs.sort(key = lambda lang: lang[0]) @@ -121,14 +120,13 @@ def handle_entityref(self, name): space = ' ' if len(code) == 3: space = ' ' - print(' case "%s":%s// %s' % (code, space, name)) + print(' case "%s":%s// %s' % (code, space, name)) if last_forms == 1: - print(' // %d form' % last_forms) + print(' // %d form' % last_forms) else: - print(' // %d forms' % last_forms) - print(' return %s;' % rule) -print(' default: // Everything else') -print(' return n != 1 ? 1 : 0;') -print(' }') + print(' // %d forms' % last_forms) + print(' return %s;' % rule) +print(' default: // Everything else') +print(' return n != 1 ? 1 : 0;') print(' }') print('});') diff --git a/src/catalog.js b/src/catalog.js index 3782b36..36ea3a6 100644 --- a/src/catalog.js +++ b/src/catalog.js @@ -1,5 +1,4 @@ -angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $http, $cacheFactory, $interpolate, $rootScope) { - var catalog; +angular.module('gettext').provider('gettextCatalog', function (gettextPlurals) { var noContext = '$$noContext'; // IE8 returns UPPER CASE tags, even though the source is lower case. @@ -8,27 +7,7 @@ angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $h var test = 'test'; var isUpperCaseTags = (angular.element('' + test + '').html() !== test); - var prefixDebug = function (string) { - if (catalog.debug && catalog.currentLanguage !== catalog.baseLanguage) { - return catalog.debugPrefix + string; - } else { - return string; - } - }; - - var addTranslatedMarkers = function (string) { - if (catalog.showTranslatedMarkers) { - return catalog.translatedMarkerPrefix + string + catalog.translatedMarkerSuffix; - } else { - return string; - } - }; - - function broadcastUpdated() { - $rootScope.$broadcast('gettextLanguageChanged'); - } - - catalog = { + var provider = { debug: false, debugPrefix: '[MISSING]: ', showTranslatedMarkers: false, @@ -37,11 +16,9 @@ angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $h strings: {}, baseLanguage: 'en', currentLanguage: 'en', - cache: $cacheFactory('strings'), setCurrentLanguage: function (lang) { this.currentLanguage = lang; - broadcastUpdated(); }, setStrings: function (language, strings) { @@ -71,8 +48,6 @@ angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $h } this.strings[language][key] = val; } - - broadcastUpdated(); }, getStringForm: function (string, n, context) { @@ -80,36 +55,88 @@ angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $h var contexts = stringTable[string] || {}; var plurals = contexts[context || noContext] || []; return plurals[n]; - }, + } + }; - getString: function (string, scope, context) { - string = this.getStringForm(string, 0, context) || prefixDebug(string); - string = scope ? $interpolate(string)(scope) : string; - return addTranslatedMarkers(string); - }, + angular.extend(this, provider); + + var self = this; + this.$get = /* @ngInject */ function ($injector) { + // lazily inject these to prevent circular dependecies + var $http; + var $interpolate; + var $rootScope; - getPlural: function (n, string, stringPlural, scope, context) { - var form = gettextPlurals(this.currentLanguage, n); - string = this.getStringForm(string, form, context) || prefixDebug(n === 1 ? string : stringPlural); - if (scope) { - scope.$count = n; - string = $interpolate(string)(scope); + function Catalog(options) { + angular.extend(this, options); + var self = this; + + var prefixDebug = function (string) { + if (self.debug && self.currentLanguage !== self.baseLanguage) { + return self.debugPrefix + string; + } else { + return string; + } + }; + + var addTranslatedMarkers = function (string) { + if (self.showTranslatedMarkers) { + return self.translatedMarkerPrefix + string + self.translatedMarkerSuffix; + } else { + return string; + } + }; + + function broadcastUpdated() { + $rootScope = $rootScope || $injector.get('$rootScope'); + $rootScope.$broadcast('gettextLanguageChanged'); } - return addTranslatedMarkers(string); - }, - loadRemote: function (url) { - return $http({ - method: 'GET', - url: url, - cache: catalog.cache - }).success(function (data) { - for (var lang in data) { - catalog.setStrings(lang, data[lang]); + this.setCurrentLanguage = function () { + options.setCurrentLanguage.apply(this, arguments); + broadcastUpdated(); + }; + + this.setStrings = function () { + options.setStrings.apply(this, arguments); + broadcastUpdated(); + }; + + this.getString = function (string, scope, context) { + $interpolate = $interpolate || $injector.get('$interpolate'); + + string = this.getStringForm(string, 0, context) || prefixDebug(string); + string = scope ? $interpolate(string)(scope) : string; + return addTranslatedMarkers(string); + }; + + this.getPlural = function (n, string, stringPlural, scope, context) { + $interpolate = $interpolate || $injector.get('$interpolate'); + + var form = gettextPlurals(this.currentLanguage, n); + string = this.getStringForm(string, form, context) || prefixDebug(n === 1 ? string : stringPlural); + if (scope) { + scope.$count = n; + string = $interpolate(string)(scope); } - }); + return addTranslatedMarkers(string); + }; + + this.loadRemote = function (url) { + $http = $http || $injector.get('$http'); + return $http({ + method: 'GET', + url: url, + cache: self.cache + }).success(function (data) { + for (var lang in data) { + self.setStrings(lang, data[lang]); + } + }); + }; } - }; - return catalog; + self.cache = self.cache || $injector.get('$cacheFactory')('strings'); + return new Catalog(self); + }; }); diff --git a/src/plural.js b/src/plural.js index fc53d87..371e07f 100644 --- a/src/plural.js +++ b/src/plural.js @@ -1,114 +1,115 @@ // Do not edit this file, it is autogenerated using genplurals.py! -angular.module("gettext").factory("gettextPlurals", function () { - return function (langCode, n) { - switch (langCode) { - case "ay": // Aymará - case "bo": // Tibetan - case "cgg": // Chiga - case "dz": // Dzongkha - case "fa": // Persian - case "id": // Indonesian - case "ja": // Japanese - case "jbo": // Lojban - case "ka": // Georgian - case "kk": // Kazakh - case "km": // Khmer - case "ko": // Korean - case "ky": // Kyrgyz - case "lo": // Lao - case "ms": // Malay - case "my": // Burmese - case "sah": // Yakut - case "su": // Sundanese - case "th": // Thai - case "tt": // Tatar - case "ug": // Uyghur - case "vi": // Vietnamese - case "wo": // Wolof - case "zh": // Chinese - // 1 form - return 0; - case "is": // Icelandic - // 2 forms - return (n%10!=1 || n%100==11) ? 1 : 0; - case "jv": // Javanese - // 2 forms - return n!=0 ? 1 : 0; - case "mk": // Macedonian - // 2 forms - return n==1 || n%10==1 ? 0 : 1; - case "ach": // Acholi - case "ak": // Akan - case "am": // Amharic - case "arn": // Mapudungun - case "br": // Breton - case "fil": // Filipino - case "fr": // French - case "gun": // Gun - case "ln": // Lingala - case "mfe": // Mauritian Creole - case "mg": // Malagasy - case "mi": // Maori - case "oc": // Occitan - case "pt_BR": // Brazilian Portuguese - case "tg": // Tajik - case "ti": // Tigrinya - case "tr": // Turkish - case "uz": // Uzbek - case "wa": // Walloon - case "zh": // Chinese - // 2 forms - return n>1 ? 1 : 0; - case "lv": // Latvian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); - case "lt": // Lithuanian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); - case "be": // Belarusian - case "bs": // Bosnian - case "hr": // Croatian - case "ru": // Russian - case "sr": // Serbian - case "uk": // Ukrainian - // 3 forms - return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); - case "mnk": // Mandinka - // 3 forms - return (n==0 ? 0 : n==1 ? 1 : 2); - case "ro": // Romanian - // 3 forms - return (n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); - case "pl": // Polish - // 3 forms - return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); - case "cs": // Czech - case "sk": // Slovak - // 3 forms - return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; - case "sl": // Slovenian - // 4 forms - return (n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); - case "mt": // Maltese - // 4 forms - return (n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); - case "gd": // Scottish Gaelic - // 4 forms - return (n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3; - case "cy": // Welsh - // 4 forms - return (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3; - case "kw": // Cornish - // 4 forms - return (n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3; - case "ga": // Irish - // 5 forms - return n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4; - case "ar": // Arabic - // 6 forms - return (n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); - default: // Everything else - return n != 1 ? 1 : 0; - } +angular.module("gettext").constant("gettextPlurals", function (langCode, n) { + switch (langCode) { + case "ay": // Aymará + case "bo": // Tibetan + case "cgg": // Chiga + case "dz": // Dzongkha + case "fa": // Persian + case "id": // Indonesian + case "ja": // Japanese + case "jbo": // Lojban + case "ka": // Georgian + case "kk": // Kazakh + case "km": // Khmer + case "ko": // Korean + case "ky": // Kyrgyz + case "lo": // Lao + case "ms": // Malay + case "my": // Burmese + case "sah": // Yakut + case "su": // Sundanese + case "th": // Thai + case "tt": // Tatar + case "ug": // Uyghur + case "vi": // Vietnamese + case "wo": // Wolof + case "zh": // Chinese + // 1 form + return 0; + case "is": // Icelandic + // 2 forms + return (n%10!=1 || n%100==11) ? 1 : 0; + case "jv": // Javanese + // 2 forms + return n!=0 ? 1 : 0; + case "mk": // Macedonian + // 2 forms + return n==1 || n%10==1 ? 0 : 1; + case "ach": // Acholi + case "ak": // Akan + case "am": // Amharic + case "arn": // Mapudungun + case "br": // Breton + case "fil": // Filipino + case "fr": // French + case "gun": // Gun + case "ln": // Lingala + case "mfe": // Mauritian Creole + case "mg": // Malagasy + case "mi": // Maori + case "oc": // Occitan + case "pt_BR": // Brazilian Portuguese + case "tg": // Tajik + case "ti": // Tigrinya + case "tr": // Turkish + case "uz": // Uzbek + case "wa": // Walloon + case "zh": // Chinese + // 2 forms + return n>1 ? 1 : 0; + case "lv": // Latvian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2); + case "lt": // Lithuanian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2); + case "be": // Belarusian + case "bs": // Bosnian + case "hr": // Croatian + case "ru": // Russian + case "sr": // Serbian + case "uk": // Ukrainian + // 3 forms + return (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); + case "mnk": // Mandinka + // 3 forms + return (n==0 ? 0 : n==1 ? 1 : 2); + case "ro": // Romanian + // 3 forms + return (n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2); + case "pl": // Polish + // 3 forms + return (n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2); + case "cs": // Czech + case "sk": // Slovak + // 3 forms + return (n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; + case "csb": // Kashubian + // 3 forms + return (n==1) ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; + case "sl": // Slovenian + // 4 forms + return (n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); + case "mt": // Maltese + // 4 forms + return (n==1 ? 0 : n==0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3); + case "gd": // Scottish Gaelic + // 4 forms + return (n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3; + case "cy": // Welsh + // 4 forms + return (n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3; + case "kw": // Cornish + // 4 forms + return (n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3; + case "ga": // Irish + // 5 forms + return (n==1) ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4; + case "ar": // Arabic + // 6 forms + return (n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5); + default: // Everything else + return n != 1 ? 1 : 0; } }); diff --git a/test/unit/circular.js b/test/unit/circular.js new file mode 100644 index 0000000..c6ffb8d --- /dev/null +++ b/test/unit/circular.js @@ -0,0 +1,20 @@ +describe("Catalog", function () { + // don't pull module out of tests! + + it("Shouldn't cause circular dependency error on $http", function () { + var testModule = angular.module("gettext.test", function () {}); + testModule.factory("testInterceptor", function (gettextCatalog) { + gettextCatalog.getString("some message"); + return {}; + }); + + testModule.config(function ($httpProvider) { + $httpProvider.interceptors.push("testInterceptor"); + }); + + module("gettext", "gettext.test"); + inject(function ($http) { + assert.notEqual($http, false); + }); + }); +}); diff --git a/test/unit/gettextCatalogProvider.js b/test/unit/gettextCatalogProvider.js new file mode 100644 index 0000000..01e71b6 --- /dev/null +++ b/test/unit/gettextCatalogProvider.js @@ -0,0 +1,45 @@ +describe('gettextCatalogProvider', function () { + var catalogProvider; + var $injector; + + beforeEach(function () { + var testModule = angular.module('gettext.test', function () {}); + testModule.config(function (gettextCatalogProvider) { + catalogProvider = gettextCatalogProvider; + }); + + module('gettext', 'gettext.test'); + inject(function (_$injector_) { + $injector = _$injector_; + }); + }); + + it('Can set strings', function () { + var strings = { Hello: 'Hallo' }; + assert.deepEqual(catalogProvider.strings, {}); + catalogProvider.setStrings('nl', strings); + assert.equal(catalogProvider.strings.nl.Hello.$$noContext[0], 'Hallo'); + + var catalog = $injector.invoke(catalogProvider.$get); + assert.equal(catalog.strings.nl.Hello.$$noContext[0], 'Hallo'); + }); + + it('Should allow setting debug', function () { + assert.equal(catalogProvider.debug, false); + catalogProvider.debug = true; + catalogProvider.currentLanguage = 'fr'; + + var catalog = $injector.invoke(catalogProvider.$get); + assert.equal(catalog.getString('Hello'), '[MISSING]: Hello'); + }); + + it('Should allow calling setCurrentLanguage', function () { + assert.equal(catalogProvider.currentLanguage, 'en'); + catalogProvider.setCurrentLanguage('fr'); + assert.equal(catalogProvider.currentLanguage, 'fr'); + + var catalog = $injector.invoke(catalogProvider.$get); + assert.equal(catalog.currentLanguage, 'fr'); + }); + +});