aboutsummaryrefslogtreecommitdiff
path: root/src/stores/locale.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/stores/locale.ts')
-rw-r--r--src/stores/locale.ts45
1 files changed, 38 insertions, 7 deletions
diff --git a/src/stores/locale.ts b/src/stores/locale.ts
index 826d717c..1b94ea96 100644
--- a/src/stores/locale.ts
+++ b/src/stores/locale.ts
@@ -25,6 +25,22 @@ interface Options {
values?: InterpolationValues;
}
+const FALLBACK_LOCALE = "en";
+
+const isPlainObject = (value: unknown): value is Record<string, unknown> =>
+ typeof value === "object" && value !== null && !Array.isArray(value);
+
+const deepMerge = (fallback: unknown, current: unknown): unknown => {
+ if (current === undefined || current === null) return fallback;
+ if (!isPlainObject(current) || !isPlainObject(fallback)) return current;
+
+ const merged: Record<string, unknown> = { ...fallback };
+ for (const [key, value] of Object.entries(current)) {
+ merged[key] = deepMerge(fallback[key], value);
+ }
+ return merged;
+};
+
const createLocale = () => {
return derived(json, ($json) => {
return (options: Options = {}) =>
@@ -32,9 +48,24 @@ const createLocale = () => {
{},
{
get(_target, key) {
- const localisation = $json(key.toString(), options.locale);
+ const keyStr = key.toString();
+ const current = $json(keyStr, options.locale);
+ const currentMissing = current === keyStr || current == null;
+
+ let resolved: unknown;
+ if (options.locale === FALLBACK_LOCALE) {
+ if (currentMissing) return undefined;
+ resolved = current;
+ } else {
+ const fallback = $json(keyStr, FALLBACK_LOCALE);
+ const fallbackMissing =
+ fallback === keyStr || fallback == null;
- if (localisation === key.toString()) return undefined;
+ if (currentMissing && fallbackMissing) return undefined;
+ if (currentMissing) resolved = fallback;
+ else if (fallbackMissing) resolved = current;
+ else resolved = deepMerge(fallback, current);
+ }
const replaceValues = (
localisation: InterpolationValues,
@@ -45,14 +76,14 @@ const createLocale = () => {
const updatedLocalisation: InterpolationValues = {};
- for (const [key, value] of Object.entries(localisation)) {
+ for (const [k, value] of Object.entries(localisation)) {
if (typeof value === "string") {
- updatedLocalisation[key] = value.replace(
+ updatedLocalisation[k] = value.replace(
/\{(\w+)\}/g,
(match, name) => (values ? values[name] : match) as string,
);
} else {
- updatedLocalisation[key] = replaceValues(
+ updatedLocalisation[k] = replaceValues(
value as InterpolationValues,
values,
) as InterpolationValue;
@@ -64,11 +95,11 @@ const createLocale = () => {
if (options.values)
return replaceValues(
- localisation as unknown as InterpolationValues,
+ resolved as unknown as InterpolationValues,
options.values,
);
- return localisation;
+ return resolved;
},
},
);