This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/lib/translation-plugin.js
David Taylor ff5a6edb71 DEV: Update plugin JS loading in Ember CLI testem environment
Previously we were adding `/assets/discourse/tests/core_plugin_tests.js` to the test html all the time. This works in development mode, but fails silently when using testem via the `ember test` CLI, because there is no proxy running.

This commit makes a few changes to fix this, and make it more useful:

- Only renders the plugin `<script>` when in development mode, or when `LOAD_PLUGINS=1` (matching core's behavior)
- Only loads plugin translations based on the same logic
- When running via testem, and the above conditions are met, testem is configured to proxy `core_plugin_tests.js` through to a rails server. (port based on the `UNICORN_PORT` env variable)
- Adds a descriptive error if the plugin `<script>` fails to load. This can happen if the rails server hasn't been started
- Updates the logic for testem browsers. Ember CLI always launches testem in "CI" mode, and we don't really want 3 browsers opening by default. Our CI explicitly specifies the 3 browsers at runtime
2022-01-18 10:16:29 +00:00

137 lines
3.5 KiB
JavaScript

const Plugin = require("broccoli-plugin");
const Yaml = require("js-yaml");
const fs = require("fs");
const concat = require("broccoli-concat");
const mergeTrees = require("broccoli-merge-trees");
const MessageFormat = require("messageformat");
const deepmerge = require("deepmerge");
const glob = require("glob");
const { shouldLoadPluginTestJs } = require("discourse/lib/plugin-js");
let built = false;
class TranslationPlugin extends Plugin {
constructor(inputNodes, inputFile, options) {
super(inputNodes, {
...options,
persistentOutput: true,
});
this.inputFile = inputFile;
}
replaceMF(formats, input, path = []) {
if (!input) {
return;
}
Object.keys(input).forEach((key) => {
let value = input[key];
let subpath = path.concat(key);
if (typeof value === "object") {
this.replaceMF(formats, value, subpath);
} else if (key.endsWith("_MF")) {
// omit locale.js
let mfPath = subpath.slice(2).join(".");
formats[mfPath] = this.mf.precompile(this.mf.parse(value));
}
});
}
build() {
// We could get fancy eventually and do this based on whether the yaml
// or vendor files change but in practice we shouldn't need exact up to date
// translations in admin.
if (built) {
return;
}
let parsed = {};
this.inputPaths.forEach((path) => {
let file = path + "/" + this.inputFile;
let yaml = fs.readFileSync(file, { encoding: "UTF-8" });
let loaded = Yaml.load(yaml, { json: true });
parsed = deepmerge(parsed, loaded);
});
let extras = {
en: {
admin: parsed.en.admin_js.admin,
},
};
delete parsed.en.admin_js;
delete parsed.en.wizard_js;
let formats = {};
this.mf = new MessageFormat("en");
this.replaceMF(formats, parsed);
this.replaceMF(formats, extras);
formats = Object.keys(formats).map((k) => `"${k}": ${formats[k]}`);
let contents = `
I18n.locale = 'en';
I18n.translations = ${JSON.stringify(parsed)};
I18n.extras = ${JSON.stringify(extras)};
MessageFormat = { locale: {} };
I18n._compiledMFs = { ${formats.join(",\n")} };
`;
fs.writeFileSync(
`${this.outputPath}/` + this.inputFile.replace(".yml", ".js"),
contents
);
built = true;
}
}
module.exports = function translatePlugin(...params) {
return new TranslationPlugin(...params);
};
module.exports.createI18nTree = function (discourseRoot, vendorJs) {
let translations = [discourseRoot + "/config/locales"];
if (shouldLoadPluginTestJs()) {
translations = translations.concat(
glob
.sync(discourseRoot + "/plugins/*/config/locales/client.en.yml")
.map((f) => f.replace(/\/client\.en\.yml$/, ""))
);
}
let en = new TranslationPlugin(translations, "client.en.yml");
return concat(
mergeTrees([
vendorJs,
discourseRoot + "/app/assets/javascripts/locales",
discourseRoot + "/lib/javascripts",
en,
]),
{
inputFiles: [
"i18n.js",
"moment.js",
"moment-timezone-with-data.js",
"messageformat-lookup.js",
"locale/en.js",
"client.en.js",
],
headerFiles: [
"i18n.js",
"moment.js",
"moment-timezone-with-data.js",
"messageformat-lookup.js",
],
footerFiles: ["client.en.js", "locale/en.js"],
outputFile: `assets/test-i18n.js`,
}
);
};
module.exports.TranslationPlugin = TranslationPlugin;