Use FluentResource to parse and serialize FTL files server-side (#952)
This commit is contained in:
parent
a997a44a23
commit
f8964ebb99
|
@ -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
|
// 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(
|
const en_ftl = fs.readFileSync(
|
||||||
require.resolve('../public/locales/en-US/send.ftl'),
|
require.resolve('../public/locales/en-US/send.ftl'),
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
);
|
||||||
const en = new FluentBundle('en-US');
|
enResource = FluentResource.fromString(en_ftl);
|
||||||
en.addMessages(en_ftl);
|
}
|
||||||
// pre-parse the ftl
|
|
||||||
const context = new FluentBundle(locale);
|
|
||||||
context.addMessages(source);
|
|
||||||
|
|
||||||
const merged = merge(en._messages, context._messages);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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",
|
||||||
|
|
Loading…
Reference in New Issue