Skip to content

Commit 2a04da0

Browse files
committed
feat(vue-intlayer): add dynamic dictionary and loading functionality with useDictionaryDynamic and useLoadDynamic
1 parent 805ec28 commit 2a04da0

File tree

4 files changed

+78
-0
lines changed

4 files changed

+78
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export * from './installIntlayer';
22
export * from './useDictionary';
3+
export * from './useDictionaryDynamic';
34
export * from './useIntlayer';
5+
export * from './useLoadDynamic';
46
export * from './useLocale';

packages/vue-intlayer/src/client/useDictionary.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export const useDictionary = <T extends Dictionary>(
1515
const localeTarget = computed(() => locale ?? intlayer?.locale?.value);
1616

1717
/** a *stable* reactive dictionary object */
18+
// @ts-expect-error - Fix Type instantiation is excessively deep and possibly infinite
1819
const content = reactive({}) as DeepTransformContent<T['content']>;
1920

2021
/** whenever `key` or `locale` change, refresh the dictionary */
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use client';
2+
3+
import type { LocalesValues } from '@intlayer/config/client';
4+
import type {
5+
Dictionary,
6+
DictionaryKeys,
7+
LanguageContent,
8+
} from '@intlayer/core';
9+
import { computed, inject } from 'vue';
10+
import { INTLAYER_SYMBOL, IntlayerProvider } from './installIntlayer';
11+
import { useDictionary } from './useDictionary';
12+
import { useLoadDynamic } from './useLoadDynamic';
13+
14+
/**
15+
* On the server side, Hook that transform a dictionary and return the content
16+
*
17+
* If the locale is not provided, it will use the locale from the client context
18+
*/
19+
export const useDictionaryDynamic = <
20+
T extends Dictionary,
21+
K extends DictionaryKeys,
22+
>(
23+
dictionaryPromise: LanguageContent<() => Promise<T>>,
24+
key: K,
25+
locale?: LocalesValues
26+
) => {
27+
const intlayer = inject<IntlayerProvider>(INTLAYER_SYMBOL);
28+
29+
const localeTarget = computed(() => locale ?? intlayer?.locale?.value);
30+
31+
const dictionary = useLoadDynamic<T>(
32+
`${String(key)}.${localeTarget.value}`,
33+
dictionaryPromise[localeTarget.value]!()
34+
) as T;
35+
36+
return useDictionary(dictionary, localeTarget as any);
37+
};
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { reactive } from 'vue';
2+
3+
/**
4+
* A "synchronous" loader for a dynamically‐imported JSON (or anything).
5+
*
6+
* - Immediately returns a reactive object so that Vue can properly track changes.
7+
* - When the Promise resolves, it replaces the object's properties with the real data.
8+
*/
9+
export const useLoadDynamic = <T extends Record<string, any>>(
10+
key: string,
11+
promise: Promise<T>
12+
): T => {
13+
// A module‐level cache of Promises, so we only import once per key.
14+
const cache: Map<string, Promise<T>> = (useLoadDynamic as any)._cache ||
15+
((useLoadDynamic as any)._cache = new Map());
16+
17+
// Hold the "current" value as a reactive object
18+
// This starts as an empty object but Vue can track changes to it
19+
const container = reactive({} as T);
20+
21+
if (!cache.has(key)) {
22+
// Kick off the dynamic import & cache it
23+
const p = promise.then((real) => {
24+
// As soon as the import resolves, populate the container with the real data
25+
Object.assign(container, real);
26+
return real;
27+
});
28+
cache.set(key, p);
29+
} else {
30+
// If it's already in flight (or done), hook into it so that the container still updates
31+
cache.get(key)!.then((real) => {
32+
Object.assign(container, real);
33+
});
34+
}
35+
36+
// Return the reactive container directly - Vue can track all changes to it
37+
return container as T;
38+
};

0 commit comments

Comments
 (0)