@xndrjs/i18n 0.7.0 → 0.8.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/README.md +67 -872
- package/dist/codegen/index.d.ts +117 -51
- package/dist/codegen/index.js +1585 -93
- package/dist/codegen/index.js.map +1 -1
- package/dist/index.d.ts +100 -234
- package/dist/index.js +74 -638
- package/dist/index.js.map +1 -1
- package/dist/validation/index.d.ts +5 -0
- package/dist/validation/index.js.map +1 -1
- package/package.json +2 -2
- package/src/IcuTranslationProviderMulti.test.ts +18 -40
- package/src/IcuTranslationProviderMulti.ts +27 -37
- package/src/audit/audit-dictionaries.ts +1 -1
- package/src/audit/run-audit.test.ts +6 -7
- package/src/builder-load-registry.ts +26 -5
- package/src/builder-loaders.ts +8 -11
- package/src/builder-types.test.ts +11 -42
- package/src/builder.test.ts +82 -243
- package/src/builder.ts +8 -110
- package/src/codegen/codegen-config-schema.ts +82 -77
- package/src/codegen/config.test.ts +55 -143
- package/src/codegen/config.ts +10 -67
- package/src/codegen/dictionary-spec-contract.test.ts +28 -0
- package/src/codegen/dictionary-spec-contract.ts +138 -0
- package/src/codegen/emit/dictionary-schema-file.ts +7 -43
- package/src/codegen/emit/instance-file.test.ts +35 -52
- package/src/codegen/emit/instance-file.ts +170 -268
- package/src/codegen/emit/namespace-loaders-file.test.ts +72 -74
- package/src/codegen/emit/namespace-loaders-file.ts +147 -90
- package/src/codegen/emit/types-file.test.ts +20 -41
- package/src/codegen/emit/types-file.ts +48 -74
- package/src/codegen/generate-i18n-types.test.ts +163 -492
- package/src/codegen/generate-i18n-types.ts +7 -269
- package/src/codegen/paths.ts +0 -14
- package/src/codegen/project-locales-set-namespace.test.ts +44 -86
- package/src/codegen/read-dictionary.test.ts +27 -9
- package/src/codegen/read-dictionary.ts +18 -40
- package/src/codegen/regenerate-namespaces.ts +180 -0
- package/src/codegen/run-codegen.test.ts +230 -0
- package/src/codegen/run-codegen.ts +252 -0
- package/src/codegen/types.ts +0 -6
- package/src/codegen-config/build-config.ts +4 -23
- package/src/codegen-config/codegen-config.test.ts +10 -6
- package/src/codegen-config/index.ts +18 -3
- package/src/engine.ts +3 -27
- package/src/fetch-artifact.ts +16 -0
- package/src/i18n-handle.ts +202 -0
- package/src/index.ts +15 -34
- package/src/project-locales.ts +2 -2
- package/src/scope-multi.ts +1 -20
- package/src/scope-types.ts +14 -6
- package/src/scope.test.ts +3 -312
- package/src/serialized-state.test.ts +114 -0
- package/src/serialized-state.ts +28 -0
- package/src/setup/setup-i18n.test.ts +22 -33
- package/src/setup/setup-i18n.ts +22 -27
- package/src/types.ts +3 -3
- package/src/validation/index.ts +4 -0
- package/src/IcuTranslationProviderSingle.test.ts +0 -177
- package/src/IcuTranslationProviderSingle.ts +0 -114
- package/src/builder-multi.ts +0 -481
- package/src/codegen/emit/dictionary-file.test.ts +0 -215
- package/src/codegen/emit/dictionary-file.ts +0 -244
- package/src/deep-freeze.test.ts +0 -40
- package/src/deep-freeze.ts +0 -22
- package/src/patch-key.test.ts +0 -186
- package/src/patch-key.ts +0 -140
- package/src/scope-single.ts +0 -85
- package/src/single-builder.ts +0 -153
|
@@ -1,34 +1,15 @@
|
|
|
1
1
|
import type { CodegenConfigInput } from "../codegen/codegen-config-schema.js";
|
|
2
|
-
import { typeNamesForProject } from "./type-names.js";
|
|
3
|
-
|
|
4
|
-
export type SetupMode = "single" | "multi";
|
|
5
2
|
|
|
6
3
|
const GENERATED_DIR = "generated";
|
|
7
4
|
const TRANSLATIONS_DIR = "translations";
|
|
8
5
|
|
|
9
|
-
export function buildCodegenConfig(
|
|
10
|
-
const typeNames = typeNamesForProject(project);
|
|
11
|
-
const base = {
|
|
12
|
-
typesOutput: `${GENERATED_DIR}/i18n-types.generated.ts`,
|
|
13
|
-
dictionaryOutput: `${GENERATED_DIR}/dictionary.generated.ts`,
|
|
14
|
-
instanceOutput: `${GENERATED_DIR}/instance.generated.ts`,
|
|
15
|
-
paramsTypeName: typeNames.paramsTypeName,
|
|
16
|
-
schemaTypeName: typeNames.schemaTypeName,
|
|
17
|
-
localeTypeName: typeNames.localeTypeName,
|
|
18
|
-
factoryName: "createI18n",
|
|
19
|
-
} satisfies CodegenConfigInput;
|
|
20
|
-
|
|
21
|
-
if (mode === "single") {
|
|
22
|
-
return {
|
|
23
|
-
dictionary: `${TRANSLATIONS_DIR}/translations.json`,
|
|
24
|
-
...base,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
6
|
+
export function buildCodegenConfig(project: string): CodegenConfigInput {
|
|
28
7
|
return {
|
|
8
|
+
projectName: project,
|
|
29
9
|
namespaces: {
|
|
30
10
|
default: `${TRANSLATIONS_DIR}/default.json`,
|
|
31
11
|
},
|
|
32
|
-
|
|
12
|
+
delivery: "split-by-locale",
|
|
13
|
+
codegenPath: GENERATED_DIR,
|
|
33
14
|
};
|
|
34
15
|
}
|
|
@@ -13,17 +13,21 @@ describe("codegen-config", () => {
|
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
it("buildCodegenConfig returns a valid
|
|
17
|
-
const config = buildCodegenConfig("
|
|
18
|
-
expect(config.
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
it("buildCodegenConfig returns a valid multi-namespace input shape", () => {
|
|
17
|
+
const config = buildCodegenConfig("MyApp");
|
|
18
|
+
expect(config.namespaces).toEqual({
|
|
19
|
+
default: "translations/default.json",
|
|
20
|
+
});
|
|
21
|
+
expect(config.projectName).toBe("MyApp");
|
|
22
|
+
expect(config.codegenPath).toBe("generated");
|
|
23
|
+
expect(config).not.toHaveProperty("dictionary");
|
|
24
|
+
expect(config).not.toHaveProperty("paramsTypeName");
|
|
21
25
|
});
|
|
22
26
|
|
|
23
27
|
it("writeCodegenConfig writes formatted JSON", () => {
|
|
24
28
|
tempDir = mkdtempSync(join(tmpdir(), "xndrjs-i18n-codegen-config-"));
|
|
25
29
|
const configPath = join(tempDir, "i18n/i18n.codegen.json");
|
|
26
|
-
const config: CodegenConfigInput = buildCodegenConfig("
|
|
30
|
+
const config: CodegenConfigInput = buildCodegenConfig("Demo");
|
|
27
31
|
|
|
28
32
|
writeCodegenConfig(configPath, config);
|
|
29
33
|
|
|
@@ -2,13 +2,21 @@ export type {
|
|
|
2
2
|
CodegenConfig,
|
|
3
3
|
CodegenConfigInput,
|
|
4
4
|
DeliveryMode,
|
|
5
|
+
LoaderStrategy,
|
|
6
|
+
ResolvedCodegenPaths,
|
|
5
7
|
} from "../codegen/codegen-config-schema.js";
|
|
6
8
|
export {
|
|
7
9
|
codegenConfigKeys,
|
|
8
10
|
DELIVERY_MODES,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
LOADER_STRATEGIES,
|
|
12
|
+
GENERATED_BASENAMES,
|
|
13
|
+
DEFAULT_FACTORY_NAME,
|
|
14
|
+
DEFAULT_LOCALE_FALLBACK_CONST_NAME,
|
|
15
|
+
formatCodegenConfigIssues,
|
|
16
|
+
resolveCodegenPaths,
|
|
17
|
+
resolveArtifactsPath,
|
|
11
18
|
} from "../codegen/codegen-config-schema.js";
|
|
19
|
+
export { loadConfig, resolveNamespaces } from "../codegen/config.js";
|
|
12
20
|
|
|
13
21
|
export type { DeliveryArtifactsMap } from "../codegen/delivery-artifacts.js";
|
|
14
22
|
|
|
@@ -17,6 +25,13 @@ export {
|
|
|
17
25
|
type SupportedImportExtension,
|
|
18
26
|
} from "../codegen/constants.js";
|
|
19
27
|
|
|
20
|
-
export { buildCodegenConfig
|
|
28
|
+
export { buildCodegenConfig } from "./build-config.js";
|
|
21
29
|
export { inferProjectName, typeNamesForProject } from "./type-names.js";
|
|
22
30
|
export { writeCodegenConfig } from "./write-config.js";
|
|
31
|
+
|
|
32
|
+
export { runCodegen, type RunCodegenInput, type RunCodegenResult } from "../codegen/run-codegen.js";
|
|
33
|
+
export {
|
|
34
|
+
regenerateNamespaces,
|
|
35
|
+
type RegenerateNamespacesInput,
|
|
36
|
+
type RegenerateNamespacesResult,
|
|
37
|
+
} from "../codegen/regenerate-namespaces.js";
|
package/src/engine.ts
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
import type { IcuTranslationProviderMulti } from "./IcuTranslationProviderMulti.js";
|
|
2
|
-
import type { IcuTranslationProviderSingle } from "./IcuTranslationProviderSingle.js";
|
|
3
2
|
import type {
|
|
4
|
-
KeyDictionary,
|
|
5
3
|
LocaleFallbackMap,
|
|
6
4
|
LocaleOfMulti,
|
|
7
|
-
LocaleOfSingle,
|
|
8
5
|
MultiDictionary,
|
|
6
|
+
PartialMultiDictionary,
|
|
9
7
|
} from "./types.js";
|
|
10
8
|
import type { I18nScopeMulti, I18nScopeMultiForLocale } from "./scope-multi.js";
|
|
11
|
-
import type { I18nScopeSingle, I18nScopeSingleForLocale } from "./scope-single.js";
|
|
12
9
|
import type { MultiParams, ParamsForNamespaces, SchemaForNamespaces } from "./scope-types.js";
|
|
13
10
|
|
|
14
|
-
/** Mutable translation engine for a single-namespace dictionary. */
|
|
15
|
-
export interface I18nEngineSingle<
|
|
16
|
-
Schema extends KeyDictionary,
|
|
17
|
-
Params extends { [K in keyof Schema]: unknown },
|
|
18
|
-
RequestLocales extends string = LocaleOfSingle<Schema>,
|
|
19
|
-
> {
|
|
20
|
-
readonly __i18nEngineMode: "single";
|
|
21
|
-
getAll(): Schema;
|
|
22
|
-
toScope(): I18nScopeSingle<Schema, Params, RequestLocales>;
|
|
23
|
-
toScope<Locale extends RequestLocales>(options: {
|
|
24
|
-
locale: Locale;
|
|
25
|
-
}): I18nScopeSingleForLocale<Schema, Params, Locale>;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
11
|
/** Mutable translation engine for a multi-namespace dictionary. */
|
|
29
12
|
export interface I18nEngineMulti<
|
|
30
13
|
Schema extends MultiDictionary,
|
|
@@ -32,7 +15,8 @@ export interface I18nEngineMulti<
|
|
|
32
15
|
RequestLocales extends string = LocaleOfMulti<Schema>,
|
|
33
16
|
> {
|
|
34
17
|
readonly __i18nEngineMode: "multi";
|
|
35
|
-
|
|
18
|
+
/** Loaded namespaces only — may be empty at cold start. */
|
|
19
|
+
getAll(): PartialMultiDictionary<Schema, RequestLocales>;
|
|
36
20
|
toScope<NsList extends readonly (keyof Schema & string)[]>(options: {
|
|
37
21
|
namespaces: NsList;
|
|
38
22
|
}): I18nScopeMulti<
|
|
@@ -54,14 +38,6 @@ export interface I18nEngineMulti<
|
|
|
54
38
|
>;
|
|
55
39
|
}
|
|
56
40
|
|
|
57
|
-
/** Alias for the default single-namespace engine implementation. */
|
|
58
|
-
export type I18nEngineSingleImpl<
|
|
59
|
-
Schema extends KeyDictionary,
|
|
60
|
-
Params extends { [K in keyof Schema]: unknown },
|
|
61
|
-
RequestLocales extends string = LocaleOfSingle<Schema>,
|
|
62
|
-
Fallback extends LocaleFallbackMap | undefined = undefined,
|
|
63
|
-
> = IcuTranslationProviderSingle<Schema, Params, RequestLocales, Fallback>;
|
|
64
|
-
|
|
65
41
|
/** Alias for the default multi-namespace engine implementation. */
|
|
66
42
|
export type I18nEngineMultiImpl<
|
|
67
43
|
Schema extends MultiDictionary,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identifies a delivery JSON artifact. Codegen passes this to {@link FetchArtifact};
|
|
3
|
+
* URL / filesystem mapping is an application concern.
|
|
4
|
+
*/
|
|
5
|
+
export type DeliveryResourceId = {
|
|
6
|
+
locale: string;
|
|
7
|
+
namespace: string;
|
|
8
|
+
/** Present for `delivery: "custom"` (partition key is the area). */
|
|
9
|
+
area?: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Loads a translation JSON artifact by resource id.
|
|
14
|
+
* Must return the parsed JSON value (not a raw Response).
|
|
15
|
+
*/
|
|
16
|
+
export type FetchArtifact = (id: DeliveryResourceId) => Promise<unknown>;
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { invokeNamespaceLoader, type NamespaceLoader } from "./builder-loaders.js";
|
|
2
|
+
import type { I18nEngineMultiImpl } from "./engine.js";
|
|
3
|
+
import type {
|
|
4
|
+
LocaleFallbackMap,
|
|
5
|
+
LocaleOfMulti,
|
|
6
|
+
MultiDictionary,
|
|
7
|
+
PartialKeyDictionary,
|
|
8
|
+
PartialMultiDictionary,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
import type { I18nScopeMultiForLocale } from "./scope-multi.js";
|
|
11
|
+
import type { MultiParams, ParamsForNamespaces, SchemaForNamespaces } from "./scope-types.js";
|
|
12
|
+
|
|
13
|
+
/** Engine handle accepted by {@link createI18nHandle} (with or without localeFallback). */
|
|
14
|
+
type HandleEngine<
|
|
15
|
+
Schema extends MultiDictionary,
|
|
16
|
+
Params extends MultiParams<Schema>,
|
|
17
|
+
RequestLocales extends string,
|
|
18
|
+
> = I18nEngineMultiImpl<Schema, Params, RequestLocales, LocaleFallbackMap | undefined>;
|
|
19
|
+
|
|
20
|
+
/** Non-empty namespace list — required by {@link I18nHandle.load} / {@link I18nHandle.peek}. */
|
|
21
|
+
type NonEmptyNamespaces<NS extends readonly string[]> = NS extends readonly [] ? never : NS;
|
|
22
|
+
|
|
23
|
+
/** Maps a request locale to the delivery partition key (locale itself, or a custom area). */
|
|
24
|
+
export type PartitionForLocale<RequestLocales extends string> = (locale: RequestLocales) => string;
|
|
25
|
+
|
|
26
|
+
export type I18nHandleOptions<
|
|
27
|
+
Schema extends MultiDictionary,
|
|
28
|
+
RequestLocales extends string = LocaleOfMulti<Schema>,
|
|
29
|
+
> = {
|
|
30
|
+
namespaceLoaders?: {
|
|
31
|
+
[NS in keyof Schema & string]?: NamespaceLoader<
|
|
32
|
+
PartialKeyDictionary<Schema[NS], RequestLocales> | Schema[NS]
|
|
33
|
+
>;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Resolves the loader partition for a locale.
|
|
37
|
+
* Default: identity (`locale → locale`) for split-by-locale.
|
|
38
|
+
* Custom delivery: codegen injects `locale → LOCALE_DELIVERY_AREA[locale]`.
|
|
39
|
+
*/
|
|
40
|
+
partitionForLocale?: PartitionForLocale<RequestLocales>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type LoadNamespacesInput<
|
|
44
|
+
Schema extends MultiDictionary,
|
|
45
|
+
NsList extends readonly (keyof Schema & string)[],
|
|
46
|
+
Locale extends string,
|
|
47
|
+
> = {
|
|
48
|
+
namespaces: NonEmptyNamespaces<NsList>;
|
|
49
|
+
locale: Locale;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Locale-bound scope returned by {@link I18nHandle.load} / {@link I18nHandle.peek}. */
|
|
53
|
+
export type ScopeForLocale<
|
|
54
|
+
Schema extends MultiDictionary,
|
|
55
|
+
Params extends MultiParams<Schema>,
|
|
56
|
+
RequestLocales extends string,
|
|
57
|
+
NsList extends readonly (keyof Schema & string)[],
|
|
58
|
+
Locale extends RequestLocales,
|
|
59
|
+
> = I18nScopeMultiForLocale<
|
|
60
|
+
SchemaForNamespaces<Schema, NsList>,
|
|
61
|
+
ParamsForNamespaces<Schema, Params, NsList>,
|
|
62
|
+
RequestLocales,
|
|
63
|
+
Locale
|
|
64
|
+
>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Single runtime handle: pass `namespaces` + `locale`; partition is derived via
|
|
68
|
+
* {@link I18nHandleOptions.partitionForLocale}.
|
|
69
|
+
*/
|
|
70
|
+
export interface I18nHandle<
|
|
71
|
+
Schema extends MultiDictionary,
|
|
72
|
+
Params extends MultiParams<Schema>,
|
|
73
|
+
RequestLocales extends string = LocaleOfMulti<Schema>,
|
|
74
|
+
> {
|
|
75
|
+
load<const NsList extends readonly (keyof Schema & string)[], Locale extends RequestLocales>(
|
|
76
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>
|
|
77
|
+
): Promise<ScopeForLocale<Schema, Params, RequestLocales, NsList, Locale>>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Sync scope when every requested resource is already marked loaded (e.g. hydrate seed).
|
|
81
|
+
* Returns `null` when a normal async {@link load} is still required.
|
|
82
|
+
*/
|
|
83
|
+
peek<const NsList extends readonly (keyof Schema & string)[], Locale extends RequestLocales>(
|
|
84
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>
|
|
85
|
+
): ScopeForLocale<Schema, Params, RequestLocales, NsList, Locale> | null;
|
|
86
|
+
|
|
87
|
+
/** Dictionary (loaded namespaces) + resources for SSR→CSR hydrate. */
|
|
88
|
+
serialize(): {
|
|
89
|
+
dictionary: PartialMultiDictionary<Schema, RequestLocales>;
|
|
90
|
+
resources: readonly (readonly [string, string])[];
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class I18nHandleImpl<
|
|
95
|
+
Schema extends MultiDictionary,
|
|
96
|
+
Params extends MultiParams<Schema>,
|
|
97
|
+
RequestLocales extends string = LocaleOfMulti<Schema>,
|
|
98
|
+
> implements I18nHandle<Schema, Params, RequestLocales> {
|
|
99
|
+
private readonly partitionForLocale: PartitionForLocale<RequestLocales>;
|
|
100
|
+
|
|
101
|
+
constructor(
|
|
102
|
+
private readonly engine: HandleEngine<Schema, Params, RequestLocales>,
|
|
103
|
+
private readonly options?: I18nHandleOptions<Schema, RequestLocales>
|
|
104
|
+
) {
|
|
105
|
+
this.partitionForLocale = options?.partitionForLocale ?? ((locale) => locale);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async load<
|
|
109
|
+
const NsList extends readonly (keyof Schema & string)[],
|
|
110
|
+
Locale extends RequestLocales,
|
|
111
|
+
>(
|
|
112
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>
|
|
113
|
+
): Promise<ScopeForLocale<Schema, Params, RequestLocales, NsList, Locale>> {
|
|
114
|
+
await applyHandleLoad(this.engine, this.options, input, this.partitionForLocale);
|
|
115
|
+
return this.engine.toScope({ namespaces: input.namespaces }).forLocale(input.locale);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
peek<const NsList extends readonly (keyof Schema & string)[], Locale extends RequestLocales>(
|
|
119
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>
|
|
120
|
+
): ScopeForLocale<Schema, Params, RequestLocales, NsList, Locale> | null {
|
|
121
|
+
if (!areHandleResourcesReady(this.engine, this.options, input, this.partitionForLocale)) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
return this.engine.toScope({ namespaces: input.namespaces }).forLocale(input.locale);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
serialize() {
|
|
128
|
+
return this.engine.serialize();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function createI18nHandle<
|
|
133
|
+
Schema extends MultiDictionary,
|
|
134
|
+
Params extends MultiParams<Schema>,
|
|
135
|
+
RequestLocales extends string = LocaleOfMulti<Schema>,
|
|
136
|
+
>(
|
|
137
|
+
engine: HandleEngine<Schema, Params, RequestLocales>,
|
|
138
|
+
options?: I18nHandleOptions<Schema, RequestLocales>
|
|
139
|
+
): I18nHandle<Schema, Params, RequestLocales> {
|
|
140
|
+
return new I18nHandleImpl(engine, options);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function areHandleResourcesReady<
|
|
144
|
+
Schema extends MultiDictionary,
|
|
145
|
+
Params extends MultiParams<Schema>,
|
|
146
|
+
RequestLocales extends string,
|
|
147
|
+
NsList extends readonly (keyof Schema & string)[],
|
|
148
|
+
Locale extends RequestLocales,
|
|
149
|
+
>(
|
|
150
|
+
engine: HandleEngine<Schema, Params, RequestLocales>,
|
|
151
|
+
options: I18nHandleOptions<Schema, RequestLocales> | undefined,
|
|
152
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>,
|
|
153
|
+
partitionForLocale: PartitionForLocale<RequestLocales>
|
|
154
|
+
): boolean {
|
|
155
|
+
if (input.namespaces.length === 0) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const partition = partitionForLocale(input.locale);
|
|
159
|
+
return input.namespaces.every((namespace) => {
|
|
160
|
+
const loader = options?.namespaceLoaders?.[namespace];
|
|
161
|
+
if (loader === undefined) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
return engine.hasBuilderResourceLoaded(namespace, partition);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function applyHandleLoad<
|
|
169
|
+
Schema extends MultiDictionary,
|
|
170
|
+
Params extends MultiParams<Schema>,
|
|
171
|
+
RequestLocales extends string,
|
|
172
|
+
NsList extends readonly (keyof Schema & string)[],
|
|
173
|
+
Locale extends RequestLocales,
|
|
174
|
+
>(
|
|
175
|
+
engine: HandleEngine<Schema, Params, RequestLocales>,
|
|
176
|
+
options: I18nHandleOptions<Schema, RequestLocales> | undefined,
|
|
177
|
+
input: LoadNamespacesInput<Schema, NsList, Locale>,
|
|
178
|
+
partitionForLocale: PartitionForLocale<RequestLocales>
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
if (input.namespaces.length === 0) {
|
|
181
|
+
throw new Error("[i18n] load() requires a non-empty namespaces array.");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const partition = partitionForLocale(input.locale);
|
|
185
|
+
|
|
186
|
+
await Promise.all(
|
|
187
|
+
input.namespaces.map(async (namespace) => {
|
|
188
|
+
const loader = options?.namespaceLoaders?.[namespace];
|
|
189
|
+
if (loader === undefined) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (engine.hasBuilderResourceLoaded(namespace, partition)) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const data = await invokeNamespaceLoader(loader, partition, { locale: input.locale });
|
|
198
|
+
engine.applyLoadMergeNamespace(namespace, data);
|
|
199
|
+
engine.markBuilderResourceLoaded(namespace, partition);
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,46 +4,32 @@ export type {
|
|
|
4
4
|
LocalesForDeliveryAreaOrAll,
|
|
5
5
|
} from "./builder-types.js";
|
|
6
6
|
|
|
7
|
-
export type {
|
|
8
|
-
I18nEngineMulti,
|
|
9
|
-
I18nEngineMultiImpl,
|
|
10
|
-
I18nEngineSingle,
|
|
11
|
-
I18nEngineSingleImpl,
|
|
12
|
-
} from "./engine.js";
|
|
7
|
+
export type { I18nEngineMulti, I18nEngineMultiImpl } from "./engine.js";
|
|
13
8
|
|
|
14
9
|
export type {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
I18nBuilderMultiInitial,
|
|
19
|
-
I18nBuilderMultiOptions,
|
|
20
|
-
I18nBuilderMultiPartitioned,
|
|
21
|
-
I18nBuilderMultiReady,
|
|
22
|
-
I18nBuilderSingle,
|
|
23
|
-
I18nBuilderSingleForLocale,
|
|
24
|
-
I18nBuilderSingleOptions,
|
|
10
|
+
I18nHandle,
|
|
11
|
+
I18nHandleOptions,
|
|
12
|
+
LoadNamespacesInput,
|
|
25
13
|
NamespaceLoader,
|
|
14
|
+
PartitionForLocale,
|
|
26
15
|
PartitionedLoader,
|
|
16
|
+
ScopeForLocale,
|
|
27
17
|
} from "./builder.js";
|
|
28
|
-
export {
|
|
29
|
-
createI18nBuilder,
|
|
30
|
-
createI18nMultiBuilder,
|
|
31
|
-
createI18nSingleBuilder,
|
|
32
|
-
invokeNamespaceLoader,
|
|
33
|
-
} from "./builder.js";
|
|
18
|
+
export { createI18nHandle, invokeNamespaceLoader } from "./builder.js";
|
|
34
19
|
|
|
35
|
-
export {
|
|
20
|
+
export type { BuilderResourceEntry } from "./builder-load-registry.js";
|
|
21
|
+
export type { I18nCreateInput, I18nSerializedState } from "./serialized-state.js";
|
|
22
|
+
export { normalizeI18nCreateInput } from "./serialized-state.js";
|
|
36
23
|
|
|
37
24
|
export { IcuTranslationProviderMulti } from "./IcuTranslationProviderMulti.js";
|
|
38
25
|
|
|
39
26
|
export type { I18nScopeMulti, I18nScopeMultiForLocale } from "./scope-multi.js";
|
|
40
|
-
export type { I18nScopeSingle, I18nScopeSingleForLocale } from "./scope-single.js";
|
|
41
27
|
|
|
42
28
|
export type {
|
|
43
29
|
MultiParams,
|
|
30
|
+
NamespaceBoundTranslateFn,
|
|
44
31
|
ParamsForNamespaces,
|
|
45
32
|
SchemaForNamespaces,
|
|
46
|
-
SingleParams,
|
|
47
33
|
} from "./scope-types.js";
|
|
48
34
|
|
|
49
35
|
export type {
|
|
@@ -51,8 +37,8 @@ export type {
|
|
|
51
37
|
KeyDictionary,
|
|
52
38
|
LocaleDictionary,
|
|
53
39
|
LocaleFallbackMap,
|
|
40
|
+
LocaleOfKeys,
|
|
54
41
|
LocaleOfMulti,
|
|
55
|
-
LocaleOfSingle,
|
|
56
42
|
MissingTranslationContext,
|
|
57
43
|
MultiDictionary,
|
|
58
44
|
PartialKeyDictionary,
|
|
@@ -67,11 +53,6 @@ export {
|
|
|
67
53
|
} from "./resolve-locale.js";
|
|
68
54
|
export type { ResolvedLocaleTemplate } from "./resolve-locale.js";
|
|
69
55
|
|
|
70
|
-
export {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
projectDictionaryForDeliveryAreaCore,
|
|
74
|
-
projectDictionaryLocalesCore,
|
|
75
|
-
projectNamespaceForDeliveryAreaCore,
|
|
76
|
-
projectNamespaceLocalesCore,
|
|
77
|
-
} from "./project-locales.js";
|
|
56
|
+
export { mergeDictionaryLocalesCore, mergeNamespaceLocalesCore } from "./project-locales.js";
|
|
57
|
+
|
|
58
|
+
export type { FetchArtifact, DeliveryResourceId } from "./fetch-artifact.js";
|
package/src/project-locales.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
KeyDictionary,
|
|
4
4
|
LocaleFallbackMap,
|
|
5
5
|
LocaleOfMulti,
|
|
6
|
-
|
|
6
|
+
LocaleOfKeys,
|
|
7
7
|
MultiDictionary,
|
|
8
8
|
PartialKeyDictionary,
|
|
9
9
|
PartialMultiDictionary,
|
|
@@ -167,7 +167,7 @@ export function projectDictionaryLocalesCore<T extends MultiDictionary>(
|
|
|
167
167
|
*/
|
|
168
168
|
export function mergeNamespaceLocalesCore<
|
|
169
169
|
T extends KeyDictionary,
|
|
170
|
-
Locales extends string =
|
|
170
|
+
Locales extends string = LocaleOfKeys<T>,
|
|
171
171
|
>(existing: T, incoming: PartialKeyDictionary<T, Locales>): T {
|
|
172
172
|
const merged = structuredClone(existing);
|
|
173
173
|
|
package/src/scope-multi.ts
CHANGED
|
@@ -22,7 +22,7 @@ export interface I18nScopeMulti<
|
|
|
22
22
|
): I18nScopeMultiForLocale<Schema, Params, RequestLocales, Locale>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
/** Multi-namespace scope with a bound locale — `t(namespace, key)`
|
|
25
|
+
/** Multi-namespace scope with a bound locale — `t(namespace, key)` without a locale argument. */
|
|
26
26
|
export interface I18nScopeMultiForLocale<
|
|
27
27
|
Schema extends MultiDictionary,
|
|
28
28
|
Params,
|
|
@@ -38,14 +38,6 @@ export interface I18nScopeMultiForLocale<
|
|
|
38
38
|
key: K,
|
|
39
39
|
...params: ParamArgs<Params[NS][K]>
|
|
40
40
|
): string;
|
|
41
|
-
set<
|
|
42
|
-
const NS extends keyof Schema & keyof Params & string,
|
|
43
|
-
const K extends keyof Schema[NS] & keyof Params[NS] & string,
|
|
44
|
-
>(
|
|
45
|
-
namespace: NS,
|
|
46
|
-
key: K,
|
|
47
|
-
template: string
|
|
48
|
-
): void;
|
|
49
41
|
forLocale<Next extends RequestLocales>(
|
|
50
42
|
locale: Next
|
|
51
43
|
): I18nScopeMultiForLocale<Schema, Params, RequestLocales, Next>;
|
|
@@ -105,17 +97,6 @@ export class I18nScopeMultiForLocaleImpl<
|
|
|
105
97
|
return this.engine.getWithLocale(String(namespace), String(key), this.locale, params);
|
|
106
98
|
};
|
|
107
99
|
|
|
108
|
-
set = <
|
|
109
|
-
const NS extends keyof Schema & keyof Params & string,
|
|
110
|
-
const K extends keyof Schema[NS] & keyof Params[NS] & string,
|
|
111
|
-
>(
|
|
112
|
-
namespace: NS,
|
|
113
|
-
key: K,
|
|
114
|
-
template: string
|
|
115
|
-
): void => {
|
|
116
|
-
this.engine.patchKeyMulti(String(namespace), String(key), this.locale, template);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
100
|
forLocale = <Next extends RequestLocales>(
|
|
120
101
|
locale: Next
|
|
121
102
|
): I18nScopeMultiForLocaleImpl<Schema, Params, RequestLocales, Next, Fallback> => {
|
package/src/scope-types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MultiDictionary } from "./types.js";
|
|
2
2
|
|
|
3
3
|
/** ICU argument map for a multi-namespace schema. */
|
|
4
4
|
export type MultiParams<Schema extends MultiDictionary> = {
|
|
@@ -18,10 +18,18 @@ export type ParamsForNamespaces<
|
|
|
18
18
|
NsList extends readonly (keyof Schema & string)[],
|
|
19
19
|
> = Pick<Params, NsList[number]>;
|
|
20
20
|
|
|
21
|
-
/** ICU argument map for a single-namespace schema. */
|
|
22
|
-
export type SingleParams<Schema extends KeyDictionary> = {
|
|
23
|
-
[K in keyof Schema]: unknown;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
21
|
/** Rest args for `t()` — `never` params omit the third argument. */
|
|
27
22
|
export type ParamArgs<P> = [P] extends [never] ? [] : [params: P];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Namespace-bound `t(key, …)` — locale already bound.
|
|
26
|
+
* Call sites omit the namespace argument.
|
|
27
|
+
*/
|
|
28
|
+
export type NamespaceBoundTranslateFn<
|
|
29
|
+
Schema extends MultiDictionary,
|
|
30
|
+
Params extends MultiParams<Schema>,
|
|
31
|
+
NS extends keyof Schema & keyof Params & string,
|
|
32
|
+
> = <const K extends keyof Schema[NS] & keyof Params[NS] & string>(
|
|
33
|
+
key: K,
|
|
34
|
+
...params: ParamArgs<Params[NS][K]>
|
|
35
|
+
) => string;
|