@pistonite/pure 0.24.1 → 0.25.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/package.json +3 -3
- package/src/pref/locale.ts +58 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pistonite/pure",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pure TypeScript libraries for my projects",
|
|
6
6
|
"homepage": "https://github.com/Pistonite/pure",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"denque": "2.1.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"vitest": "^3.
|
|
34
|
-
"mono-dev": "0.1.
|
|
33
|
+
"vitest": "^3.1.1",
|
|
34
|
+
"mono-dev": "0.1.1"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/pref/locale.ts
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { persist } from "../memory/persist.ts";
|
|
2
|
+
import type { Result } from "../result/index.ts";
|
|
3
|
+
import { serial } from "../sync/serial.ts";
|
|
2
4
|
|
|
3
5
|
let supportedLocales: readonly string[] = [];
|
|
4
6
|
let defaultLocale: string = "";
|
|
7
|
+
let settingLocale: string = ""; // if locale is being set (setLocale called)
|
|
8
|
+
let onBeforeChangeHook: (
|
|
9
|
+
newLocale: string,
|
|
10
|
+
) => Promise<Result<void, "cancel">> = () => {
|
|
11
|
+
return Promise.resolve({} as Result<void, "cancel">);
|
|
12
|
+
};
|
|
5
13
|
const locale = persist<string>({
|
|
6
14
|
initial: "",
|
|
7
15
|
key: "Pure.Locale",
|
|
@@ -36,11 +44,13 @@ export type LocaleOptions<TLocale extends string> = {
|
|
|
36
44
|
* These can be full locale strings like "en-US" or just languages like "en"
|
|
37
45
|
*/
|
|
38
46
|
supported: readonly TLocale[];
|
|
47
|
+
|
|
39
48
|
/**
|
|
40
49
|
* The default locale if the user's preferred locale is not supported.
|
|
41
50
|
* This must be one of the items in `supported`.
|
|
42
51
|
*/
|
|
43
52
|
default: TLocale;
|
|
53
|
+
|
|
44
54
|
/**
|
|
45
55
|
* Initial value for locale
|
|
46
56
|
*
|
|
@@ -57,6 +67,24 @@ export type LocaleOptions<TLocale extends string> = {
|
|
|
57
67
|
* Persist the locale preference to localStorage
|
|
58
68
|
*/
|
|
59
69
|
persist?: boolean;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Hook to be called by `setLocale`, but before setting the locale and thus notifying
|
|
73
|
+
* the subscribers.
|
|
74
|
+
*
|
|
75
|
+
* Internally, this is synchronized by the `serial` function, which means
|
|
76
|
+
* if another `setLocale` is called before the hook finishes, the set operation of the current
|
|
77
|
+
* call will not happen and the locale will only be set after the hook finishes in the new call.
|
|
78
|
+
*
|
|
79
|
+
* If there are race conditions in the hook, `checkCancel` should be used after any async operations,
|
|
80
|
+
* which will throw an error if another call happened.
|
|
81
|
+
*
|
|
82
|
+
* Note that this hook will not be called during initialization.
|
|
83
|
+
*/
|
|
84
|
+
onBeforeChange?: (
|
|
85
|
+
newLocale: string,
|
|
86
|
+
checkCancel: () => void,
|
|
87
|
+
) => void | Promise<void>;
|
|
60
88
|
};
|
|
61
89
|
|
|
62
90
|
/**
|
|
@@ -93,6 +121,15 @@ export type LocaleOptions<TLocale extends string> = {
|
|
|
93
121
|
export const initLocale = <TLocale extends string>(
|
|
94
122
|
options: LocaleOptions<TLocale>,
|
|
95
123
|
): void => {
|
|
124
|
+
if (options.onBeforeChange) {
|
|
125
|
+
const onBeforeChange = options.onBeforeChange;
|
|
126
|
+
onBeforeChangeHook = serial({
|
|
127
|
+
fn: (checkCancel) => async (newLocale: string) => {
|
|
128
|
+
await onBeforeChange(newLocale, checkCancel);
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
96
133
|
let _locale = "";
|
|
97
134
|
supportedLocales = options.supported;
|
|
98
135
|
if (options.initial) {
|
|
@@ -136,14 +173,29 @@ export const getDefaultLocale = (): string => {
|
|
|
136
173
|
/**
|
|
137
174
|
* Set the selected locale
|
|
138
175
|
*
|
|
139
|
-
* Returns `false` if the locale is not supported
|
|
176
|
+
* Returns `false` if the locale is not supported.
|
|
177
|
+
*
|
|
178
|
+
* onBeforeChange hook is called regardless of if the new locale
|
|
179
|
+
* is the same as the current locale. If the hook is asynchronous and
|
|
180
|
+
* another `setLocale` is called before it finishes, the locale will not be set
|
|
181
|
+
* with the current call and will be set with the new call instead.
|
|
140
182
|
*/
|
|
141
183
|
export const setLocale = (newLocale: string): boolean => {
|
|
142
184
|
const supported = convertToSupportedLocale(newLocale);
|
|
143
185
|
if (!supported) {
|
|
144
186
|
return false;
|
|
145
187
|
}
|
|
146
|
-
|
|
188
|
+
if (supported === settingLocale) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
settingLocale = supported;
|
|
192
|
+
onBeforeChangeHook(supported).then((result) => {
|
|
193
|
+
if (result.err) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
settingLocale = "";
|
|
197
|
+
locale.set(supported);
|
|
198
|
+
});
|
|
147
199
|
return true;
|
|
148
200
|
};
|
|
149
201
|
|
|
@@ -202,7 +254,10 @@ export const convertToSupportedLocaleOrDefault = (
|
|
|
202
254
|
* Add a subscriber to be notified when the locale changes.
|
|
203
255
|
* Returns a function to remove the subscriber
|
|
204
256
|
*
|
|
205
|
-
* If `notifyImmediately` is `true`, the subscriber will be called immediately with the current locale
|
|
257
|
+
* If `notifyImmediately` is `true`, the subscriber will be called immediately with the current locale.
|
|
258
|
+
* Note that it's not guaranteed that the new locale is ready when the subscriber is notified.
|
|
259
|
+
* Any async operations such as loading the language files should be done in the
|
|
260
|
+
* `onBeforeChange` hook if the subscribers need to wait for it.
|
|
206
261
|
*/
|
|
207
262
|
export const addLocaleSubscriber = (
|
|
208
263
|
fn: (locale: string) => void,
|