FIX: Handle missing plural keys on client

FIX: Handle missing plural keys on client

diff --git a/app/assets/javascripts/locales/i18n.js b/app/assets/javascripts/locales/i18n.js
index 58b824f..cffc2e2 100644
--- a/app/assets/javascripts/locales/i18n.js
+++ b/app/assets/javascripts/locales/i18n.js
@@ -131,39 +131,47 @@ I18n.interpolate = function(message, options) {
 
 I18n.translate = function(scope, options) {
   options = this.prepareOptions(options);
+  options.needsPluralization = typeof options.count === "number";
+  options.ignoreMissing = !this.noFallbacks;
 
-  var translation = this.lookup(scope, options);
+  var translation = this.findTranslation(scope, options);
 
   if (!this.noFallbacks) {
     if (!translation && this.fallbackLocale) {
       options.locale = this.fallbackLocale;
-      translation = this.lookup(scope, options);
+      translation = this.findTranslation(scope, options);
     }
+
+    options.ignoreMissing = false;
+
     if (!translation && this.currentLocale() !== this.defaultLocale) {
       options.locale = this.defaultLocale;
-      translation = this.lookup(scope, options);
+      translation = this.findTranslation(scope, options);
     }
+
     if (!translation && this.currentLocale() !== 'en') {
       options.locale = 'en';
-      translation = this.lookup(scope, options);
+      translation = this.findTranslation(scope, options);
     }
   }
 
   try {
-    if (typeof translation === "object") {
-      if (typeof options.count === "number") {
-        return this.pluralize(translation, scope, options);
-      } else {
-        return translation;
-      }
-    } else {
-      return this.interpolate(translation, options);
-    }
+    return this.interpolate(translation, options);
   } catch (error) {
     return this.missingTranslation(scope);
   }
 };
 
+I18n.findTranslation = function(scope, options) {
+  var translation = this.lookup(scope, options);
+
+  if (translation && options.needsPluralization) {
+    translation = this.pluralize(translation, scope, options);
+  }
+
+  return translation;
+};
+
 I18n.toNumber = function(number, options) {
   options = this.prepareOptions(
     options,
@@ -260,6 +268,8 @@ I18n.findAndTranslateValidNode = function(keys, translation) {
 };
 
 I18n.pluralize = function(translation, scope, options) {
+  if (typeof translation !== "object") return translation;
+
   options = this.prepareOptions(options);
   var count = options.count.toString();
 
@@ -268,9 +278,12 @@ I18n.pluralize = function(translation, scope, options) {
   var keys = ((typeof key === "object") && (key instanceof Array)) ? key : [key];
 
   var message = this.findAndTranslateValidNode(keys, translation);
-  if (message == null) message = this.missingTranslation(scope, keys[0]);
 
-  return this.interpolate(message, options);
+  if (message !== null || options.ignoreMissing) {
+    return message;
+  }
+
+  return this.missingTranslation(scope, keys[0]);
 };
 
 I18n.missingTranslation = function(scope, key) {
diff --git a/test/javascripts/lib/i18n-test.js.es6 b/test/javascripts/lib/i18n-test.js.es6
index b68c871..f1c628a 100644
--- a/test/javascripts/lib/i18n-test.js.es6
+++ b/test/javascripts/lib/i18n-test.js.es6
@@ -2,6 +2,8 @@ QUnit.module("lib:i18n", {
   _locale: I18n.locale,
   _fallbackLocale: I18n.fallbackLocale,
   _translations: I18n.translations,
+  _extras: I18n.extras,
+  _pluralizationRules: Object.assign({}, I18n.pluralizationRules),
 
   beforeEach() {
     I18n.locale = "fr";
@@ -34,6 +36,9 @@ QUnit.module("lib:i18n", {
             few: "{{count}} FEW",
             many: "{{count}} MANY",
             other: "{{count}} OTHER"
+          },
+          days: {
+            other: "%{count} jours"
           }
         }
       },
@@ -51,12 +56,17 @@ QUnit.module("lib:i18n", {
           word_count: {
             one: "1 word",
             other: "{{count}} words"
+          },
+          days: {
+            one: "%{count} day",
+            other: "%{count} days"
           }
         }
       }
     };
 
     // fake pluralization rules
+    I18n.pluralizationRules = Object.assign({}, I18n.pluralizationRules);
     I18n.pluralizationRules.fr = function(n) {
       if (n === 0) return "zero";
       if (n === 1) return "one";
@@ -71,6 +81,8 @@ QUnit.module("lib:i18n", {
     I18n.locale = this._locale;
     I18n.fallbackLocale = this._fallbackLocale;
     I18n.translations = this._translations;
+    I18n.extras = this._extras;
+    I18n.pluralizationRules = this._pluralizationRules;
   }
 });
 
@@ -181,6 +193,17 @@ QUnit.test("pluralizations", assert => {
 });
 
 QUnit.test("fallback", assert => {
+  assert.equal(
+    I18n.t("days", { count: 1 }),
+    "1 day",
+    "uses fallback locale for missing plural key"
+  );
+  assert.equal(
+    I18n.t("days", { count: 200 }),
+    "200 jours",
+    "uses existing French plural key"
+  );
+
   I18n.locale = "fr_FOO";
   I18n.fallbackLocale = "fr";

GitHub sha: d1228f47

1 Like

This commit has been mentioned on Discourse Meta. There might be relevant details there: