• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

i18next / i18next / #12521

19 Apr 2018 07:07AM UTC coverage: 87.441% (+2.0%) from 85.448%
#12521

push

jamuhl
rebuild

933 of 1067 relevant lines covered (87.44%)

38.24 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.67
/src/PluralResolver.js
1
import baseLogger from './logger.js';
2

3
// definition http://translate.sourceforge.net/wiki/l10n/pluralforms
1✔
4
/* eslint-disable */
5
let sets = [
6
  { lngs: ['ach','ak','am','arn','br','fil','gun','ln','mfe','mg','mi','oc', 'pt', 'pt-BR',
7
    'tg','ti','tr','uz','wa'], nr: [1,2], fc: 1 },
1✔
8

9
  { lngs: ['af','an','ast','az','bg','bn','ca','da','de','dev','el','en',
1✔
10
    'eo','es','et','eu','fi','fo','fur','fy','gl','gu','ha','he','hi',
11
    'hu','hy','ia','it','kn','ku','lb','mai','ml','mn','mr','nah','nap','nb',
1✔
12
    'ne','nl','nn','no','nso','pa','pap','pms','ps','pt-PT','rm','sco',
13
    'se','si','so','son','sq','sv','sw','ta','te','tk','ur','yo'], nr: [1,2], fc: 2 },
21✔
14

15
  { lngs: ['ay','bo','cgg','fa','id','ja','jbo','ka','kk','km','ko','ky','lo',
16
    'ms','sah','su','th','tt','ug','vi','wo','zh'], nr: [1], fc: 3 },
17

1✔
18
  { lngs: ['be','bs','dz','hr','ru','sr','uk'], nr: [1,2,5], fc: 4 },
19

1✔
20
  { lngs: ['ar'], nr: [0,1,2,3,11,100], fc: 5 },
21
  { lngs: ['cs','sk'], nr: [1,2,5], fc: 6 },
12✔
22
  { lngs: ['csb','pl'], nr: [1,2,5], fc: 7 },
23
  { lngs: ['cy'], nr: [1,2,3,8], fc: 8 },
24
  { lngs: ['fr'], nr: [1,2], fc: 9 },
33✔
25
  { lngs: ['ga'], nr: [1,2,3,7,11], fc: 10 },
26
  { lngs: ['gd'], nr: [1,2,3,20], fc: 11 },
27
  { lngs: ['is'], nr: [1,2], fc: 12 },
6✔
28
  { lngs: ['jv'], nr: [0,1], fc: 13 },
29
  { lngs: ['kw'], nr: [1,2,3,4], fc: 14 },
30
  { lngs: ['lt'], nr: [1,2,10], fc: 15 },
3✔
31
  { lngs: ['lv'], nr: [1,2,0], fc: 16 },
32
  { lngs: ['mk'], nr: [1,2], fc: 17 },
33
  { lngs: ['mnk'], nr: [0,1,2], fc: 18 },
23✔
34
  { lngs: ['mt'], nr: [1,2,11,20], fc: 19 },
35
  { lngs: ['or'], nr: [2,1], fc: 2 },
36
  { lngs: ['ro'], nr: [1,2,20], fc: 20 },
3✔
37
  { lngs: ['sl'], nr: [5,1,2,3], fc: 21 }
38
]
39

3✔
40
let _rulesPluralsTypes = {
41
  1: function(n) {return Number(n > 1);},
42
  2: function(n) {return Number(n != 1);},
4✔
43
  3: function(n) {return 0;},
44
  4: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
45
  5: function(n) {return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);},
6✔
46
  6: function(n) {return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);},
47
  7: function(n) {return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
48
  8: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3);},
5✔
49
  9: function(n) {return Number(n >= 2);},
50
  10: function(n) {return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;},
51
  11: function(n) {return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3);},
4✔
52
  12: function(n) {return Number(n%10!=1 || n%100==11);},
53
  13: function(n) {return Number(n !== 0);},
54
  14: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3);},
