UNPKG

infusion

Version:

Infusion is an application framework for developing flexible stuff with JavaScript

138 lines (128 loc) 6.02 kB
/* Copyright The Infusion copyright holders See the AUTHORS.md file at the top-level directory of this distribution and at https://github.com/fluid-project/infusion/raw/main/AUTHORS.md. Licensed under the Educational Community License (ECL), Version 2.0 or the New BSD license. You may not use this file except in compliance with one these Licenses. You may obtain a copy of the ECL 2.0 License and BSD License at https://github.com/fluid-project/infusion/raw/main/Infusion-LICENSE.txt */ "use strict"; fluid.defaults("fluid.messageResolver", { gradeNames: ["fluid.component"], mergePolicy: { messageBase: "nomerge", parents: "nomerge" }, resolveFunc: fluid.stringTemplate, parseFunc: fluid.identity, messageBase: {}, members: { messageBase: "@expand:{that}.options.parseFunc({that}.options.messageBase)" }, invokers: { lookup: "fluid.messageResolver.lookup({that}, {arguments}.0)", // messagecodes resolve: "fluid.messageResolver.resolve({that}, {arguments}.0, {arguments}.1)" // messagecodes, args }, parents: [] }); /** * Look up the first matching message template, starting with the current grade and working up through its parents. * Returns both the template for the message and the function used to resolve the localised value. By default * the resolve function is `fluid.stringTemplate`, and the template returned uses its syntax. * * @param {Object} that - The component itself. * @param {String[]} messagecodes - One or more message codes to look up templates for. * @return {Object} - An object that contains `template` and `resolveFunc` members (see above). */ fluid.messageResolver.lookup = function (that, messagecodes) { var resolved = fluid.messageResolver.resolveOne(that.messageBase, messagecodes); if (resolved === undefined) { return fluid.find(that.options.parents, function (parent) { return parent ? parent.lookup(messagecodes) : undefined; }); } else { return {template: resolved, resolveFunc: that.options.resolveFunc}; } }; /** * Look up the first message that corresponds to a message code found in `messageCodes`. Then, resolve its * localised value. By default, supports variable substitutions using `fluid.stringTemplate`. * * @param {Object} that - The component itself. * @param {Array} messagecodes - A list of message codes to look for. * @param {Object} args - A map of variables that may potentially be used as part of the final output. * @return {String} - The final message, localised, with any variables found in `args`. */ fluid.messageResolver.resolve = function (that, messagecodes, args) { if (!messagecodes) { return "[No messagecodes provided]"; } messagecodes = fluid.makeArray(messagecodes); var looked = that.lookup(messagecodes); return looked ? looked.resolveFunc(looked.template, args) : "[Message string for key " + messagecodes[0] + " not found]"; }; // unsupported, NON-API function fluid.messageResolver.resolveOne = function (messageBase, messagecodes) { // Use this strategy to fake up the possibility of indirecting into a dynamically reloaded resource (e.g. // via relocalisation) without having to push it through a component model if (messageBase instanceof fluid.fetchResources.FetchOne) { messageBase = fluid.fetchResources.resolveFetchOne(messageBase); }; for (var i = 0; i < messagecodes.length; ++i) { var code = messagecodes[i]; var message = messageBase[code]; // Bless people who have resolved individual messages asynchronously as well. In practice this will // eventually have to give way to an approach for general asynchrony in options, or the much more // efficient "immutable application" model for models, or both if (message instanceof fluid.fetchResources.FetchOne) { message = fluid.fetchResources.resolveFetchOne(message); } if (message !== undefined) { return message; } } }; /** * Converts a data structure consisting of a mapping of keys to message strings, into a "messageLocator" function * which maps an array of message codes, to be tried in sequence until a key is found, and an array of substitution * arguments, into a substituted message string. * * @param {Object} messageBase - A body of messages to wrap in a resolver function. * @param {Function} [resolveFunc] - (optional) A "resolver" function to use instead of the default `fluid.stringTemplate`. * @return {Function} - A "messageLocator" function (see above). */ fluid.messageLocator = function (messageBase, resolveFunc) { var resolver = fluid.messageResolver({messageBase: messageBase, resolveFunc: resolveFunc}); return function (messagecodes, args) { return resolver.resolve(messagecodes, args); }; }; /** * Resolve a "message source", which is either itself a resolver, or an object representing a bundle of messages * and the associated resolution function. * * When passing a "data" object, it is expected to have a `type` element that is set to `data`, and to have a * `messages` array and a `resolveFunc` function that can be used to resolve messages. * * A "resolver" is expected to be an object with a `type` element that is set to `resolver` that exposes a `resolve` * function. * * @param {Object} messageSource - See above. * @return {Function|String|undefined} - A resolve function or a `String` representing the final resolved output. */ fluid.resolveMessageSource = function (messageSource) { if (messageSource.type === "data") { if (messageSource.url === undefined) { return fluid.messageLocator(messageSource.messages, messageSource.resolveFunc); } else { // TODO: fetch via AJAX, and convert format if necessary } } else if (messageSource.type === "resolver") { return messageSource.resolver.resolve; } };