Skip to content
This repository

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 Nando Vieira
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
Nando Vieira
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.

Nando Vieira fnando closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

May 17, 2012
Padmanabhan Venkitasubramanian Add provision for scope inheritance and recursive fallback to parent …
…scope for the keys in localization files
2c25bac
This page is out of date. Refresh to see the latest.

Showing 2 changed files with 44 additions and 4 deletions. Show diff stats Hide diff stats

  1. +27 0 spec/i18n_spec.js
  2. +17 4 vendor/assets/javascripts/i18n.js
27 spec/i18n_spec.js
@@ -817,4 +817,31 @@ describe("I18n.js", function(){
817 817 expect(I18n.findAndTranslateValidNode(["one", "other"], {other: "other"})).toBeEqualTo("other");
818 818 expect(I18n.findAndTranslateValidNode(["one"], {})).toBeEqualTo(null);
819 819 });
  820 +
  821 + // Scope fallback tests
  822 + specify('should not perform scope fallback if not configured',function(){
  823 + expect(I18n.lookup("number.human.storage_units.units.large.kb")).toBe(undefined);
  824 + expect(I18n.translate("greetings.hello")).toBe('[missing "en.greetings.hello" translation]');
  825 + });
  826 +
  827 + specify('should override global scope fallback configuration on a method-level if specified',function() {
  828 + expect(I18n.translate("greetings.hello")).toBe('[missing "en.greetings.hello" translation]');
  829 + expect(I18n.translate("greetings.hello",{scopeFallbackNeeded: true})).toBe('Hello World!');
  830 + I18n.scopeFallbackNeeded=true;
  831 + expect(I18n.translate("greetings.hello")).toBe('Hello World!');
  832 + expect(I18n.translate("greetings.hello",{scopeFallbackNeeded: false})).toBe('[missing "en.greetings.hello" translation]');
  833 + });
  834 +
  835 + specify('should compute parent scope by excluding second last scope element from key when original key is not found', function() {
  836 + I18n.scopeFallbackNeeded = true;
  837 + expect(I18n.translate("number.human.storage_units.units.large.kb")).toBe("KB");
  838 + expect(I18n.translate("greetings.hello")).toBe("Hello World!");
  839 + expect(I18n.translate("greetings.name",{name:"Sam"})).toBe("Hello Sam!");
  840 + });
  841 +
  842 + specify('should compute parent scope properly for single-scoped keys', function() {
  843 + I18n.scopeFallbackNeeded = true;
  844 + expect(I18n.translate("hello")).toBe("Hello World!");
  845 + expect(I18n.translate("address")).toBe('[missing "en.address" translation]');
  846 + });
820 847 });
21 vendor/assets/javascripts/i18n.js
@@ -57,6 +57,9 @@ I18n.defaultSeparator = ".";
57 57 // Set current locale to null
58 58 I18n.locale = null;
59 59
  60 +// Fallback to parent scope
  61 +I18n.scopeFallbackNeeded = false;
  62 +
60 63 // Set the placeholder format. Accepts `{{placeholder}}` and `%{placeholder}`.
61 64 I18n.PLACEHOLDER = /(?:\{\{|%\{)(.*?)(?:\}\}?)/gm;
62 65
@@ -92,6 +95,11 @@ I18n.isValidNode = function(obj, node, undefined) {
92 95 return obj[node] !== null && obj[node] !== undefined;
93 96 };
94 97
  98 +var computeFallbackScope= function(scopes) {
  99 + scopes.splice(scopes.length < 2 ? 0 : -2, 1);
  100 + return scopes;
  101 +};
  102 +
95 103 I18n.lookup = function(scope, options) {
96 104 var options = options || {}
97 105 , lookupInitialScope = scope
@@ -100,8 +108,10 @@ I18n.lookup = function(scope, options) {
100 108 , messages = translations[locale] || {}
101 109 , options = this.prepareOptions(options)
102 110 , currentScope
103   - ;
  111 + , scopeFallbackNeeded;
104 112
  113 + scopeFallbackNeeded = (options.scopeFallbackNeeded !== undefined) ?
  114 + options.scopeFallbackNeeded : this.scopeFallbackNeeded;
105 115 if (typeof(scope) == "object") {
106 116 scope = scope.join(this.defaultSeparator);
107 117 }
@@ -110,17 +120,21 @@ I18n.lookup = function(scope, options) {
110 120 scope = options.scope.toString() + this.defaultSeparator + scope;
111 121 }
112 122
  123 + var originalScopes = scope.split(this.defaultSeparator);
113 124 scope = scope.split(this.defaultSeparator);
114 125
115 126 while (messages && scope.length > 0) {
116 127 currentScope = scope.shift();
117 128 messages = messages[currentScope];
118 129 }
119   -
120 130 if (!messages) {
  131 +
  132 + if (scopeFallbackNeeded && originalScopes.length > 1) {
  133 + return I18n.lookup(computeFallbackScope(originalScopes).join(this.defaultSeparator));
  134 + }
121 135 if (I18n.fallbacks) {
122 136 var fallbacks = this.getFallbacks(locale);
123   - for (var fallback = 0; fallback < fallbacks.length; fallbacks++) {
  137 + for (var fallback = 0; fallback < fallbacks.length; fallback++) {
124 138 messages = I18n.lookup(lookupInitialScope, this.prepareOptions({locale: fallbacks[fallback]}, options));
125 139 if (messages) {
126 140 break;
@@ -132,7 +146,6 @@ I18n.lookup = function(scope, options) {
132 146 messages = options.defaultValue;
133 147 }
134 148 }
135   -
136 149 return messages;
137 150 };
138 151

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.