adapt-authoring-lang 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/check.js +1 -1
- package/index.js +1 -0
- package/lib/LangModule.js +8 -34
- package/lib/utils/storeStrings.js +13 -0
- package/lib/utils/translate.js +43 -0
- package/lib/utils/translateError.js +17 -0
- package/lib/utils.js +3 -0
- package/package.json +2 -2
- package/tests/utils-storeStrings.spec.js +49 -0
- package/tests/utils-translate.spec.js +114 -0
- package/tests/utils-translateError.spec.js +63 -0
package/bin/check.js
CHANGED
|
@@ -74,7 +74,7 @@ async function getUsedStrings (translatedStrings) {
|
|
|
74
74
|
usedStrings[key].add(f.replace(root, '').split('/')[1]) // only add module name for errors
|
|
75
75
|
})
|
|
76
76
|
}))
|
|
77
|
-
const sourceFiles = await glob('adapt-authoring-*/**/*.@(js|hbs)', { cwd: root, absolute: true, ignore: '**/node_modules/**' })
|
|
77
|
+
const sourceFiles = await glob('adapt-authoring-*/**/*.@(js|hbs)', { cwd: root, absolute: true, ignore: ['**/node_modules/**', '**/*.spec.js', '**/tests/**'] })
|
|
78
78
|
|
|
79
79
|
await Promise.all(sourceFiles.map(async f => {
|
|
80
80
|
const contents = (await fs.readFile(f)).toString()
|
package/index.js
CHANGED
package/lib/LangModule.js
CHANGED
|
@@ -2,6 +2,7 @@ import { AbstractModule } from 'adapt-authoring-core'
|
|
|
2
2
|
import fs from 'fs/promises'
|
|
3
3
|
import { glob } from 'glob'
|
|
4
4
|
import path from 'path'
|
|
5
|
+
import { storeStrings, translate, translateError } from './utils.js'
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Module to handle localisation of language strings
|
|
@@ -51,18 +52,18 @@ class LangModule extends AbstractModule {
|
|
|
51
52
|
await Promise.all(files.map(async f => {
|
|
52
53
|
try {
|
|
53
54
|
const contents = JSON.parse((await fs.readFile(f)).toString())
|
|
54
|
-
Object.entries(contents).forEach(([k, v]) => this.
|
|
55
|
+
Object.entries(contents).forEach(([k, v]) => storeStrings(this.phrases, `${path.basename(f).replace('.json', '')}.${k}`, v))
|
|
55
56
|
} catch (e) {
|
|
56
57
|
this.log('error', e.message, f)
|
|
57
58
|
}
|
|
58
59
|
}))
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/**
|
|
63
|
+
* @deprecated Use storeStrings() from 'adapt-authoring-lang' instead
|
|
64
|
+
*/
|
|
61
65
|
storeStrings (key, value) {
|
|
62
|
-
|
|
63
|
-
const lang = key.slice(0, i)
|
|
64
|
-
if (!this.phrases[lang]) this.phrases[lang] = {}
|
|
65
|
-
this.phrases[lang][key.slice(i + 1)] = value
|
|
66
|
+
storeStrings(this.phrases, key, value)
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
/**
|
|
@@ -146,34 +147,7 @@ class LangModule extends AbstractModule {
|
|
|
146
147
|
* @return {String}
|
|
147
148
|
*/
|
|
148
149
|
translate (lang, key, data) {
|
|
149
|
-
|
|
150
|
-
lang = this.getConfig('defaultLang')
|
|
151
|
-
}
|
|
152
|
-
if (key.constructor.name.endsWith('Error')) {
|
|
153
|
-
return this.translateError(lang, key)
|
|
154
|
-
}
|
|
155
|
-
const s = this.phrases[lang]?.[key]
|
|
156
|
-
if (!s) {
|
|
157
|
-
this.log('warn', `missing key '${lang}.${key}'`)
|
|
158
|
-
return key
|
|
159
|
-
}
|
|
160
|
-
if (!data) {
|
|
161
|
-
return s
|
|
162
|
-
}
|
|
163
|
-
return Object.entries(data).reduce((s, [k, v]) => {
|
|
164
|
-
// map any errors specified in data
|
|
165
|
-
v = Array.isArray(v) ? v.map(v2 => this.translateError(lang, v2)) : this.translateError(lang, v)
|
|
166
|
-
s = s.replaceAll(`\${${k}}`, v)
|
|
167
|
-
// handle special-case array replacements
|
|
168
|
-
if (Array.isArray(v)) {
|
|
169
|
-
const matches = [...s.matchAll(new RegExp(String.raw`\$map{${k}:(.+)}`, 'g'))]
|
|
170
|
-
matches.forEach(([replace, data]) => {
|
|
171
|
-
const [attrs, delim] = data.split(':')
|
|
172
|
-
s = s.replace(replace, v.map(val => attrs.split(',').map(a => Object.prototype.hasOwnProperty.call(val, a) ? val[a] : a)).join(delim))
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
return s
|
|
176
|
-
}, s)
|
|
150
|
+
return translate(this.phrases, this.getConfig('defaultLang'), msg => this.log('warn', msg), lang, key, data)
|
|
177
151
|
}
|
|
178
152
|
|
|
179
153
|
/**
|
|
@@ -183,7 +157,7 @@ class LangModule extends AbstractModule {
|
|
|
183
157
|
* @returns The translated error (if passed error is not an instance of AdaptError, the original value will be returned)
|
|
184
158
|
*/
|
|
185
159
|
translateError (lang, error) {
|
|
186
|
-
return
|
|
160
|
+
return translateError(this.phrases, this.getConfig('defaultLang'), msg => this.log('warn', msg), lang, error)
|
|
187
161
|
}
|
|
188
162
|
}
|
|
189
163
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a dotted language key and stores the value in the phrases dictionary
|
|
3
|
+
* @param {Object} phrases The phrases dictionary to store into
|
|
4
|
+
* @param {String} key Key in the format 'lang.namespace.key'
|
|
5
|
+
* @param {String} value The string value to store
|
|
6
|
+
* @memberof lang
|
|
7
|
+
*/
|
|
8
|
+
export function storeStrings (phrases, key, value) {
|
|
9
|
+
const i = key.indexOf('.')
|
|
10
|
+
const lang = key.slice(0, i)
|
|
11
|
+
if (!phrases[lang]) phrases[lang] = {}
|
|
12
|
+
phrases[lang][key.slice(i + 1)] = value
|
|
13
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { translateError } from './translateError.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns translated language string
|
|
5
|
+
* @param {Object} phrases The phrases dictionary
|
|
6
|
+
* @param {String} defaultLang Default language to use when lang is not a string
|
|
7
|
+
* @param {Function} logWarn Logging function for missing keys (receives message string)
|
|
8
|
+
* @param {String} lang The target language (if undefined, the default language will be used)
|
|
9
|
+
* @param {String|AdaptError} key The unique string key (if an AdaptError is passed, the error data will be used for the data param)
|
|
10
|
+
* @param {Object} data Dynamic data to be inserted into translated string
|
|
11
|
+
* @return {String}
|
|
12
|
+
* @memberof lang
|
|
13
|
+
*/
|
|
14
|
+
export function translate (phrases, defaultLang, logWarn, lang, key, data) {
|
|
15
|
+
if (typeof lang !== 'string') {
|
|
16
|
+
lang = defaultLang
|
|
17
|
+
}
|
|
18
|
+
if (key.constructor.name.endsWith('Error')) {
|
|
19
|
+
return translateError(phrases, defaultLang, logWarn, lang, key)
|
|
20
|
+
}
|
|
21
|
+
const s = phrases[lang]?.[key]
|
|
22
|
+
if (!s) {
|
|
23
|
+
logWarn(`missing key '${lang}.${key}'`)
|
|
24
|
+
return key
|
|
25
|
+
}
|
|
26
|
+
if (!data) {
|
|
27
|
+
return s
|
|
28
|
+
}
|
|
29
|
+
return Object.entries(data).reduce((s, [k, v]) => {
|
|
30
|
+
// map any errors specified in data
|
|
31
|
+
v = Array.isArray(v) ? v.map(v2 => translateError(phrases, defaultLang, logWarn, lang, v2)) : translateError(phrases, defaultLang, logWarn, lang, v)
|
|
32
|
+
s = s.replaceAll(`\${${k}}`, v)
|
|
33
|
+
// handle special-case array replacements
|
|
34
|
+
if (Array.isArray(v)) {
|
|
35
|
+
const matches = [...s.matchAll(new RegExp(String.raw`\$map{${k}:(.+)}`, 'g'))]
|
|
36
|
+
matches.forEach(([replace, data]) => {
|
|
37
|
+
const [attrs, delim] = data.split(':')
|
|
38
|
+
s = s.replace(replace, v.map(val => attrs.split(',').map(a => Object.prototype.hasOwnProperty.call(val, a) ? val[a] : a)).join(delim))
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
return s
|
|
42
|
+
}, s)
|
|
43
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { translate } from './translate.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Translates an AdaptError
|
|
5
|
+
* @param {Object} phrases The phrases dictionary
|
|
6
|
+
* @param {String} defaultLang Default language to use when lang is not a string
|
|
7
|
+
* @param {Function} logWarn Logging function for missing keys (receives message string)
|
|
8
|
+
* @param {String} lang The target language
|
|
9
|
+
* @param {AdaptError} error Error to translate
|
|
10
|
+
* @returns The translated error (if passed error is not an instance of AdaptError, the original value will be returned)
|
|
11
|
+
* @memberof lang
|
|
12
|
+
*/
|
|
13
|
+
export function translateError (phrases, defaultLang, logWarn, lang, error) {
|
|
14
|
+
return error?.constructor.name.endsWith('Error')
|
|
15
|
+
? translate(phrases, defaultLang, logWarn, lang, `error.${error.code}`, error.data ?? error)
|
|
16
|
+
: error
|
|
17
|
+
}
|
package/lib/utils.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "adapt-authoring-lang",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Localisation for the Adapt authoring tool",
|
|
5
5
|
"homepage": "https://github.com/taylortom/adapt-authoring-lang",
|
|
6
6
|
"license": "GPL-3.0",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"repository": "github:adapt-security/adapt-authoring-lang",
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"adapt-authoring-core": "^
|
|
17
|
+
"adapt-authoring-core": "^2.0.0",
|
|
18
18
|
"glob": "^13.0.0"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, it, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert/strict'
|
|
3
|
+
import { storeStrings } from '../lib/utils/storeStrings.js'
|
|
4
|
+
|
|
5
|
+
describe('storeStrings()', () => {
|
|
6
|
+
let phrases
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
phrases = {}
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('should store string with language prefix', () => {
|
|
13
|
+
storeStrings(phrases, 'en.app.test', 'Test Value')
|
|
14
|
+
assert.equal(phrases.en['app.test'], 'Test Value')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should create language key if not exists', () => {
|
|
18
|
+
storeStrings(phrases, 'fr.app.hello', 'Bonjour')
|
|
19
|
+
assert.ok(phrases.fr)
|
|
20
|
+
assert.equal(phrases.fr['app.hello'], 'Bonjour')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should store multiple strings for same language', () => {
|
|
24
|
+
storeStrings(phrases, 'en.app.test1', 'Value 1')
|
|
25
|
+
storeStrings(phrases, 'en.app.test2', 'Value 2')
|
|
26
|
+
assert.equal(phrases.en['app.test1'], 'Value 1')
|
|
27
|
+
assert.equal(phrases.en['app.test2'], 'Value 2')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('should handle nested keys with dots', () => {
|
|
31
|
+
storeStrings(phrases, 'en.app.nested.key', 'Nested Value')
|
|
32
|
+
assert.equal(phrases.en['app.nested.key'], 'Nested Value')
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should overwrite existing key', () => {
|
|
36
|
+
storeStrings(phrases, 'en.app.test', 'Original')
|
|
37
|
+
storeStrings(phrases, 'en.app.test', 'Updated')
|
|
38
|
+
assert.equal(phrases.en['app.test'], 'Updated')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should store strings for multiple languages', () => {
|
|
42
|
+
storeStrings(phrases, 'en.app.hello', 'Hello')
|
|
43
|
+
storeStrings(phrases, 'fr.app.hello', 'Bonjour')
|
|
44
|
+
storeStrings(phrases, 'de.app.hello', 'Hallo')
|
|
45
|
+
assert.equal(phrases.en['app.hello'], 'Hello')
|
|
46
|
+
assert.equal(phrases.fr['app.hello'], 'Bonjour')
|
|
47
|
+
assert.equal(phrases.de['app.hello'], 'Hallo')
|
|
48
|
+
})
|
|
49
|
+
})
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string */
|
|
2
|
+
import { describe, it, beforeEach, mock } from 'node:test'
|
|
3
|
+
import assert from 'node:assert/strict'
|
|
4
|
+
import { translate } from '../lib/utils/translate.js'
|
|
5
|
+
|
|
6
|
+
describe('translate()', () => {
|
|
7
|
+
let phrases
|
|
8
|
+
const defaultLang = 'en'
|
|
9
|
+
let logWarn
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
logWarn = mock.fn()
|
|
13
|
+
phrases = {
|
|
14
|
+
en: {
|
|
15
|
+
'app.simple': 'Simple text',
|
|
16
|
+
'app.withdata': 'Hello ${name}',
|
|
17
|
+
'app.multiple': 'User ${user} has ${count} items',
|
|
18
|
+
'app.array': 'Items: ${items}',
|
|
19
|
+
'app.arraymap': 'Names: $map{users:name:, }',
|
|
20
|
+
'error.TEST_ERROR': 'Test error message'
|
|
21
|
+
},
|
|
22
|
+
fr: {
|
|
23
|
+
'app.simple': 'Texte simple',
|
|
24
|
+
'app.withdata': 'Bonjour ${name}'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should return simple translated string', () => {
|
|
30
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.simple'), 'Simple text')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should return string in specified language', () => {
|
|
34
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'fr', 'app.simple'), 'Texte simple')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should return key if translation not found', () => {
|
|
38
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.missing'), 'app.missing')
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('should call logWarn when key is missing', () => {
|
|
42
|
+
translate(phrases, defaultLang, logWarn, 'en', 'app.missing')
|
|
43
|
+
assert.equal(logWarn.mock.callCount(), 1)
|
|
44
|
+
assert.ok(logWarn.mock.calls[0].arguments[0].includes('app.missing'))
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should use default language when lang is not a string', () => {
|
|
48
|
+
assert.equal(translate(phrases, defaultLang, logWarn, null, 'app.simple'), 'Simple text')
|
|
49
|
+
assert.equal(translate(phrases, defaultLang, logWarn, undefined, 'app.simple'), 'Simple text')
|
|
50
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 42, 'app.simple'), 'Simple text')
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('should replace single placeholder with data', () => {
|
|
54
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.withdata', { name: 'John' }), 'Hello John')
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it('should replace multiple placeholders', () => {
|
|
58
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.multiple', { user: 'Alice', count: 5 }), 'User Alice has 5 items')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('should leave unreplaced placeholders when data is missing', () => {
|
|
62
|
+
const result = translate(phrases, defaultLang, logWarn, 'en', 'app.withdata', {})
|
|
63
|
+
assert.equal(result, 'Hello ${name}')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should return string without substitution when no data provided', () => {
|
|
67
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.simple'), 'Simple text')
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should handle $map syntax with arrays of objects', () => {
|
|
71
|
+
const users = [
|
|
72
|
+
{ name: 'Alice', age: 30 },
|
|
73
|
+
{ name: 'Bob', age: 25 }
|
|
74
|
+
]
|
|
75
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.arraymap', { users }), 'Names: Alice, Bob')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should translate error objects', () => {
|
|
79
|
+
const mockError = {
|
|
80
|
+
constructor: { name: 'AdaptError' },
|
|
81
|
+
code: 'TEST_ERROR',
|
|
82
|
+
data: {}
|
|
83
|
+
}
|
|
84
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', mockError), 'Test error message')
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
it('should translate error values in data', () => {
|
|
88
|
+
phrases.en['app.status'] = 'Status: ${err}'
|
|
89
|
+
phrases.en['error.INNER'] = 'inner error'
|
|
90
|
+
const innerError = {
|
|
91
|
+
constructor: { name: 'AdaptError' },
|
|
92
|
+
code: 'INNER',
|
|
93
|
+
data: {}
|
|
94
|
+
}
|
|
95
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'en', 'app.status', { err: innerError }), 'Status: inner error')
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('should translate error values inside arrays in data', () => {
|
|
99
|
+
phrases.en['app.errors'] = 'Errors: ${errs}'
|
|
100
|
+
phrases.en['error.E1'] = 'err one'
|
|
101
|
+
phrases.en['error.E2'] = 'err two'
|
|
102
|
+
const errs = [
|
|
103
|
+
{ constructor: { name: 'AdaptError' }, code: 'E1', data: {} },
|
|
104
|
+
{ constructor: { name: 'AdaptError' }, code: 'E2', data: {} }
|
|
105
|
+
]
|
|
106
|
+
const result = translate(phrases, defaultLang, logWarn, 'en', 'app.errors', { errs })
|
|
107
|
+
assert.ok(result.includes('err one'))
|
|
108
|
+
assert.ok(result.includes('err two'))
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('should return key when language does not exist', () => {
|
|
112
|
+
assert.equal(translate(phrases, defaultLang, logWarn, 'de', 'app.simple'), 'app.simple')
|
|
113
|
+
})
|
|
114
|
+
})
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string */
|
|
2
|
+
import { describe, it, mock } from 'node:test'
|
|
3
|
+
import assert from 'node:assert/strict'
|
|
4
|
+
import { translateError } from '../lib/utils/translateError.js'
|
|
5
|
+
|
|
6
|
+
describe('translateError()', () => {
|
|
7
|
+
const phrases = {
|
|
8
|
+
en: {
|
|
9
|
+
'error.TEST_CODE': 'Error: ${message}',
|
|
10
|
+
'error.SIMPLE': 'Simple error'
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
const defaultLang = 'en'
|
|
14
|
+
const logWarn = mock.fn()
|
|
15
|
+
|
|
16
|
+
it('should translate error with code', () => {
|
|
17
|
+
const error = {
|
|
18
|
+
constructor: { name: 'AdaptError' },
|
|
19
|
+
code: 'SIMPLE',
|
|
20
|
+
data: {}
|
|
21
|
+
}
|
|
22
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', error), 'Simple error')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should translate error with data', () => {
|
|
26
|
+
const error = {
|
|
27
|
+
constructor: { name: 'TestError' },
|
|
28
|
+
code: 'TEST_CODE',
|
|
29
|
+
data: { message: 'Something went wrong' }
|
|
30
|
+
}
|
|
31
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', error), 'Error: Something went wrong')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should return non-error values unchanged', () => {
|
|
35
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', 'just a string'), 'just a string')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('should return null unchanged', () => {
|
|
39
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', null), null)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should return undefined unchanged', () => {
|
|
43
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', undefined), undefined)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('should return number values unchanged', () => {
|
|
47
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', 42), 42)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should use error object itself as data when data is missing', () => {
|
|
51
|
+
phrases.en['error.NO_DATA'] = 'Code: ${code}'
|
|
52
|
+
const error = {
|
|
53
|
+
constructor: { name: 'AdaptError' },
|
|
54
|
+
code: 'NO_DATA'
|
|
55
|
+
}
|
|
56
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', error), 'Code: NO_DATA')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('should handle objects without constructor gracefully', () => {
|
|
60
|
+
const obj = {}
|
|
61
|
+
assert.equal(translateError(phrases, defaultLang, logWarn, 'en', obj), obj)
|
|
62
|
+
})
|
|
63
|
+
})
|