@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.
@@ -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 };