[ Index ]

PHP Cross Reference of Moodle 310

title

Body

[close]

/lib/amd/src/ -> str.js (source)

   1  // This file is part of Moodle - http://moodle.org/
   2  //
   3  // Moodle is free software: you can redistribute it and/or modify
   4  // it under the terms of the GNU General Public License as published by
   5  // the Free Software Foundation, either version 3 of the License, or
   6  // (at your option) any later version.
   7  //
   8  // Moodle is distributed in the hope that it will be useful,
   9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11  // GNU General Public License for more details.
  12  //
  13  // You should have received a copy of the GNU General Public License
  14  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  15  
  16  /**
  17   * Fetch and return language strings.
  18   *
  19   * @module     core/str
  20   * @copyright  2015 Damyon Wiese <damyon@moodle.com>
  21   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22   * @since      2.9
  23   *
  24   */
  25  import $ from 'jquery';
  26  import Ajax from 'core/ajax';
  27  import LocalStorage from 'core/localstorage';
  28  
  29  // Module cache for the promises so that we don't make multiple
  30  // unnecessary requests.
  31  let promiseCache = [];
  32  
  33  /* eslint-disable no-restricted-properties */
  34  
  35  /**
  36   * Return a Promise that resolves to a string.
  37   *
  38   * If the string has previously been cached, then the Promise will be resolved immediately, otherwise it will be fetched
  39   * from the server and resolved when available.
  40   *
  41   * @method get_string
  42   * @param {string} key The language string key
  43   * @param {string} component The language string component
  44   * @param {string} param The param for variable expansion in the string.
  45   * @param {string} lang The users language - if not passed it is deduced.
  46   * @return {Promise}
  47   *
  48   * @example <caption>Fetching a string</caption>
  49   *
  50   * import {get_string as getString} from 'core/str';
  51   * get_string('cannotfindteacher', 'error')
  52   * .then(str => {
  53   *     window.console.log(str); // Cannot find teacher
  54   * })
  55   * .catch();
  56   */
  57  // eslint-disable-next-line camelcase
  58  export const get_string = (key, component, param, lang) => {
  59      return get_strings([{key, component, param, lang}])
  60          .then(results => results[0]);
  61  };
  62  
  63  /**
  64   * Make a batch request to load a set of strings.
  65   *
  66   * Any missing string will be fetched from the server.
  67   * The Promise will only be resolved once all strings are available, or an attempt has been made to fetch them.
  68   *
  69   * @method get_strings
  70   * @param {Object[]} requests List of strings to fetch
  71   * @param {string} requests.key The string identifer to fetch
  72   * @param {string} [requests.component='core'] The componet to fetch from
  73   * @param {string} [requests.lang] The language to fetch a string for. Defaults to current page language.
  74   * @param {object|string} [requests.param] The param for variable expansion in the string.
  75   * @return {Promise[]}
  76   *
  77   * @example <caption>Fetching a set of strings</caption>
  78   *
  79   * import {get_strings as getStrings} from 'core/str';
  80   * get_strings([
  81   *     {
  82   *         key: 'cannotfindteacher',
  83   *         component: 'error',
  84   *     },
  85   *     {
  86   *         key: 'yes',
  87   *         component: 'core',
  88   *     },
  89   *     {
  90   *         key: 'no',
  91   *         component: 'core',
  92   *     },
  93   * ])
  94   * .then((cannotFindTeacher, yes, no) => {
  95   *     window.console.log(cannotFindTeacher); // Cannot find teacher
  96   *     window.console.log(yes); // Yes
  97   *     window.console.log(no); // No
  98   * })
  99   * .catch();
 100   */
 101  // eslint-disable-next-line camelcase
 102  export const get_strings = (requests) => {
 103      let requestData = [];
 104      const pageLang = $('html').attr('lang').replace(/-/g, '_');
 105      // Helper function to construct the cache key.
 106      const getCacheKey = ({key, component, lang = pageLang}) => {
 107          if (!component) {
 108              component = 'core';
 109          }
 110          return `core_str/$key}/$component}/$lang}`;
 111      };
 112  
 113      const stringPromises = requests.map((request) => {
 114          const cacheKey = getCacheKey(request);
 115          const {component, key, param, lang = pageLang} = request;
 116          // Helper function to add the promise to cache.
 117          const buildReturn = (promise) => {
 118              // Make sure the promise cache contains our promise.
 119              promiseCache[cacheKey] = promise;
 120              return promise;
 121          };
 122  
 123          // Check if we can serve the string straight from M.str.
 124          if (component in M.str && key in M.str[component]) {
 125              return buildReturn(new Promise((resolve) => {
 126                  resolve(M.util.get_string(key, component, param, lang));
 127              }));
 128          }
 129  
 130          // Check if the string is in the browser's local storage.
 131          const cached = LocalStorage.get(cacheKey);
 132          if (cached) {
 133              M.str[component] = {...M.str[component], [key]: cached};
 134              return buildReturn(new Promise((resolve) => {
 135                  resolve(M.util.get_string(key, component, param, lang));
 136              }));
 137          }
 138  
 139          // Check if we've already loaded this string from the server.
 140          if (cacheKey in promiseCache) {
 141              return buildReturn(promiseCache[cacheKey]).then(() => {
 142                  return M.util.get_string(key, component, param, lang);
 143              });
 144          } else {
 145              // We're going to have to ask the server for the string so
 146              // add this string to the list of requests to be sent.
 147              return buildReturn(new Promise((resolve, reject) => {
 148                  requestData.push({
 149                      methodname: 'core_get_string',
 150                      args: {
 151                          stringid: key,
 152                          stringparams: [],
 153                          component,
 154                          lang,
 155                      },
 156                      done: (str) => {
 157                          // When we get the response from the server
 158                          // we should update M.str and the browser's
 159                          // local storage before resolving this promise.
 160                          M.str[component] = {...M.str[component], [key]: str};
 161                          LocalStorage.set(cacheKey, str);
 162                          resolve(M.util.get_string(key, component, param, lang));
 163                      },
 164                      fail: reject
 165                  });
 166              }));
 167          }
 168      });
 169  
 170      if (requestData.length) {
 171          // If we need to load any strings from the server then send
 172          // off the request.
 173          Ajax.call(requestData, true, false, false, 0, M.cfg.langrev);
 174      }
 175  
 176      // We need to use jQuery here because some calling code uses the
 177      // .done handler instead of the .then handler.
 178      return $.when.apply($, stringPromises)
 179          .then((...strings) => strings);
 180  };
 181  
 182  /**
 183   * Add a list of strings to the caches.
 184   *
 185   * This function should typically only be called from core APIs to pre-cache values.
 186   *
 187   * @method cache_strings
 188   * @protected
 189   * @param {Object[]} strings List of strings to fetch
 190   * @param {string} strings.key The string identifer to fetch
 191   * @param {string} strings.value The string value
 192   * @param {string} [strings.component='core'] The componet to fetch from
 193   * @param {string} [strings.lang] The language to fetch a string for. Defaults to current page language.
 194   */
 195  // eslint-disable-next-line camelcase
 196  export const cache_strings = (strings) => {
 197      const defaultLang = $('html').attr('lang').replace(/-/g, '_');
 198  
 199      strings.forEach(({key, component, value, lang = defaultLang}) => {
 200          const cacheKey = ['core_str', key, component, lang].join('/');
 201  
 202          // Check M.str caching.
 203          if (!(component in M.str) || !(key in M.str[component])) {
 204              if (!(component in M.str)) {
 205                  M.str[component] = {};
 206              }
 207  
 208              M.str[component][key] = value;
 209          }
 210  
 211          // Check local storage.
 212          if (!LocalStorage.get(cacheKey)) {
 213              LocalStorage.set(cacheKey, value);
 214          }
 215  
 216          // Check the promises cache.
 217          if (!(cacheKey in promiseCache)) {
 218              promiseCache[cacheKey] = $.Deferred().resolve(value).promise();
 219          }
 220      });
 221  };
 222  /* eslint-enable no-restricted-properties */


Generated: Wed Jan 22 11:59:49 2025 Cross-referenced by PHPXref 0.7.1