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

This commit is contained in:
Staś Małolepszy 2018-09-27 20:49:41 +02:00 committed by Danny Coates
parent a997a44a23
commit f8964ebb99
3 changed files with 41 additions and 40 deletions

View File

@ -1,16 +1,8 @@
const { FluentBundle } = require('fluent'); const { FluentResource } = require('fluent/compat');
const fs = require('fs'); const fs = require('fs');
function toJSON(map) { function toJSON(resource) {
return JSON.stringify(Array.from(map)); return JSON.stringify(Array.from(resource));
}
function merge(m1, m2) {
const result = new Map(m1);
for (const [k, v] of m2) {
result.set(k, v);
}
return result;
} }
module.exports = function(source) { module.exports = function(source) {
@ -20,34 +12,45 @@ module.exports = function(source) {
if (!locale) { if (!locale) {
throw new Error(`couldn't find locale in: ${this.resourcePath}`); 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 ` return `
module.exports = \` module.exports = \`
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
var fluent = require('fluent'); var fluent = require('fluent');
} }
(function () { (function () {
var bundle = new fluent.FluentBundle('${locale}', {useIsolating: false}); let bundles = [
bundle._messages = new Map(${toJSON(merged)}); ['${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) { function translate(id, data) {
var msg = bundle.getMessage(id); for (let bundle of bundles) {
if (typeof(msg) !== 'string' && !msg.val && msg.attrs) { if (bundle.hasMessage(id)) {
msg = msg.attrs.title || msg.attrs.alt let message = bundle.getMessage(id);
return bundle.format(message, data);
}
} }
return bundle.format(msg, data);
} }
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
module.exports = translate; module.exports = translate;
} }

18
package-lock.json generated
View File

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

View File

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