2✔
55
  15: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);},
56
  16: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2);},
57
  17: function(n) {return Number(n==1 || n%10==1 ? 0 : 1);},
2✔
58
  18: function(n) {return Number(n==0 ? 0 : n==1 ? 1 : 2);},
59
  19: function(n) {return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);},
60
  20: function(n) {return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);},
4✔
61
  21: function(n) {return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
62
};
63
/* eslint-enable */
3✔
64

65
function createRules() {
66
  const rules = {};
3✔
67
  sets.forEach((set) => {
68
    set.lngs.forEach((l) => {
69
      rules[l] = {
3✔
70
        numbers: set.nr,
71
        plurals: _rulesPluralsTypes[set.fc]
72
      };
3✔
73
    });
74
  });
75
  return rules;
4✔
76
}
77

78
class PluralResolver {
3✔
79
  constructor(languageUtils, options = {}) {
80
    this.languageUtils = languageUtils;
81
    this.options = options;
4✔
82

83
    this.logger = baseLogger.create('pluralResolver');
84

85
    this.rules = createRules();
86
  }
1✔
87

21✔
88
  addRule(lng, obj) {
21✔
89
    this.rules[lng] = obj;
462✔
90
  }
2,751✔
91

92
  getRule(code) {
93
    return this.rules[code] || this.rules[this.languageUtils.getLanguagePartFromCode(code)];
94
  }
95

96
  needsPlural(code) {
21✔
97
    const rule = this.getRule(code);
98

99
    return rule && rule.numbers.length > 1;
1✔
100
  }
1✔
101

21✔
102
  getPluralFormsOfKey(code, key) {
103
    const ret = [];
21✔
104

105
    const rule = this.getRule(code);
21✔
106

21✔
107
    if (!rule) return ret;
108

21✔
109
    rule.numbers.forEach((n) => {
110
      const suffix = this.getSuffix(code, n);
21✔
111
      ret.push(`${key}${suffix}`);
112
    });
113

1✔
114
    return ret;
×
115
  }
116

117
  getSuffix(code, count) {
1✔
118
    const rule = this.getRule(code);
163✔
119

120
    if (rule) {
121
      // if (rule.numbers.length === 1) return ''; // only singular
1✔
122

27✔
123
      const idx = rule.noAbs ? rule.plurals(count) : rule.plurals(Math.abs(count));
124
      let suffix = rule.numbers[idx];
27✔
125

126
      // special treatment for lngs only having singular and plural
127
      if (this.options.simplifyPluralSuffix && rule.numbers.length === 2 && rule.numbers[0] === 1) {
1✔
128
        if (suffix === 2) {
3✔
129
          suffix = 'plural';
130
        } else if (suffix === 1) {
3✔
131
          suffix = '';
132
        }
3✔
133
      }
134

3✔
135
      const returnSuffix = () => (
136
        this.options.prepend && suffix.toString() ? this.options.prepend + suffix.toString() : suffix.toString()
3✔
137
      );
14✔
138

14✔
139
      // COMPATIBILITY JSON
140
      // v1
141
      if (this.options.compatibilityJSON === 'v1') {
3✔
142
        if (suffix === 1) return '';
143
        if (typeof suffix === 'number') return `_plural_${suffix.toString()}`;
144
        return returnSuffix();
1✔
145
      } else if (/* v2 */ this.options.compatibilityJSON === 'v2' || (rule.numbers.length === 2 && rule.numbers[0] === 1)) {
133✔
146
        return returnSuffix();
147
      } else if (/* v3 - gettext index */ rule.numbers.length === 2 && rule.numbers[0] === 1) {
133✔
148
        return returnSuffix();
149
      }
133✔
150
      return this.options.prepend && idx.toString() ? this.options.prepend + idx.toString() : idx.toString();
151
    }
152

133✔
153
    this.logger.warn(`no plural rule found for: ${code}`);
133✔
154
    return '';
155
  }
156
}
133✔
157

54✔
158
export default PluralResolver;
30✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc