All files filter.js

93.33% Statements 42/45
84.21% Branches 32/38
100% Functions 5/5
97.62% Lines 41/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 871x 12x 12x 8x   8x 6x 9x 9x 1x     8x 8x         12x                   1x 1x       1x 4x   4x 4x 12x   12x 12x   8x   2x     4x   4x 4x 4x 4x 4x     4x 4x     4x       4x   2x       4x       12x   12x 10x     12x 4x   8x    
const trans = (translation, context) => {
  let result = translation;
  if (typeof context === 'object') {
    const matches = result.match(/(%([^%]|%%)*%)/g);
 
    if (matches) {
      matches.forEach((match) => {
        const prop = match.replace(/[%]+/g, '');
        if (!Object.prototype.hasOwnProperty.call(context, prop)) {
          return;
        }
 
        const regex = new RegExp(match, 'g');
        result = result.replace(regex, context[prop]);
      });
    }
  }
 
  return result;
};
 
// match groups for `rangePattern`
// match 0: the entire translation string
// match 1: open or closed range ] or [ i.e. exlusive or inclusive start
// match 2: value of range start
// match 3: value of range end
// match 4: open or closed range ] or [ i.e. inclusive or exlusive end
// match 5: the contents of the template (i.e. exclude type preamble)
const rangePattern = /(\[|\])(\d+|Inf), ?(\d+|Inf)(\[|\])(.+)/;
const exactPattern = /\{(\d+)\}(.*)/;
 
// a typical multiple choice pattern looks like:
// '{0} no apples|{1} one apple|]1, Inf] A lot of apples'
const transchoice = (translation, context) => {
  let result = translation;
  // split choice template on delimiter `|`
  const templates = result.split('|');
  templates.forEach((t) => {
    const choice = parseInt(context.count, 10);
    // for each choice pattern, determine the type: exact or range
    const exactMatch = t.match(exactPattern);
    if (exactMatch) {
      // we found the correct exact match
      if (parseInt(exactMatch[1], 10) === choice) {
        // eslint-disable-next-line prefer-destructuring
        result = exactMatch[2];
      }
    } else {
      const rangeMatch = t.match(rangePattern);
      // there was no pattern
      Iif (!rangeMatch) { return; }
      let start = rangeMatch[2];
      let end = rangeMatch[3];
      Eif (start !== 'Inf') start = parseInt(start, 10);
      Iif (end !== 'Inf') end = parseInt(end, 10);
 
      // starting range excludes the start value
      Eif (rangeMatch[1] === ']' && typeof start === 'number') {
        start += 1;
      }
      // ending range excludes the end value
      Iif (rangeMatch[4] === '[' && typeof end === 'number') {
        end -= 1;
      }
      // the passed in value was within the range
      if (choice >= start && (choice <= end || end === 'Inf')) {
        // eslint-disable-next-line prefer-destructuring
        result = rangeMatch[5];
      }
    }
  });
  return trans(result, context);
};
 
export default (key, context) => {
  let translation = key;
 
  if (window.translations !== undefined && window.translations[key] !== undefined) {
    translation = window.translations[key];
  }
 
  if (context && typeof context === 'object' && Object.prototype.hasOwnProperty.call(context, 'count')) {
    return transchoice(translation, context);
  }
  return trans(translation, context);
};