Skip to content

Add support for multiple fallback languages (fallback waterfall) #345

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"element",
"expect",
"inject",
"it"
"it",
"JSON"
]
}
111 changes: 90 additions & 21 deletions dist/angular-gettext.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ angular.module('gettext').constant('gettext', function (str) {
*/
return str;
});

/**
* @ngdoc service
* @module gettext
Expand All @@ -60,9 +60,9 @@ angular.module('gettext').constant('gettext', function (str) {
* @requires https://docs.angularjs.org/api/ng/service/$cacheFactory $cacheFactory
* @requires https://docs.angularjs.org/api/ng/service/$interpolate $interpolate
* @requires https://docs.angularjs.org/api/ng/service/$rootScope $rootScope
* @description Provides set of method to translate stings
* @description Provides set of method to translate strings
*/
angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextFallbackLanguage", "$http", "$cacheFactory", "$interpolate", "$rootScope", function (gettextPlurals, gettextFallbackLanguage, $http, $cacheFactory, $interpolate, $rootScope) {
angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextFallbackLanguage", "gettextUtil", "$http", "$cacheFactory", "$interpolate", "$rootScope", function (gettextPlurals, gettextFallbackLanguage, gettextUtil, $http, $cacheFactory, $interpolate, $rootScope) {
var catalog;
var noContext = '$$noContext';

Expand Down Expand Up @@ -172,6 +172,14 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* @description Active language.
*/
currentLanguage: 'en',
/**
* @ngdoc property
* @name gettextCatalog#fallbackLanguages
* @public
* @type {Object.<Array>.<String>}
* @description Fallback languages.
*/
fallbackLanguages: {},
/**
* @ngdoc property
* @name gettextCatalog#cache
Expand Down Expand Up @@ -204,6 +212,28 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
return this.currentLanguage;
},

/**
* @ngdoc method
* @name gettextCatalog#setFallbackLanguages
* @public
* @param {Object.<Array>.<String>} fallbacks set of string arrays where the key is the source language, and the strings in the array the fallback langauges to try, in order
* @description Sets the fallback languages.
*/
setFallbackLanguages: function (fallbacks) {
this.fallbackLanguages = gettextUtil.copy(fallbacks || {});
},

/**
* @ngdoc method
* @name gettextCatalog#getFallbackLanguages
* @public
* @returns {Object.<Array>.<String>} fallback languages
* @description Returns the fallback languages.
*/
getFallbackLanguages: function () {
return gettextUtil.copy(this.fallbackLanguages);
},

/**
* @ngdoc method
* @name gettextCatalog#setStrings
Expand Down Expand Up @@ -258,7 +288,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* @protected
* @param {String} language language name
* @param {String} string translation key
* @param {Number=} n number to build sting form for
* @param {Number=} n number to build string form for
* @param {String=} context translation key context, e.g. {@link doc:context Verb, Noun}
* @returns {String|Null} translated or annotated string or null if language is not set
* @description Translate a string with the given language, count and context.
Expand All @@ -273,6 +303,32 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
return plurals[gettextPlurals(language, n)];
},

/**
* @ngdoc method
* @name gettextCatalog#getFallbackStringFormFor
* @protected
* @param {String} language language name
* @param {String} string translation key
* @param {Number=} n number to build string form for
* @param {String=} context translation key context, e.g. {@link doc:context Verb, Noun}
* @param {String=} stringPlural plural translation key
* @returns {String|Null} translated or annotated string or null if language is not set
* @description Translate a string with the given language, count and context.
*
* First it tries a language (e.g. `en-US`) then {@link gettextCatalog#fallbackLanguages language}, if any, then {@link gettextFallbackLanguage fallback} (e.g. `en`).
*/
getFallbackStringFormFor: function (language, string, n, context, stringPlural) {
var fallbackLanguages = (this.fallbackLanguages[language] || []).slice();
var defaultFallbackLanguage = gettextFallbackLanguage(language);
if (defaultFallbackLanguage) { fallbackLanguages.push(defaultFallbackLanguage); }

var output = this.getStringFormFor(language, string, n, context);
for (var i = 0; i < fallbackLanguages.length; i++) {
output = output || this.getStringFormFor(fallbackLanguages[i], string, n, context);
}
return output || prefixDebug(n === 1 ? string : stringPlural);
},

