Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Add provision for scope inheritance and recursive fallback to parent scope for the keys in localization files #94

Closed
wants to merge 1 commit into from

2 participants

@tvsathish

E.g.

When the localization JSON applied has the following structure
{
Key1:Value1
Scope1:
{
Key2:value2
Scope2: { Key3: value3 }
}
}
then a lookup of
a) Scope1.Scope2.Key1 should return Value1
b) Scope1.Scope2.Key2 should return Value2
c) Scope1.Scope2.Key3 should return Value3
d) Scope1.Scope2.Key4 should return null.

Padmanabhan Venkitasubramanian Add provision for scope inheritance and recursive fallback to parent …
…scope for the keys in localization files
2c25bac
@fnando
Owner

Thanks for your patch. Not applying/maintaining master branch anymore. Will set rewrite branch as master soon, so you can send this patch again over that codebase if still needed.

@fnando fnando closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 17, 2012
  1. Add provision for scope inheritance and recursive fallback to parent …

    Padmanabhan Venkitasubramanian authored
    …scope for the keys in localization files
This page is out of date. Refresh to see the latest.
Showing with 44 additions and 4 deletions.
  1. +27 −0 spec/i18n_spec.js
  2. +17 −4 vendor/assets/javascripts/i18n.js
View
27 spec/i18n_spec.js
@@ -817,4 +817,31 @@ describe("I18n.js", function(){
expect(I18n.findAndTranslateValidNode(["one", "other"], {other: "other"})).toBeEqualTo("other");
expect(I18n.findAndTranslateValidNode(["one"], {})).toBeEqualTo(null);
});
+
+ // Scope fallback tests
+ specify('should not perform scope fallback if not configured',function(){
+ expect(I18n.lookup("number.human.storage_units.units.large.kb")).toBe(undefined);
+ expect(I18n.translate("greetings.hello")).toBe('[missing "en.greetings.hello" translation]');
+ });
+
+ specify('should override global scope fallback configuration on a method-level if specified',function() {
+ expect(I18n.translate("greetings.hello")).toBe('[missing "en.greetings.hello" translation]');
+ expect(I18n.translate("greetings.hello",{scopeFallbackNeeded: true})).toBe('Hello World!');
+ I18n.scopeFallbackNeeded=true;
+ expect(I18n.translate("greetings.hello")).toBe('Hello World!');
+ expect(I18n.translate("greetings.hello",{scopeFallbackNeeded: false})).toBe('[missing "en.greetings.hello" translation]');
+ });
+
+ specify('should compute parent scope by excluding second last scope element from key when original key is not found', function() {
+ I18n.scopeFallbackNeeded = true;
+ expect(I18n.translate("number.human.storage_units.units.large.kb")).toBe("KB");
+ expect(I18n.translate("greetings.hello")).toBe("Hello World!");
+ expect(I18n.translate("greetings.name",{name:"Sam"})).toBe("Hello Sam!");
+ });
+
+ specify('should compute parent scope properly for single-scoped keys', function() {
+ I18n.scopeFallbackNeeded = true;
+ expect(I18n.translate("hello")).toBe("Hello World!");
+ expect(I18n.translate("address")).toBe('[missing "en.address" translation]');
+ });
});
View
21 vendor/assets/javascripts/i18n.js
@@ -57,6 +57,9 @@ I18n.defaultSeparator = ".";
// Set current locale to null
I18n.locale = null;
+// Fallback to parent scope
+I18n.scopeFallbackNeeded = false;
+
// Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
@@ -92,6 +95,11 @@ I18n.isValidNode = function(obj, node, undefined) {
return obj[node] !== null && obj[node] !== undefined;
};
+var computeFallbackScope= function(scopes) {
+ scopes.splice(scopes.length < 2 ? 0 : -2, 1);
+ return scopes;
+};
+
I18n.lookup = function(scope, options) {
var options = options || {}
, lookupInitialScope = scope
@@ -100,8 +108,10 @@ I18n.lookup = function(scope, options) {
, messages = translations[locale] || {}
, options = this.prepareOptions(options)
, currentScope
- ;
+ , scopeFallbackNeeded;
+ scopeFallbackNeeded = (options.scopeFallbackNeeded !== undefined) ?
+ options.scopeFallbackNeeded : this.scopeFallbackNeeded;
if (typeof(scope) == "object") {
scope = scope.join(this.defaultSeparator);
}
@@ -110,17 +120,21 @@ I18n.lookup = function(scope, options) {
scope = options.scope.toString() + this.defaultSeparator + scope;
}
+ var originalScopes = scope.split(this.defaultSeparator);
scope = scope.split(this.defaultSeparator);
while (messages && scope.length > 0) {
currentScope = scope.shift();
messages = messages[currentScope];
}
-
if (!messages) {
+
+ if (scopeFallbackNeeded && originalScopes.length > 1) {
+ return I18n.lookup(computeFallbackScope(originalScopes).join(this.defaultSeparator));
+ }
if (I18n.fallbacks) {
var fallbacks = this.getFallbacks(locale);
- for (var fallback = 0; fallback < fallbacks.length; fallbacks++) {
+ for (var fallback = 0; fallback < fallbacks.length; fallback++) {
messages = I18n.lookup(lookupInitialScope, this.prepareOptions({locale: fallbacks[fallback]}, options));
if (messages) {
break;
@@ -132,7 +146,6 @@ I18n.lookup = function(scope, options) {
messages = options.defaultValue;
}
}
-
return messages;
};
Something went wrong with that request. Please try again.