Browse Source

Use FluentResource to parse and serialize FTL files server-side (#952)

Staś Małolepszy 6 years ago
parent
commit
f8964ebb99
3 changed files with 41 additions and 40 deletions
  1. 32 29
      build/fluent_loader.js
  2. 8 10
      package-lock.json
  3. 1 1
      package.json

+ 32 - 29
build/fluent_loader.js

@@ -1,16 +1,8 @@
-const { FluentBundle } = require('fluent');
+const { FluentResource } = require('fluent/compat');
 const fs = require('fs');
 
-function toJSON(map) {
-  return JSON.stringify(Array.from(map));
-}
-
-function merge(m1, m2) {
-  const result = new Map(m1);
-  for (const [k, v] of m2) {
-    result.set(k, v);
-  }
-  return result;
+function toJSON(resource) {
+  return JSON.stringify(Array.from(resource));
 }
 
 module.exports = function(source) {
@@ -20,34 +12,45 @@ module.exports = function(source) {
   if (!locale) {
     throw new Error(`couldn't find locale in: ${this.resourcePath}`);
   }
-  // load default language and "merge" contexts
-  // TODO: make this configurable
-  const en_ftl = fs.readFileSync(
-    require.resolve('../public/locales/en-US/send.ftl'),
-    'utf8'
-  );
-  const en = new FluentBundle('en-US');
-  en.addMessages(en_ftl);
-  // pre-parse the ftl
-  const context = new FluentBundle(locale);
-  context.addMessages(source);
 
-  const merged = merge(en._messages, context._messages);
+  // Parse the current language's translation file.
+  const locResource = FluentResource.fromString(source);
+  let enResource;
+
+  // If the current language is not en-US, also parse en-US to provide a
+  // fallback for missing translations.
+  if (locale !== 'en-US') {
+    const en_ftl = fs.readFileSync(
+      require.resolve('../public/locales/en-US/send.ftl'),
+      'utf8'
+    );
+    enResource = FluentResource.fromString(en_ftl);
+  }
+
   return `
 module.exports = \`
 if (typeof window === 'undefined') {
   var fluent = require('fluent');
 }
 (function () {
-  var bundle = new fluent.FluentBundle('${locale}', {useIsolating: false});
-  bundle._messages = new Map(${toJSON(merged)});
+  let bundles = [
+    ['${locale}', ${toJSON(locResource)}],
+    ${enResource ? `['en-US', ${toJSON(enResource)}]` : ''}
+  ].map(([locale, entries]) => {
+    let bundle = new fluent.FluentBundle(locale, {useIsolating: false});
+    bundle.addResource(new fluent.FluentResource(entries));
+    return bundle;
+  });
+
   function translate(id, data) {
-    var msg = bundle.getMessage(id);
-    if (typeof(msg) !== 'string' && !msg.val && msg.attrs) {
-      msg = msg.attrs.title || msg.attrs.alt
+    for (let bundle of bundles) {
+      if (bundle.hasMessage(id)) {
+        let message = bundle.getMessage(id);
+        return bundle.format(message, data);
+      }
     }
-    return bundle.format(msg, data);
   }
+
   if (typeof window === 'undefined') {
     module.exports = translate;
   }

+ 8 - 10
package-lock.json

@@ -6675,9 +6675,9 @@
       "dev": true
     },
     "fluent": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/fluent/-/fluent-0.8.0.tgz",
-      "integrity": "sha512-bZfthhubEH1lKgGIi0fIDeNkZrfEOu3MrLbi284LdxNG+9Q5gq2KsuoocumqNPStVtWo3S3/1p8RIqd34u3Mzw=="
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/fluent/-/fluent-0.8.1.tgz",
+      "integrity": "sha512-hVlyzl3N9okoqqQUd6cExsBAOmxBeaxP3JFmBBPkYqSRQs4d2U2y2a5KxwMSvno1m9nmwM4CsjeBWdJ9wSYWsA=="
     },
     "fluent-intl-polyfill": {
       "version": "0.1.0",
@@ -6686,13 +6686,6 @@
       "dev": true,
       "requires": {
         "intl-pluralrules": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b"
-      },
-      "dependencies": {
-        "intl-pluralrules": {
-          "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b",
-          "from": "github:projectfluent/IntlPluralRules#module",
-          "dev": true
-        }
       }
     },
     "fluent-langneg": {
@@ -8188,6 +8181,11 @@
       "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
       "dev": true
     },
+    "intl-pluralrules": {
+      "version": "github:projectfluent/IntlPluralRules#94cb0fa1c23ad943bc5aafef43cea132fa51d68b",
+      "from": "github:projectfluent/IntlPluralRules#module",
+      "dev": true
+    },
     "invariant": {
       "version": "2.2.4",
       "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",

+ 1 - 1
package.json

@@ -125,7 +125,7 @@
     "convict": "^4.4.0",
     "express": "^4.16.3",
     "express-ws": "^4.0.0",
-    "fluent": "^0.8.0",
+    "fluent": "^0.8.1",
     "fluent-langneg": "^0.1.0",
     "helmet": "^3.13.0",
     "mkdirp": "^0.5.1",