/**
* @ngdoc method
* @name gettextCatalog#getString
Expand All @@ -283,8 +339,6 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* @returns {String} translated or annotated string
* @description Translate a string with the given scope and context.
*
* First it tries {@link gettextCatalog#currentLanguage gettextCatalog#currentLanguage} (e.g. `en-US`) then {@link gettextFallbackLanguage fallback} (e.g. `en`).
*
* When `scope` is supplied it uses Angular.JS interpolation, so something like this will do what you expect:
* ```js
* var hello = gettextCatalog.getString("Hello {{name}}!", { name: "Ruben" });
Expand All @@ -293,10 +347,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* Avoid using scopes - this skips interpolation and is a lot faster.
*/
getString: function (string, scope, context) {
var fallbackLanguage = gettextFallbackLanguage(this.currentLanguage);
string = this.getStringFormFor(this.currentLanguage, string, 1, context) ||
this.getStringFormFor(fallbackLanguage, string, 1, context) ||
prefixDebug(string);
string = this.getFallbackStringFormFor(this.currentLanguage, string, 1, context);
string = scope ? $interpolate(string)(scope) : string;
return addTranslatedMarkers(string);
},
Expand All @@ -305,7 +356,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* @ngdoc method
* @name gettextCatalog#getPlural
* @public
* @param {Number} n number to build sting form for
* @param {Number} n number to build string form for
* @param {String} string translation key
* @param {String} stringPlural plural translation key
* @param {$rootScope.Scope=} scope scope to do interpolation against
Expand All @@ -315,10 +366,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF
* @description Translate a plural string with the given context.
*/
getPlural: function (n, string, stringPlural, scope, context) {
var fallbackLanguage = gettextFallbackLanguage(this.currentLanguage);
string = this.getStringFormFor(this.currentLanguage, string, n, context) ||
this.getStringFormFor(fallbackLanguage, string, n, context) ||
prefixDebug(n === 1 ? string : stringPlural);
string = this.getFallbackStringFormFor(this.currentLanguage, string, n, context, stringPlural);
if (scope) {
scope.$count = n;
string = $interpolate(string)(scope);
Expand Down Expand Up @@ -353,7 +401,7 @@ angular.module('gettext').factory('gettextCatalog', ["gettextPlurals", "gettextF

return catalog;
}]);

/**
* @ngdoc directive
* @module gettext
Expand Down Expand Up @@ -531,7 +579,7 @@ angular.module('gettext').directive('translate', ["gettextCatalog", "$parse", "$
}
};
}]);

/**
* @ngdoc factory
* @module gettext
Expand Down Expand Up @@ -564,7 +612,7 @@ angular.module("gettext").factory("gettextFallbackLanguage", function () {

return null;
};
});
});
/**
* @ngdoc filter
* @module gettext
Expand Down Expand Up @@ -593,7 +641,7 @@ angular.module('gettext').filter('translate', ["gettextCatalog", function (gette
filter.$stateful = true;
return filter;
}]);

// Do not edit this file, it is autogenerated using genplurals.py!
angular.module("gettext").factory("gettextPlurals", function () {
var languageCodes = {
Expand Down Expand Up @@ -725,7 +773,7 @@ angular.module("gettext").factory("gettextPlurals", function () {
return languageCodes[langCode];
}
});

/**
* @ngdoc factory
* @module gettext
Expand Down Expand Up @@ -816,10 +864,31 @@ angular.module('gettext').factory('gettextUtil', function gettextUtil() {
return first + target.substr(1);
}

/**
* @ngdoc method
* @name gettextUtil#copy
* @public
* @param {object} o Object to copy.
* @returns {object} A copy of the object.
* @description Makes a deep copy of an object, making sure to not keep any references to the original object.
*/
function copy(o) {
var output;
var v;
var key;
output = Array.isArray(o) ? [] : {};
for (key in o) {
v = o[key];
output[key] = (typeof v === 'object') ? copy(v) : v;
}
return output;
}

return {
trim: trim,
assert: assert,
startsWith: startsWith,
lcFirst: lcFirst
lcFirst: lcFirst,
copy: copy
};
});
Loading