@gabrielbourget/i18n-foundation 0.1.0 → 0.1.1
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/CHANGELOG.md +14 -0
- package/README.md +15 -9
- package/dist/assets/index.d.ts +23 -4
- package/dist/assets/index.d.ts.map +1 -1
- package/dist/assets/index.js +33 -4
- package/dist/verifier/verifyI18nSource.d.ts +3 -1
- package/dist/verifier/verifyI18nSource.d.ts.map +1 -1
- package/dist/verifier/verifyI18nSource.js +14 -8
- package/package.json +17 -11
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.1 - 2026-06-15
|
|
4
|
+
|
|
5
|
+
- Added namespace source-root resolver helpers for mixed app-owned and foundation-owned locale roots.
|
|
6
|
+
- Extended generated asset helpers and source verification to accept namespace source-root resolvers while preserving the existing single-root API.
|
|
7
|
+
- Added package publish guardrails with `prepack`, `prepublishOnly`, `verify`, and test typechecking.
|
|
8
|
+
- Added package CI and a Node version pin.
|
|
9
|
+
- Corrected README examples to use the public subpath imports.
|
|
10
|
+
|
|
11
|
+
## 0.1.0 - 2026-06-14
|
|
12
|
+
|
|
13
|
+
- Initial private i18n foundation package release.
|
|
14
|
+
- Extracted shared i18next runtime helpers, env parsing, manifest helpers, pseudolocalization, asset helpers, verifier helpers, and foundation-owned common locale JSON.
|
package/README.md
CHANGED
|
@@ -93,12 +93,9 @@ namespace.
|
|
|
93
93
|
The app facade owns all app-specific registry values:
|
|
94
94
|
|
|
95
95
|
```ts
|
|
96
|
-
import {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
createI18nProvider,
|
|
100
|
-
validateDevManifest,
|
|
101
|
-
} from "@gabrielbourget/i18n-foundation"
|
|
96
|
+
import { createI18nProvider } from "@gabrielbourget/i18n-foundation/core/client"
|
|
97
|
+
import { buildClientRuntimeConfig, createI18nClientEnvReader } from "@gabrielbourget/i18n-foundation/env/client"
|
|
98
|
+
import { validateDevManifest } from "@gabrielbourget/i18n-foundation/manifest"
|
|
102
99
|
|
|
103
100
|
const registry = {
|
|
104
101
|
defaultLocale: DEFAULT_LOCALE,
|
|
@@ -131,7 +128,15 @@ Facade scripts should pass explicit app paths and registries into foundation
|
|
|
131
128
|
helpers:
|
|
132
129
|
|
|
133
130
|
```ts
|
|
134
|
-
import {
|
|
131
|
+
import { FOUNDATION_COMMON_NAMESPACES } from "@gabrielbourget/i18n-foundation/common"
|
|
132
|
+
import { createI18nNamespaceSourceRootResolver, generateI18nAssets } from "@gabrielbourget/i18n-foundation/assets"
|
|
133
|
+
import { buildI18nManifest } from "@gabrielbourget/i18n-foundation/manifest"
|
|
134
|
+
import { verifyI18nSource } from "@gabrielbourget/i18n-foundation/verifier"
|
|
135
|
+
|
|
136
|
+
const resolveNamespaceSourceRoot = createI18nNamespaceSourceRootResolver({
|
|
137
|
+
defaultLocalesRoot: appLocalesRoot,
|
|
138
|
+
overrides: [{ localesRoot: foundationLocalesRoot, namespaces: FOUNDATION_COMMON_NAMESPACES }],
|
|
139
|
+
})
|
|
135
140
|
|
|
136
141
|
const manifest = buildI18nManifest({
|
|
137
142
|
defaultLocale: DEFAULT_LOCALE,
|
|
@@ -141,13 +146,14 @@ const manifest = buildI18nManifest({
|
|
|
141
146
|
})
|
|
142
147
|
|
|
143
148
|
generateI18nAssets({
|
|
144
|
-
localesRoot,
|
|
145
149
|
outputRoot,
|
|
146
150
|
manifest,
|
|
151
|
+
resolveNamespaceSourceRoot,
|
|
147
152
|
})
|
|
148
153
|
|
|
149
154
|
await verifyI18nSource({
|
|
150
|
-
localesRoot,
|
|
155
|
+
localesRoot: appLocalesRoot,
|
|
156
|
+
resolveNamespaceSourceRoot,
|
|
151
157
|
availableNamespaces: AVAILABLE_NAMESPACES,
|
|
152
158
|
declaredLocales: DECLARED_LOCALES,
|
|
153
159
|
defaultLocale: DEFAULT_LOCALE,
|
package/dist/assets/index.d.ts
CHANGED
|
@@ -5,8 +5,24 @@ export type TGeneratedI18nAsset<Locale extends string = string, Namespace extend
|
|
|
5
5
|
sourcePath: string;
|
|
6
6
|
outputPath: string;
|
|
7
7
|
};
|
|
8
|
-
export type
|
|
8
|
+
export type TI18nNamespaceSourceRootResolver<Namespace extends string = string> = (namespace: Namespace) => string;
|
|
9
|
+
export type TI18nNamespaceSourceRootOverride<Namespace extends string = string> = {
|
|
9
10
|
localesRoot: string;
|
|
11
|
+
namespaces: readonly Namespace[];
|
|
12
|
+
};
|
|
13
|
+
export type TCreateI18nNamespaceSourceRootResolverArgs<Namespace extends string = string> = {
|
|
14
|
+
defaultLocalesRoot: string;
|
|
15
|
+
overrides?: readonly TI18nNamespaceSourceRootOverride<Namespace>[] | undefined;
|
|
16
|
+
};
|
|
17
|
+
export type TResolveI18nNamespaceSourcePathArgs<Locale extends string = string, Namespace extends string = string> = {
|
|
18
|
+
locale: Locale;
|
|
19
|
+
namespace: Namespace;
|
|
20
|
+
localesRoot?: string | undefined;
|
|
21
|
+
resolveNamespaceSourceRoot?: TI18nNamespaceSourceRootResolver<Namespace> | undefined;
|
|
22
|
+
};
|
|
23
|
+
export type TGenerateI18nAssetsArgs<Locale extends string, Namespace extends string> = {
|
|
24
|
+
localesRoot?: string | undefined;
|
|
25
|
+
resolveNamespaceSourceRoot?: TI18nNamespaceSourceRootResolver<Namespace> | undefined;
|
|
10
26
|
outputRoot: string;
|
|
11
27
|
manifest: TI18nManifest<Locale, Namespace>;
|
|
12
28
|
cleanOutputRoot?: boolean | undefined;
|
|
@@ -17,7 +33,8 @@ export type TGenerateI18nAssetsResult<Locale extends string, Namespace extends s
|
|
|
17
33
|
assets: readonly TGeneratedI18nAsset<Locale, Namespace>[];
|
|
18
34
|
};
|
|
19
35
|
export type TValidateGeneratedI18nAssetsArgs<Locale extends string, Namespace extends string> = {
|
|
20
|
-
localesRoot
|
|
36
|
+
localesRoot?: string | undefined;
|
|
37
|
+
resolveNamespaceSourceRoot?: TI18nNamespaceSourceRootResolver<Namespace> | undefined;
|
|
21
38
|
generatedRoot: string;
|
|
22
39
|
manifest: TI18nManifest<Locale, Namespace>;
|
|
23
40
|
};
|
|
@@ -30,6 +47,8 @@ export declare const listJSONFileNames: (directoryPath: string) => string[];
|
|
|
30
47
|
export declare const assertEqualArrays: (label: string, expected: readonly string[], actual: readonly string[]) => void;
|
|
31
48
|
export declare const ensureDirectory: (directoryPath: string) => void;
|
|
32
49
|
export declare const removeDirectoryIfExists: (directoryPath: string) => void;
|
|
33
|
-
export declare const
|
|
34
|
-
export declare const
|
|
50
|
+
export declare const createI18nNamespaceSourceRootResolver: <Namespace extends string>({ defaultLocalesRoot, overrides, }: TCreateI18nNamespaceSourceRootResolverArgs<Namespace>) => TI18nNamespaceSourceRootResolver<Namespace>;
|
|
51
|
+
export declare const resolveI18nNamespaceSourcePath: <Locale extends string, Namespace extends string>({ locale, namespace, localesRoot, resolveNamespaceSourceRoot, }: TResolveI18nNamespaceSourcePathArgs<Locale, Namespace>) => string;
|
|
52
|
+
export declare const generateI18nAssets: <Locale extends string, Namespace extends string>({ localesRoot, resolveNamespaceSourceRoot, outputRoot, manifest, cleanOutputRoot, }: TGenerateI18nAssetsArgs<Locale, Namespace>) => TGenerateI18nAssetsResult<Locale, Namespace>;
|
|
53
|
+
export declare const validateGeneratedI18nAssets: <Locale extends string, Namespace extends string>({ localesRoot, resolveNamespaceSourceRoot, generatedRoot, manifest, }: TValidateGeneratedI18nAssetsArgs<Locale, Namespace>) => void;
|
|
35
54
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IACnG,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,IAAI;IACrF,WAAW,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/assets/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEzD,MAAM,MAAM,mBAAmB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IACnG,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,gCAAgC,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,SAAS,KAAK,MAAM,CAAA;AAElH,MAAM,MAAM,gCAAgC,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IAChF,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,SAAS,SAAS,EAAE,CAAA;CACjC,CAAA;AAED,MAAM,MAAM,0CAA0C,CAAC,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IAC1F,kBAAkB,EAAE,MAAM,CAAA;IAC1B,SAAS,CAAC,EAAE,SAAS,gCAAgC,CAAC,SAAS,CAAC,EAAE,GAAG,SAAS,CAAA;CAC/E,CAAA;AAED,MAAM,MAAM,mCAAmC,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IACnH,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,0BAA0B,CAAC,EAAE,gCAAgC,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;CACrF,CAAA;AAED,MAAM,MAAM,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,IAAI;IACrF,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,0BAA0B,CAAC,EAAE,gCAAgC,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;IACpF,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC1C,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACtC,CAAA;AAED,MAAM,MAAM,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,IAAI;IACvF,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,SAAS,mBAAmB,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAA;CAC1D,CAAA;AAED,MAAM,MAAM,gCAAgC,CAAC,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,IAAI;IAC9F,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAChC,0BAA0B,CAAC,EAAE,gCAAgC,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;IACpF,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CAC3C,CAAA;AAED,eAAO,MAAM,QAAQ,GAAI,UAAU,MAAM,KAAG,MAA2C,CAAA;AAEvF,eAAO,MAAM,SAAS,GAAI,UAAU,MAAM,EAAE,OAAO,MAAM,KAAG,IAE3D,CAAA;AAED,eAAO,MAAM,YAAY,GAAI,UAAU,MAAM,KAAG,OAQ/C,CAAA;AAED,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,OAAO,OAAO,KAAG,IAEhE,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,eAAe,MAAM,KAAG,MAAM,EAMhE,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,eAAe,MAAM,KAAG,MAAM,EAM/D,CAAA;AAED,eAAO,MAAM,iBAAiB,GAAI,OAAO,MAAM,EAAE,UAAU,SAAS,MAAM,EAAE,EAAE,QAAQ,SAAS,MAAM,EAAE,KAAG,IAOzG,CAAA;AAED,eAAO,MAAM,eAAe,GAAI,eAAe,MAAM,KAAG,IAEvD,CAAA;AAED,eAAO,MAAM,uBAAuB,GAAI,eAAe,MAAM,KAAG,IAE/D,CAAA;AAED,eAAO,MAAM,qCAAqC,GAAI,SAAS,SAAS,MAAM,EAAE,oCAG7E,0CAA0C,CAAC,SAAS,CAAC,KAAG,gCAAgC,CAAC,SAAS,CAcpG,CAAA;AAED,eAAO,MAAM,8BAA8B,GAAI,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,EAAE,iEAK7F,mCAAmC,CAAC,MAAM,EAAE,SAAS,CAAC,KAAG,MAQ3D,CAAA;AAWD,eAAO,MAAM,kBAAkB,GAAI,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,EAAE,qFAMjF,uBAAuB,CAAC,MAAM,EAAE,SAAS,CAAC,KAAG,yBAAyB,CAAC,MAAM,EAAE,SAAS,CAqC1F,CAAA;AAED,eAAO,MAAM,2BAA2B,GAAI,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,EAAE,uEAK1F,gCAAgC,CAAC,MAAM,EAAE,SAAS,CAAC,KAAG,IA+CxD,CAAA"}
|
package/dist/assets/index.js
CHANGED
|
@@ -43,6 +43,25 @@ export const ensureDirectory = (directoryPath) => {
|
|
|
43
43
|
export const removeDirectoryIfExists = (directoryPath) => {
|
|
44
44
|
fs.rmSync(directoryPath, { recursive: true, force: true });
|
|
45
45
|
};
|
|
46
|
+
export const createI18nNamespaceSourceRootResolver = ({ defaultLocalesRoot, overrides = [], }) => {
|
|
47
|
+
const overrideRootByNamespace = new Map();
|
|
48
|
+
for (const override of overrides) {
|
|
49
|
+
for (const namespace of override.namespaces) {
|
|
50
|
+
if (overrideRootByNamespace.has(namespace)) {
|
|
51
|
+
throw new Error(`[i18n assets] Namespace source root configured more than once: ${namespace}`);
|
|
52
|
+
}
|
|
53
|
+
overrideRootByNamespace.set(namespace, override.localesRoot);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return (namespace) => overrideRootByNamespace.get(namespace) ?? defaultLocalesRoot;
|
|
57
|
+
};
|
|
58
|
+
export const resolveI18nNamespaceSourcePath = ({ locale, namespace, localesRoot, resolveNamespaceSourceRoot, }) => {
|
|
59
|
+
const resolvedLocalesRoot = resolveNamespaceSourceRoot?.(namespace) ?? localesRoot;
|
|
60
|
+
if (!resolvedLocalesRoot) {
|
|
61
|
+
throw new Error("[i18n assets] Either localesRoot or resolveNamespaceSourceRoot must be provided.");
|
|
62
|
+
}
|
|
63
|
+
return path.join(resolvedLocalesRoot, locale, `${namespace}.json`);
|
|
64
|
+
};
|
|
46
65
|
const assertFileContentMatches = (label, expectedPath, actualPath) => {
|
|
47
66
|
const expected = readUTF8(expectedPath);
|
|
48
67
|
const actual = readUTF8(actualPath);
|
|
@@ -50,7 +69,7 @@ const assertFileContentMatches = (label, expectedPath, actualPath) => {
|
|
|
50
69
|
throw new Error(`${label} does not match source file.\nsource: ${expectedPath}\nasset: ${actualPath}`);
|
|
51
70
|
}
|
|
52
71
|
};
|
|
53
|
-
export const generateI18nAssets = ({ localesRoot, outputRoot, manifest, cleanOutputRoot = true, }) => {
|
|
72
|
+
export const generateI18nAssets = ({ localesRoot, resolveNamespaceSourceRoot, outputRoot, manifest, cleanOutputRoot = true, }) => {
|
|
54
73
|
if (cleanOutputRoot) {
|
|
55
74
|
removeDirectoryIfExists(outputRoot);
|
|
56
75
|
}
|
|
@@ -60,7 +79,12 @@ export const generateI18nAssets = ({ localesRoot, outputRoot, manifest, cleanOut
|
|
|
60
79
|
const localeOutputPath = path.join(outputRoot, locale);
|
|
61
80
|
ensureDirectory(localeOutputPath);
|
|
62
81
|
for (const namespace of manifest.namespaces) {
|
|
63
|
-
const sourcePath =
|
|
82
|
+
const sourcePath = resolveI18nNamespaceSourcePath({
|
|
83
|
+
locale,
|
|
84
|
+
localesRoot,
|
|
85
|
+
namespace,
|
|
86
|
+
resolveNamespaceSourceRoot,
|
|
87
|
+
});
|
|
64
88
|
const outputPath = path.join(localeOutputPath, `${namespace}.json`);
|
|
65
89
|
readJSONFile(sourcePath);
|
|
66
90
|
writeUTF8(outputPath, readUTF8(sourcePath));
|
|
@@ -75,7 +99,7 @@ export const generateI18nAssets = ({ localesRoot, outputRoot, manifest, cleanOut
|
|
|
75
99
|
outputRoot,
|
|
76
100
|
};
|
|
77
101
|
};
|
|
78
|
-
export const validateGeneratedI18nAssets = ({ localesRoot, generatedRoot, manifest, }) => {
|
|
102
|
+
export const validateGeneratedI18nAssets = ({ localesRoot, resolveNamespaceSourceRoot, generatedRoot, manifest, }) => {
|
|
79
103
|
const manifestPath = path.join(generatedRoot, "manifest.json");
|
|
80
104
|
if (!fs.existsSync(generatedRoot))
|
|
81
105
|
throw new Error(`[i18n assets] Generated root not found: ${generatedRoot}`);
|
|
@@ -96,7 +120,12 @@ export const validateGeneratedI18nAssets = ({ localesRoot, generatedRoot, manife
|
|
|
96
120
|
const expectedFileNames = manifest.namespaces.map((namespace) => `${namespace}.json`);
|
|
97
121
|
assertEqualArrays(`[i18n assets] generated namespace files for ${locale}`, expectedFileNames, listJSONFileNames(generatedLocalePath));
|
|
98
122
|
for (const namespace of manifest.namespaces) {
|
|
99
|
-
assertFileContentMatches(`[i18n assets] ${locale}/${namespace}.json`,
|
|
123
|
+
assertFileContentMatches(`[i18n assets] ${locale}/${namespace}.json`, resolveI18nNamespaceSourcePath({
|
|
124
|
+
locale,
|
|
125
|
+
localesRoot,
|
|
126
|
+
namespace,
|
|
127
|
+
resolveNamespaceSourceRoot,
|
|
128
|
+
}), path.join(generatedLocalePath, `${namespace}.json`));
|
|
100
129
|
}
|
|
101
130
|
}
|
|
102
131
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type TI18nNamespaceSourceRootResolver } from "../assets/index.js";
|
|
1
2
|
import { type TDomainSeedSourceContract, type TDomainTranslationContract } from "./domainContracts.js";
|
|
2
3
|
export type TVerifyI18nSourceArgs<Locale extends string = string, Namespace extends string = string> = {
|
|
3
4
|
localesRoot: string;
|
|
5
|
+
resolveNamespaceSourceRoot?: TI18nNamespaceSourceRootResolver<Namespace> | undefined;
|
|
4
6
|
availableNamespaces: readonly Namespace[];
|
|
5
7
|
declaredLocales?: readonly Locale[] | undefined;
|
|
6
8
|
defaultLocale: Locale;
|
|
@@ -21,5 +23,5 @@ export type TVerifyI18nSourceResult = {
|
|
|
21
23
|
domainSeedSourceContractCount: number;
|
|
22
24
|
domainSeedSourceCodeCount: number;
|
|
23
25
|
};
|
|
24
|
-
export declare const verifyI18nSource: <Locale extends string, Namespace extends string>({ localesRoot, availableNamespaces, declaredLocales, defaultLocale, initialLoadNamespaces, repoRoot, domainTranslationContracts, domainSeedSourceContracts, structuredNamespaceKeyConventionExceptions, }: TVerifyI18nSourceArgs<Locale, Namespace>) => Promise<TVerifyI18nSourceResult>;
|
|
26
|
+
export declare const verifyI18nSource: <Locale extends string, Namespace extends string>({ localesRoot, availableNamespaces, declaredLocales, defaultLocale, initialLoadNamespaces, repoRoot, domainTranslationContracts, domainSeedSourceContracts, structuredNamespaceKeyConventionExceptions, resolveNamespaceSourceRoot, }: TVerifyI18nSourceArgs<Locale, Namespace>) => Promise<TVerifyI18nSourceResult>;
|
|
25
27
|
//# sourceMappingURL=verifyI18nSource.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifyI18nSource.d.ts","sourceRoot":"","sources":["../../src/verifier/verifyI18nSource.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verifyI18nSource.d.ts","sourceRoot":"","sources":["../../src/verifier/verifyI18nSource.ts"],"names":[],"mappings":"AAEA,OAAO,EAAkC,KAAK,gCAAgC,EAAE,MAAM,oBAAoB,CAAA;AAW1G,OAAO,EAGL,KAAK,yBAAyB,EAC9B,KAAK,0BAA0B,EAChC,MAAM,sBAAsB,CAAA;AAE7B,MAAM,MAAM,qBAAqB,CAAC,MAAM,SAAS,MAAM,GAAG,MAAM,EAAE,SAAS,SAAS,MAAM,GAAG,MAAM,IAAI;IACrG,WAAW,EAAE,MAAM,CAAA;IACnB,0BAA0B,CAAC,EAAE,gCAAgC,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;IACpF,mBAAmB,EAAE,SAAS,SAAS,EAAE,CAAA;IACzC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IAC/C,aAAa,EAAE,MAAM,CAAA;IACrB,qBAAqB,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAA;IACxD,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC7B,0BAA0B,CAAC,EAAE,SAAS,0BAA0B,EAAE,GAAG,SAAS,CAAA;IAC9E,yBAAyB,CAAC,EAAE,SAAS,yBAAyB,EAAE,GAAG,SAAS,CAAA;IAC5E,0CAA0C,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAA;CAC9E,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,wBAAwB,EAAE,MAAM,CAAA;IAChC,YAAY,EAAE,MAAM,CAAA;IACpB,8BAA8B,EAAE,MAAM,CAAA;IACtC,gCAAgC,EAAE,MAAM,CAAA;IACxC,6BAA6B,EAAE,MAAM,CAAA;IACrC,yBAAyB,EAAE,MAAM,CAAA;CAClC,CAAA;AAUD,eAAO,MAAM,gBAAgB,GAAU,MAAM,SAAS,MAAM,EAAE,SAAS,SAAS,MAAM,EAAE,uOAWrF,qBAAqB,CAAC,MAAM,EAAE,SAAS,CAAC,KAAG,OAAO,CAAC,uBAAuB,CA2O5E,CAAA"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { resolveI18nNamespaceSourcePath } from "../assets/index.js";
|
|
2
3
|
import { getDeclaredInterpolationTokens, getTranslationStringEntries, parseICUContract, pushContractDiffs, } from "./icuContracts.js";
|
|
3
4
|
import { getLeafShapes, normalizeShapeEntries, validateKeyConventions } from "./keyShape.js";
|
|
4
5
|
import { listDirNames, listJSONFiles, readJSONFileOrThrow } from "./fileSystem.js";
|
|
@@ -10,7 +11,7 @@ const assertNoItems = (label, items) => {
|
|
|
10
11
|
return;
|
|
11
12
|
throw new Error(`[i18n verify] ${label}\n${formatList(items)}`);
|
|
12
13
|
};
|
|
13
|
-
export const verifyI18nSource = async ({ localesRoot, availableNamespaces, declaredLocales, defaultLocale, initialLoadNamespaces = [], repoRoot, domainTranslationContracts = [], domainSeedSourceContracts = [], structuredNamespaceKeyConventionExceptions = [], }) => {
|
|
14
|
+
export const verifyI18nSource = async ({ localesRoot, availableNamespaces, declaredLocales, defaultLocale, initialLoadNamespaces = [], repoRoot, domainTranslationContracts = [], domainSeedSourceContracts = [], structuredNamespaceKeyConventionExceptions = [], resolveNamespaceSourceRoot, }) => {
|
|
14
15
|
if (availableNamespaces.length === 0) {
|
|
15
16
|
throw new Error("[i18n verify] availableNamespaces must contain at least one namespace");
|
|
16
17
|
}
|
|
@@ -34,21 +35,26 @@ export const verifyI18nSource = async ({ localesRoot, availableNamespaces, decla
|
|
|
34
35
|
const namespaceUnion = new Set();
|
|
35
36
|
for (const locale of locales) {
|
|
36
37
|
const localeDir = path.join(localesRoot, locale);
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
const namespaces = resolveNamespaceSourceRoot
|
|
39
|
+
? [...availableNamespaces]
|
|
40
|
+
: (await listJSONFiles(localeDir)).map((file) => file.replace(/\.json$/, ""));
|
|
41
|
+
if (namespaces.length === 0) {
|
|
40
42
|
throw new Error(`[i18n verify] No translation sheets found for locale=${locale}`);
|
|
41
43
|
}
|
|
42
44
|
namespacesByLocale.set(locale, namespaces);
|
|
43
45
|
sheetsByLocale.set(locale, new Map());
|
|
44
46
|
namespaces.forEach((namespace) => namespaceUnion.add(namespace));
|
|
45
|
-
for (const
|
|
46
|
-
const
|
|
47
|
-
|
|
47
|
+
for (const namespace of namespaces) {
|
|
48
|
+
const filePath = resolveI18nNamespaceSourcePath({
|
|
49
|
+
locale,
|
|
50
|
+
localesRoot,
|
|
51
|
+
namespace,
|
|
52
|
+
resolveNamespaceSourceRoot,
|
|
53
|
+
});
|
|
48
54
|
const { json: sheet, raw } = await readJSONFileOrThrow(filePath, "[i18n verify]");
|
|
49
55
|
const canonicalSheet = formatI18nSheet(sheet);
|
|
50
56
|
if (raw !== canonicalSheet) {
|
|
51
|
-
sheetOrderingErrors.push(`${locale}/${
|
|
57
|
+
sheetOrderingErrors.push(`${locale}/${namespace}.json`);
|
|
52
58
|
}
|
|
53
59
|
sheetsByLocale.get(locale)?.set(namespace, sheet);
|
|
54
60
|
sheetCount += 1;
|
package/package.json
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gabrielbourget/i18n-foundation",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Shared i18n runtime foundation for Wavemap and Waveguide facade packages.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
|
+
"packageManager": "pnpm@10.18.3",
|
|
9
10
|
"files": [
|
|
10
11
|
"dist",
|
|
11
12
|
"locales",
|
|
12
|
-
"README.md"
|
|
13
|
+
"README.md",
|
|
14
|
+
"CHANGELOG.md"
|
|
13
15
|
],
|
|
14
16
|
"sideEffects": false,
|
|
15
17
|
"publishConfig": {
|
|
@@ -68,6 +70,18 @@
|
|
|
68
70
|
"import": "./dist/verifier/index.js"
|
|
69
71
|
}
|
|
70
72
|
},
|
|
73
|
+
"scripts": {
|
|
74
|
+
"build": "tsc -p tsconfig.json",
|
|
75
|
+
"format": "prettier --write .",
|
|
76
|
+
"format:check": "prettier --check .",
|
|
77
|
+
"prepack": "pnpm build",
|
|
78
|
+
"prepublishOnly": "pnpm verify",
|
|
79
|
+
"test": "vitest run",
|
|
80
|
+
"test:unit": "vitest run",
|
|
81
|
+
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
82
|
+
"typecheck:tests": "tsc --noEmit -p tsconfig.vitest.json",
|
|
83
|
+
"verify": "pnpm format:check && pnpm typecheck && pnpm typecheck:tests && pnpm test"
|
|
84
|
+
},
|
|
71
85
|
"peerDependencies": {
|
|
72
86
|
"i18next": "^23.16.8",
|
|
73
87
|
"i18next-icu": "^2.4.1",
|
|
@@ -91,13 +105,5 @@
|
|
|
91
105
|
"react-i18next": "13.5.0",
|
|
92
106
|
"typescript": "5.9.3",
|
|
93
107
|
"vitest": "4.0.18"
|
|
94
|
-
},
|
|
95
|
-
"scripts": {
|
|
96
|
-
"build": "tsc -p tsconfig.json",
|
|
97
|
-
"format": "prettier --write .",
|
|
98
|
-
"format:check": "prettier --check .",
|
|
99
|
-
"test": "vitest run",
|
|
100
|
-
"test:unit": "vitest run",
|
|
101
|
-
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
102
108
|
}
|
|
103
|
-
}
|
|
109
|
+
}
|