diff --git a/.gitignore b/.gitignore index 0b639ce..5941534 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ /libpeerconnection.log /unit-results.xml /e2e-results.xml -/.idea \ No newline at end of file +/.idea +.project \ No newline at end of file diff --git a/.jshintrc b/.jshintrc index d6f946d..be35583 100644 --- a/.jshintrc +++ b/.jshintrc @@ -24,9 +24,13 @@ "beforeEach", "browser", "describe", + "ddescribe", "element", "expect", "inject", - "it" + "it", + "iit", + "xdescribe", + "xit" ] } diff --git a/dist/angular-gettext.js b/dist/angular-gettext.js index 4790821..8337235 100644 --- a/dist/angular-gettext.js +++ b/dist/angular-gettext.js @@ -81,6 +81,10 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "$http", getPlural: function (n, string, stringPlural, context) { var form = gettextPlurals(this.currentLanguage, n); string = this.getStringForm(string, form) || prefixDebug(n === 1 ? string : stringPlural); + + // Replace {} pattern with number + string = string.replace(/\{\}/g, n); + string = context ? $interpolate(string)(context) : string; return addTranslatedMarkers(string); }, @@ -178,6 +182,14 @@ angular.module('gettext').filter('translate', ["gettextCatalog", function (gette return filter; }]); +angular.module('gettext').filter('translatePlural', ['gettextCatalog', function (gettextCatalog) { + function filter(string, n, stringPlural) { + return gettextCatalog.getPlural(n, string, stringPlural); + } + filter.$stateful = true; + return filter; +}]); + // Do not edit this file, it is autogenerated using genplurals.py! angular.module("gettext").factory("gettextPlurals", function () { return function (langCode, n) { diff --git a/dist/angular-gettext.min.js b/dist/angular-gettext.min.js index 8424fd2..38f1950 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=function(a){return g.debug&&g.currentLanguage!==g.baseLanguage?g.debugPrefix+a:a},i=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];this.strings[a][c]="string"==typeof d?[d]:d}f()},getStringForm:function(a,b){var c=this.strings[this.currentLanguage]||{},d=c[a]||[];return d[b]},getString:function(a,b){return a=this.getStringForm(a,0)||h(a),a=b?d(a)(b):a,i(a)},getPlural:function(b,c,e,f){var g=a(this.currentLanguage,b);return c=this.getStringForm(c,g)||h(1===b?c:e),c=f?d(c)(f):c,i(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",function(a,b,c,d){function e(a,b,c){if(!a)throw new Error("You should add a "+b+" attribute whenever you add a "+c+" attribute.")}var f=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}}();return{restrict:"A",terminal:!0,compile:function(g,h){e(!h.translatePlural||h.translateN,"translate-n","translate-plural"),e(!h.translateN||h.translatePlural,"translate-plural","translate-n");var i=f(g.html()),j=h.translatePlural;return{post:function(e,f,g){function h(){var b;j?(e=l||(l=e.$new()),e.$count=k(e),b=a.getPlural(e.$count,i,j)):b=a.getString(i);var g=angular.element(""+b+"");d(g.contents())(e);var h=f.contents(),m=g.contents();c.enter(m,f),c.leave(h)}var k=b(g.translateN),l=null;g.translateN&&e.$watch(g.translateN,h),e.$on("gettextLanguageChanged",h),h()}}}}}]),angular.module("gettext").filter("translate",["gettextCatalog",function(a){function b(b){return a.getString(b)}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").factory("gettextCatalog",["gettextPlurals","$http","$cacheFactory","$interpolate","$rootScope",function(a,b,c,d,e){function f(){e.$broadcast("gettextLanguageChanged")}var g,h=function(a){return g.debug&&g.currentLanguage!==g.baseLanguage?g.debugPrefix+a:a},i=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];this.strings[a][c]="string"==typeof d?[d]:d}f()},getStringForm:function(a,b){var c=this.strings[this.currentLanguage]||{},d=c[a]||[];return d[b]},getString:function(a,b){return a=this.getStringForm(a,0)||h(a),a=b?d(a)(b):a,i(a)},getPlural:function(b,c,e,f){var g=a(this.currentLanguage,b);return c=this.getStringForm(c,g)||h(1===b?c:e),c=c.replace(/\{\}/g,b),c=f?d(c)(f):c,i(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",function(a,b,c,d){function e(a,b,c){if(!a)throw new Error("You should add a "+b+" attribute whenever you add a "+c+" attribute.")}var f=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}}();return{restrict:"A",terminal:!0,compile:function(g,h){e(!h.translatePlural||h.translateN,"translate-n","translate-plural"),e(!h.translateN||h.translatePlural,"translate-plural","translate-n");var i=f(g.html()),j=h.translatePlural;return{post:function(e,f,g){function h(){var b;j?(e=l||(l=e.$new()),e.$count=k(e),b=a.getPlural(e.$count,i,j)):b=a.getString(i);var g=angular.element(""+b+"");d(g.contents())(e);var h=f.contents(),m=g.contents();c.enter(m,f),c.leave(h)}var k=b(g.translateN),l=null;g.translateN&&e.$watch(g.translateN,h),e.$on("gettextLanguageChanged",h),h()}}}}}]),angular.module("gettext").filter("translate",["gettextCatalog",function(a){function b(b){return a.getString(b)}return b.$stateful=!0,b}]),angular.module("gettext").filter("translatePlural",["gettextCatalog",function(a){function b(b,c,d){return a.getPlural(c,b,d)}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 diff --git a/src/catalog.js b/src/catalog.js index e9ec04c..775bd96 100644 --- a/src/catalog.js +++ b/src/catalog.js @@ -69,6 +69,10 @@ angular.module('gettext').factory('gettextCatalog', function (gettextPlurals, $h getPlural: function (n, string, stringPlural, context) { var form = gettextPlurals(this.currentLanguage, n); string = this.getStringForm(string, form) || prefixDebug(n === 1 ? string : stringPlural); + + // Replace {} pattern with number + string = string.replace(/\{\}/g, n); + string = context ? $interpolate(string)(context) : string; return addTranslatedMarkers(string); }, diff --git a/src/filter.js b/src/filter.js index ca4c799..7feba9c 100644 --- a/src/filter.js +++ b/src/filter.js @@ -5,3 +5,11 @@ angular.module('gettext').filter('translate', function (gettextCatalog) { filter.$stateful = true; return filter; }); + +angular.module('gettext').filter('translatePlural', ['gettextCatalog', function (gettextCatalog) { + function filter(string, n, stringPlural) { + return gettextCatalog.getPlural(n, string, stringPlural); + } + filter.$stateful = true; + return filter; +}]); diff --git a/test/unit/catalog.js b/test/unit/catalog.js index cffc757..66e8dad 100644 --- a/test/unit/catalog.js +++ b/test/unit/catalog.js @@ -112,6 +112,16 @@ describe("Catalog", function () { assert.equal(catalog.getPlural(1, "There is {{count}} bird", "There are {{count}} birds", { count: 1 }), "There is 1 bird"); }); + it("Can return an interpolated plural string for special {} pattern", function () { + assert.deepEqual(catalog.strings, {}); + catalog.currentLanguage = "gb"; + catalog.setStrings("gb", { + "There is {} bird": ["There is {} bird", "There are {} birds"] + }); + assert.equal(catalog.getPlural(2, "There is {} bird", "There are {} birds"), "There are 2 birds"); + assert.equal(catalog.getPlural(1, "There is {} bird", "There are {} birds"), "There is 1 bird"); + }); + it("Should add translation markers when enabled", function () { catalog.showTranslatedMarkers = true; assert.equal(catalog.getString("Bye"), "[Bye]"); diff --git a/test/unit/filter.js b/test/unit/filter.js index 22a6aa8..88a435b 100644 --- a/test/unit/filter.js +++ b/test/unit/filter.js @@ -36,3 +36,56 @@ describe("Filter", function () { assert.equal(el.attr("placeholder"), "Hallo"); }); }); + +describe("Filter: translatePlural", function () { + var catalog = null; + var $rootScope = null; + var $compile = null; + + beforeEach(module("gettext")); + + beforeEach(inject(function ($injector, gettextCatalog) { + $rootScope = $injector.get("$rootScope"); + $compile = $injector.get("$compile"); + catalog = gettextCatalog; + catalog.setStrings("nl", { + Hello: "Hallo", + "Hello {{name}}!": "Hallo {{name}}!", + "One boat": ["Een boot", "{} boten"] + }); + + $rootScope.n = 1; + })); + + it("Should have a translatePlural filter", function () { + var el = $compile("