-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlocalizeAll.ts
More file actions
88 lines (81 loc) · 2.59 KB
/
Copy pathlocalizeAll.ts
File metadata and controls
88 lines (81 loc) · 2.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
import type { Any } from './Any.ts';
import type { LocalizationOptionsExcludingInterpolation } from './LocalizationOptions.ts';
import { localize } from './localize.ts';
import { isLocalizedFunctionUnit } from './LocalizedFunctionUnit.ts';
import { isLocalizedUnit } from './LocalizedUnit.ts';
// dprint-ignore
/**
Type that transforms a localization tree to preserve function signatures at leaf nodes.
This allows the resulting tree to have either strings or strongly-typed functions as its leaf nodes.
*/
type LocalizedTreeWithFunctions<T, Locales extends string> = T extends {
[K in Locales]: infer Content;
} ? Content extends (...args: Any[]) => unknown
? Content // Preserve the function signature
: string // the only other valid type
: T extends Record<string, Any> ? {
readonly [K in keyof T]: LocalizedTreeWithFunctions<T[K], Locales>;
}
: never;
/**
Localize all values in a tree structure, supporting both simple strings and parameterized functions.
This allows you to define translations like:
```ts
const translations = {
button: {
delete: {
en: (name: string) => `Delete ${name}`,
ja: (name: string) => `${name}を削除`
}
},
greeting: {
en: 'Hello',
ja: 'こんにちは'
}
}
```
And use them with full type safety:
```ts
const t = localizeAllWithFunctions(translations);
t.button.delete('Document'); // Returns "Delete Document" or "Documentを削除"
t.greeting; // Returns "Hello" or "こんにちは"
```
*/
export const localizeAll = <
Locales extends string,
InputT extends Record<string, unknown>,
>(
localizations: InputT,
options: LocalizationOptionsExcludingInterpolation<Locales> = {},
): LocalizedTreeWithFunctions<InputT, Locales> =>
{
const result: Any = {};
for (const [key, value] of Object.entries(localizations))
{
if (isLocalizedUnit(value))
{
// String-based localized unit - return the localized string
Object.defineProperty(result, key, {
get: () => localize(value, { ...options, skipInterpolation: true }),
enumerable: true,
});
}
else if (isLocalizedFunctionUnit(value))
{
// Function-based localized unit - return a function that localizes
result[key] = (...args: Any[]) =>
{
const localeFn = value[options.locale || 'en'] as (
...args: Any[]
) => string;
return localeFn(...args);
};
}
else if (typeof value === 'object' && value !== null)
{
// Nested object - recurse
result[key] = localizeAll(value as Record<string, unknown>, options);
}
}
return result;
};