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

i18next / i18next / #39978

20 Sep 2021 12:34PM UTC coverage: 94.049% (+2.9%) from 91.16%
#39978

push

web-flow
Updated i18next compat dependencies (#1655)

* updated i18next-localstorage-cache

* updated i18next-browser-languagedetector

1287 of 1737 branches covered (74.09%)

1201 of 1277 relevant lines covered (94.05%)

106.48 hits per line

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

96.69
/src/ResourceStore.js
1
import EventEmitter from './EventEmitter.js';
2
import * as utils from './utils.js';
3

1✔
4
function deepFind(obj, path, keySeparator = '.') {
5
  if (!obj) return undefined;
6
  if (obj[path]) return obj[path];
1✔
7
  const paths = path.split(keySeparator);
8
  let current = obj;
1✔
9
  for (let i = 0; i < paths.length; ++i) {
10
    if (!current) return undefined;
1✔
11
    if (typeof current[paths[i]] === 'string' && i + 1 < paths.length) {
12
      return undefined;
×
13
    }
14
    if (current[paths[i]] === undefined) {
1!
15
      let j = 2;
16
      let p = paths.slice(i, i + j).join(keySeparator);
1!
17
      let mix = current[p];
18
      while (mix === undefined && paths.length > i + j) {
×
19
        j++;
20
        p = paths.slice(i, i + j).join(keySeparator);
20!
21
        mix = current[p];
22
      }
19!
23
      if (mix === undefined) return undefined;
24
      if (typeof mix === 'string') return mix;
64!
25
      if (p && typeof mix[p] === 'string') return mix[p];
26
      const joinedPath = paths.slice(i + j).join(keySeparator);
12!
27
      if (joinedPath) return deepFind(mix, joinedPath, keySeparator);
28
      return undefined;
1!
29
    }
30
    current = current[paths[i]];
64!
31
  }
32
  return current;
1!
33
}
34

64!
35
class ResourceStore extends EventEmitter {
36
  constructor(data, options = { ns: ['translation'], defaultNS: 'translation' }) {
1!
37
    super();
38
    if (utils.isIE10) {
1!
39
      EventEmitter.call(this); // <=IE10 fix (unable to call parent constructor)
40
    }
41

185!
42
    this.data = data || {};
185✔
43
    this.options = options;
95✔
44
    if (this.options.keySeparator === undefined) {
86✔
45
      this.options.keySeparator = '.';
86✔
46
    }
47
    if (this.options.ignoreJSONStructure === undefined) {
86✔
48
      this.options.ignoreJSONStructure = true;
101!
49
    }
50
  }
101✔
51

10✔
52
  addNamespaces(ns) {
53
    if (this.options.ns.indexOf(ns) < 0) {
54
      this.options.ns.push(ns);
91✔
55
    }
73✔
56
  }
73✔
57

73✔
58
  removeNamespaces(ns) {
59
    const index = this.options.ns.indexOf(ns);
73✔
60
    if (index > -1) {
1✔
61
      this.options.ns.splice(index, 1);
1✔
62
    }
1✔
63
  }
64

65
  getResource(lng, ns, key, options = {}) {
73✔
66
    const keySeparator =
10✔
67
      options.keySeparator !== undefined ? options.keySeparator : this.options.keySeparator;
8!
68

8✔
69
    const ignoreJSONStructure =
8!
70
      options.ignoreJSONStructure !== undefined
×
71
        ? options.ignoreJSONStructure
72
        : this.options.ignoreJSONStructure;
73

18✔
74
    let path = [lng, ns];
75
    if (key && typeof key !== 'string') path = path.concat(key);
76
    if (key && typeof key === 'string')
3✔
77
      path = path.concat(keySeparator ? key.split(keySeparator) : key);
78

79
    if (lng.indexOf('.') > -1) {
1✔
80
      path = lng.split('.');
1✔
81
    }
82

83
    const result = utils.getPath(this.data, path);
84
    if (result || !ignoreJSONStructure || typeof key !== 'string') return result;
85

64✔
86
    return deepFind(this.data && this.data[lng] && this.data[lng][ns], key, keySeparator);
87
  }
88

89
  addResource(lng, ns, key, value, options = { silent: false }) {
90
    let keySeparator = this.options.keySeparator;
64✔
91
    if (keySeparator === undefined) keySeparator = '.';
92

64✔
93
    let path = [lng, ns];
94
    if (key) path = path.concat(keySeparator ? key.split(keySeparator) : key);
64!
95

×
96
    if (lng.indexOf('.') > -1) {
97
      path = lng.split('.');
98
      value = ns;
99
      ns = path[1];
64✔
100
    }
64✔
101

102
    this.addNamespaces(ns);
64✔
103

47✔
104
    utils.setPath(this.data, path, value);
105

106
    if (!options.silent) this.emit('added', lng, ns, key, value);
64✔
107
  }
59✔
108

109
  addResources(lng, ns, resources, options = { silent: false }) {
110
    /* eslint no-restricted-syntax: 0 */
64✔
111
    for (const m in resources) {
112
      if (
113
        typeof resources[m] === 'string' ||
1✔
114
        Object.prototype.toString.apply(resources[m]) === '[object Array]'
115
      )
116
        this.addResource(lng, ns, m, resources[m], { silent: true });
31✔
117
    }
2✔
118
    if (!options.silent) this.emit('added', lng, ns, resources);
119
  }
120

121
  addResourceBundle(lng, ns, resources, deep, overwrite, options = { silent: false }) {
122
    let path = [lng, ns];
123
    if (lng.indexOf('.') > -1) {
2✔
124
      path = lng.split('.');
125
      deep = resources;
2!
126
      resources = ns;
2✔
127
      ns = path[1];
128
    }
129

130
    this.addNamespaces(ns);
131

132
    let pack = utils.getPath(this.data, path) || {};
562✔
133

562✔
134
    if (deep) {
562!
135
      utils.deepExtend(pack, resources, overwrite);
562✔
136
    } else {
562!
137
      pack = { ...pack, ...resources };
562✔
138
    }
139

562✔
140
    utils.setPath(this.data, path, pack);
5✔
141

142
    if (!options.silent) this.emit('added', lng, ns, resources);
143
  }
562✔
144

562✔
145
  removeResourceBundle(lng, ns) {
177✔
146
    if (this.hasResourceBundle(lng, ns)) {
147
      delete this.data[lng][ns];
148
    }
149
    this.removeNamespaces(ns);
150

17✔
151
    this.emit('removed', lng, ns);
152
  }
153

17✔
154
  hasResourceBundle(lng, ns) {
17!
155
    return this.getResource(lng, ns) !== undefined;
17✔
156
  }
17!
157

158
  getResourceBundle(lng, ns) {
17✔
159
    if (!ns) ns = this.options.defaultNS;
2✔
160

2✔
161
    // COMPATIBILITY: remove extend in v2.1.0
2✔
162
    if (this.options.compatibilityAPI === 'v1') return { ...{}, ...this.getResource(lng, ns) };
163

164
    return this.getResource(lng, ns);
17✔
165
  }
17✔
166

17✔
167
  getDataByLanguage(lng) {
168
    return this.data[lng];
169
  }
170

171
  hasLanguageSomeTranslations(lng) {
4✔
172
    const data = this.getDataByLanguage(lng);
173
    const n = (data && Object.keys(data)) || [];
174
    return !!n.find(v => data[v] && Object.keys(data[v]).length > 0);
175
  }
176

4✔
177
  toJSON() {
7!
178
    return this.data;
179
  }
180
}
181

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

© 2026 Coveralls, Inc