@eouia/intl-msg 0.1.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/LICENSE +21 -0
- package/README.md +615 -0
- package/dist/browser/intl-msg.js +591 -0
- package/dist/cjs/compose.cjs +65 -0
- package/dist/cjs/loaders.cjs +73 -0
- package/dist/cjs/main.cjs +588 -0
- package/dist/esm/compose.js +60 -0
- package/dist/esm/loaders.js +66 -0
- package/dist/esm/main.js +586 -0
- package/dist/esm/package.json +3 -0
- package/package.json +67 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
if (Object.prototype.toString.call(value) !== '[object Object]') {
|
|
3
|
+
return false
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const prototype = Object.getPrototypeOf(value);
|
|
7
|
+
return prototype === null || prototype === Object.prototype
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function mergeDictionaryEntry(target = {}, source = {}) {
|
|
11
|
+
const mergedTranslations = {
|
|
12
|
+
...(isPlainObject(target.translations) ? target.translations : {}),
|
|
13
|
+
...(isPlainObject(source.translations) ? source.translations : {}),
|
|
14
|
+
};
|
|
15
|
+
const mergedFormatters = {
|
|
16
|
+
...(isPlainObject(target.formatters) ? target.formatters : {}),
|
|
17
|
+
...(isPlainObject(source.formatters) ? source.formatters : {}),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const result = {};
|
|
21
|
+
if (Object.keys(mergedTranslations).length > 0) result.translations = mergedTranslations;
|
|
22
|
+
if (Object.keys(mergedFormatters).length > 0) result.formatters = mergedFormatters;
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function mergeDictionaries(target = {}, source = {}) {
|
|
27
|
+
if (!isPlainObject(source)) return target
|
|
28
|
+
|
|
29
|
+
const result = { ...target };
|
|
30
|
+
for (const locale of Object.keys(source)) {
|
|
31
|
+
const existingEntry = isPlainObject(result[locale]) ? result[locale] : {};
|
|
32
|
+
const nextEntry = isPlainObject(source[locale]) ? source[locale] : null;
|
|
33
|
+
if (!nextEntry) continue
|
|
34
|
+
result[locale] = mergeDictionaryEntry(existingEntry, nextEntry);
|
|
35
|
+
}
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function composeDictionaries(plan = [], loader, options = {}) {
|
|
40
|
+
if (!Array.isArray(plan)) throw new TypeError('plan must be an array')
|
|
41
|
+
if (typeof loader !== 'function') throw new TypeError('loader must be a function')
|
|
42
|
+
|
|
43
|
+
const onError = options.onError ?? 'throw';
|
|
44
|
+
let merged = {};
|
|
45
|
+
|
|
46
|
+
for (const entry of plan) {
|
|
47
|
+
try {
|
|
48
|
+
const loaded = await loader(entry);
|
|
49
|
+
if (!loaded) continue
|
|
50
|
+
merged = mergeDictionaries(merged, loaded);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (onError === 'skip') continue
|
|
53
|
+
throw error
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return merged
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { composeDictionaries, composeDictionaries as default };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
function defaultResolvePath({ locale, source }) {
|
|
2
|
+
return `./dictionaries/${source}/${locale}.json`
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function defaultResolveUrl({ locale, source }) {
|
|
6
|
+
return `/dictionaries/${source}/${locale}.json`
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function createMemoryLoader(registry = {}) {
|
|
10
|
+
return async function memoryLoader({ locale, source }) {
|
|
11
|
+
return registry?.[source]?.[locale] ?? null
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function createFetchLoader({
|
|
16
|
+
resolveUrl = defaultResolveUrl,
|
|
17
|
+
fetchImpl = globalThis.fetch,
|
|
18
|
+
parse = async (response) => response.json(),
|
|
19
|
+
} = {}) {
|
|
20
|
+
if (typeof resolveUrl !== 'function') throw new TypeError('resolveUrl must be a function')
|
|
21
|
+
if (typeof fetchImpl !== 'function') throw new TypeError('fetchImpl must be a function')
|
|
22
|
+
if (typeof parse !== 'function') throw new TypeError('parse must be a function')
|
|
23
|
+
|
|
24
|
+
return async function fetchLoader(entry) {
|
|
25
|
+
const url = await resolveUrl(entry);
|
|
26
|
+
if (!url) return null
|
|
27
|
+
|
|
28
|
+
const response = await fetchImpl(url);
|
|
29
|
+
if (!response?.ok) return null
|
|
30
|
+
|
|
31
|
+
const dictionary = await parse(response);
|
|
32
|
+
return dictionary ?? null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createPathLoader({
|
|
37
|
+
resolvePath = defaultResolvePath,
|
|
38
|
+
readFile,
|
|
39
|
+
parse = JSON.parse,
|
|
40
|
+
} = {}) {
|
|
41
|
+
if (typeof resolvePath !== 'function') throw new TypeError('resolvePath must be a function')
|
|
42
|
+
if (typeof readFile !== 'function') throw new TypeError('readFile must be a function')
|
|
43
|
+
if (typeof parse !== 'function') throw new TypeError('parse must be a function')
|
|
44
|
+
|
|
45
|
+
return async function pathLoader(entry) {
|
|
46
|
+
const path = await resolvePath(entry);
|
|
47
|
+
if (!path) return null
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const fileContents = await readFile(path, 'utf8');
|
|
51
|
+
const dictionary = await parse(fileContents);
|
|
52
|
+
return dictionary ?? null
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) return null
|
|
55
|
+
throw error
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var loaders = {
|
|
61
|
+
createMemoryLoader,
|
|
62
|
+
createFetchLoader,
|
|
63
|
+
createPathLoader,
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export { createFetchLoader, createMemoryLoader, createPathLoader, loaders as default };
|