@wads.dev/i18n-ts 0.0.1-alpha.0 → 0.0.1-alpha.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/AI/ARCHITECTURE.md +4 -1
- package/README.md +13 -3
- package/dist/cli/exportBundle.js +2 -2
- package/dist/config/index.d.ts +29 -1
- package/dist/config/index.js +83 -4
- package/docs/BUNDLE_WORKFLOW.md +1 -1
- package/docs/CONFIGURATION.md +121 -7
- package/package.json +2 -2
package/AI/ARCHITECTURE.md
CHANGED
|
@@ -12,13 +12,16 @@ Read this document before changing a consuming project's translations. The host
|
|
|
12
12
|
`i18n.config.json` describes how translation paths map to the repository:
|
|
13
13
|
|
|
14
14
|
- `levelCount` defines how many leading key segments are structural groups, excluding root.
|
|
15
|
+
- `catalogFile` identifies the project-root-relative TypeScript module that exports `Langs`.
|
|
15
16
|
- `levelNames` gives those groups human-readable names.
|
|
16
17
|
- `levelImports[0]` describes the root translation location without consuming a key segment.
|
|
17
18
|
- `levelImports[1...levelCount]` map group values to directories and may define `valueReplacer` and `fullReplacer` rules.
|
|
18
|
-
- `importAliases` resolves project-root prefixes; unaliased level paths are relative to their parent.
|
|
19
|
+
- `exportConfig.importAliases` resolves project-root prefixes; unaliased level paths are relative to their parent.
|
|
20
|
+
- `exportConfig.codeFormat` controls quotes, semicolons, shorthand properties, trailing commas, indentation and fit-based object/array wrapping in generated TypeScript. Defaults are single quotes, semicolons, shorthand properties, trailing commas, a 120-character print width, at most 4 inline object properties, at most 8 inline array items and two spaces per level. Nested collections are always multiline; only shallow collections may be inline.
|
|
19
21
|
- `translationsDirectory` is the locale directory inside the resolved group.
|
|
20
22
|
- `languageFileTemplate` maps a language identifier to its file.
|
|
21
23
|
- `languageReplacer` maps a catalog language key to a different filename when required.
|
|
24
|
+
- `deletion` controls how tools report and remove files inside translation directories that are absent from the generated plan. `false` disables detection; otherwise `ignoredExtensions` preserves intentional colocated files and `autoDelete` opts the project into deletion without the CLI `--delete` flag.
|
|
22
25
|
|
|
23
26
|
Replacers accept dotted full paths or nested objects. `valueReplacer` changes the value inserted in `{value}`. A string in `fullReplacer` redirects a subtree, while `null` keeps the subtree in the parent level's translation files.
|
|
24
27
|
|
package/README.md
CHANGED
|
@@ -6,6 +6,16 @@ Framework-independent TypeScript foundations for strongly typed internationaliza
|
|
|
6
6
|
|
|
7
7
|
> Status: `0.0.1-alpha.0`. Public APIs and JSON formats may change before `1.0.0`.
|
|
8
8
|
|
|
9
|
+
## Wads i18n ecosystem
|
|
10
|
+
|
|
11
|
+
| Project | Responsibility |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| [`@wads.dev/i18n-ts`](https://github.com/wads-dev/i18n-ts) | Framework-independent contracts, language loading, project configuration and portable bundles. |
|
|
14
|
+
| [`@wads.dev/i18n-react`](https://github.com/wads-dev/i18n-react) | React Provider, hooks and rich translation rendering built on `i18n-ts`. |
|
|
15
|
+
| [`@wads.dev/i18n-editor`](https://github.com/wads-dev/i18n-editor) | Local editor for inspecting and changing bundles and, incrementally, regenerating project files. |
|
|
16
|
+
|
|
17
|
+
Use only the packages required by the project. The core remains independent of React and of the Editor.
|
|
18
|
+
|
|
9
19
|
## Why it exists
|
|
10
20
|
|
|
11
21
|
Translation files are application code: their structure changes, keys move, languages grow and mistakes should fail during development rather than reach users. This package keeps that foundation small and explicit:
|
|
@@ -16,7 +26,7 @@ Translation files are application code: their structure changes, keys move, lang
|
|
|
16
26
|
- A JSON bundle lets editors and tools work without importing the application runtime.
|
|
17
27
|
- `i18n.config.json` explains project structure to CLIs, editors and AI agents.
|
|
18
28
|
|
|
19
|
-
Platform integrations are separate. React support belongs to `@wads.dev/i18n-react
|
|
29
|
+
Platform integrations are separate. React support belongs to [`@wads.dev/i18n-react`](https://github.com/wads-dev/i18n-react); translation editing belongs to [`@wads.dev/i18n-editor`](https://github.com/wads-dev/i18n-editor). The same contracts can support future Swift and Kotlin runtimes.
|
|
20
30
|
|
|
21
31
|
## Installation
|
|
22
32
|
|
|
@@ -104,7 +114,7 @@ selected.lang.commons.continue
|
|
|
104
114
|
|
|
105
115
|
## Configure the project structure
|
|
106
116
|
|
|
107
|
-
Add `i18n.config.json` to the repository root. The application runtime does not need this file: it exists primarily to describe the project to AI agents and to `@wads.dev/i18n-editor`.
|
|
117
|
+
Add `i18n.config.json` to the repository root. The application runtime does not need this file: it exists primarily to describe the project to AI agents and to `@wads.dev/i18n-editor`. Its `catalogFile` points to the project-root-relative TypeScript module that exports `Langs`, allowing the Editor to generate a missing bundle automatically.
|
|
108
118
|
|
|
109
119
|
The Editor uses it to understand which key segments represent modules or features, how object names map to real folders, where root translations belong and which files should be regenerated after editing. This keeps structural knowledge outside application code.
|
|
110
120
|
|
|
@@ -121,7 +131,7 @@ npx i18n-bundle \
|
|
|
121
131
|
--output i18n.bundle.json
|
|
122
132
|
```
|
|
123
133
|
|
|
124
|
-
The bundle can be opened by `@wads.dev/i18n-editor` or shared with translators without giving them the repository or asking them to navigate many TypeScript files. After review, the edited bundle can return to the development team and be redistributed into the configured project structure. The resulting source changes remain ordinary files, so the Git diff becomes the final safety and review layer before merge.
|
|
134
|
+
The bundle can be opened by [`@wads.dev/i18n-editor`](https://github.com/wads-dev/i18n-editor) or shared with translators without giving them the repository or asking them to navigate many TypeScript files. After review, the edited bundle can return to the development team and be redistributed into the configured project structure. The resulting source changes remain ordinary files, so the Git diff becomes the final safety and review layer before merge.
|
|
125
135
|
|
|
126
136
|
The alpha currently supports bundle generation, visualization and in-memory editing. Regenerating the complete TypeScript file tree from a reviewed bundle is the next Editor/CLI integration step; the configuration and export plan already describe those destinations.
|
|
127
137
|
|
package/dist/cli/exportBundle.js
CHANGED
|
@@ -17,7 +17,7 @@ function loadTypeScript() {
|
|
|
17
17
|
}
|
|
18
18
|
function parseArguments(argv) {
|
|
19
19
|
const options = {
|
|
20
|
-
input: 'src/shared/i18n/
|
|
20
|
+
input: 'src/shared/i18n/index.ts',
|
|
21
21
|
output: 'i18n.bundle.json',
|
|
22
22
|
};
|
|
23
23
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -51,7 +51,7 @@ Usage:
|
|
|
51
51
|
i18n-bundle --input src/shared/i18n/translations/index.ts --output i18n.bundle.json
|
|
52
52
|
|
|
53
53
|
Options:
|
|
54
|
-
--input Project TypeScript catalog (default: src/shared/i18n/
|
|
54
|
+
--input Project TypeScript catalog (default: src/shared/i18n/index.ts)
|
|
55
55
|
--output Output JSON file (default: i18n.bundle.json)
|
|
56
56
|
--config Optional i18n.config.json copied beside the output bundle
|
|
57
57
|
--help, -h Show this help`);
|
package/dist/config/index.d.ts
CHANGED
|
@@ -9,19 +9,47 @@ export type I18nLevelImport = {
|
|
|
9
9
|
valueReplacer?: I18nPathReplacer;
|
|
10
10
|
fullReplacer?: I18nPathReplacer;
|
|
11
11
|
};
|
|
12
|
+
export type I18nDeletionConfig = {
|
|
13
|
+
ignoredExtensions: string[];
|
|
14
|
+
autoDelete: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type I18nIndentationConfig = {
|
|
17
|
+
character: 'space' | 'tab';
|
|
18
|
+
size: number;
|
|
19
|
+
};
|
|
20
|
+
export type I18nCollectionLayout = 'fit' | 'multiline';
|
|
21
|
+
export type I18nCodeFormatConfig = {
|
|
22
|
+
useDoubleQuotes: boolean;
|
|
23
|
+
useSemicolons: boolean;
|
|
24
|
+
useShorthandProperties: boolean;
|
|
25
|
+
useTrailingCommas: boolean;
|
|
26
|
+
printWidth: number;
|
|
27
|
+
maxObjectInlineItems: number;
|
|
28
|
+
maxArrayInlineItems: number;
|
|
29
|
+
objectLayout: I18nCollectionLayout;
|
|
30
|
+
arrayLayout: I18nCollectionLayout;
|
|
31
|
+
indentation: I18nIndentationConfig;
|
|
32
|
+
};
|
|
33
|
+
export type I18nExportConfig = {
|
|
34
|
+
importAliases: Record<string, string>;
|
|
35
|
+
codeFormat: I18nCodeFormatConfig;
|
|
36
|
+
};
|
|
12
37
|
export type I18nProjectConfig = {
|
|
13
38
|
format: typeof PROJECT_CONFIG_FORMAT;
|
|
14
39
|
version: typeof PROJECT_CONFIG_VERSION;
|
|
40
|
+
catalogFile: string;
|
|
15
41
|
levelCount: number;
|
|
16
42
|
levelNames: string;
|
|
17
43
|
levelImports: I18nLevelImport[];
|
|
18
|
-
|
|
44
|
+
exportConfig: I18nExportConfig;
|
|
19
45
|
translationsDirectory: string;
|
|
20
46
|
languageFileTemplate: string;
|
|
21
47
|
languageReplacer: Record<string, string>;
|
|
48
|
+
deletion: false | I18nDeletionConfig;
|
|
22
49
|
};
|
|
23
50
|
export declare function getDefaultLevelImport(levelIndex: number): I18nLevelImport;
|
|
24
51
|
export declare function createDefaultProjectConfig(): I18nProjectConfig;
|
|
52
|
+
export declare function normalizeDeletionConfig(value: unknown): false | I18nDeletionConfig;
|
|
25
53
|
export declare function normalizeProjectConfig(value?: Partial<I18nProjectConfig>): I18nProjectConfig;
|
|
26
54
|
export declare function getLevelName(config: I18nProjectConfig, level: number): string;
|
|
27
55
|
export declare function getLevelImport(config: I18nProjectConfig, levelIndex: number): I18nLevelImport;
|
package/dist/config/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export function createDefaultProjectConfig() {
|
|
|
13
13
|
return {
|
|
14
14
|
format: PROJECT_CONFIG_FORMAT,
|
|
15
15
|
version: PROJECT_CONFIG_VERSION,
|
|
16
|
+
catalogFile: 'src/shared/i18n/index.ts',
|
|
16
17
|
levelCount: 2,
|
|
17
18
|
levelNames: 'Module, Feature',
|
|
18
19
|
levelImports: [
|
|
@@ -20,10 +21,31 @@ export function createDefaultProjectConfig() {
|
|
|
20
21
|
getDefaultLevelImport(1),
|
|
21
22
|
getDefaultLevelImport(2),
|
|
22
23
|
],
|
|
23
|
-
|
|
24
|
+
exportConfig: {
|
|
25
|
+
importAliases: { '@/': 'src/' },
|
|
26
|
+
codeFormat: {
|
|
27
|
+
useDoubleQuotes: false,
|
|
28
|
+
useSemicolons: true,
|
|
29
|
+
useShorthandProperties: true,
|
|
30
|
+
useTrailingCommas: true,
|
|
31
|
+
printWidth: 120,
|
|
32
|
+
maxObjectInlineItems: 4,
|
|
33
|
+
maxArrayInlineItems: 8,
|
|
34
|
+
objectLayout: 'fit',
|
|
35
|
+
arrayLayout: 'fit',
|
|
36
|
+
indentation: {
|
|
37
|
+
character: 'space',
|
|
38
|
+
size: 2,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
24
42
|
translationsDirectory: 'i18n',
|
|
25
43
|
languageFileTemplate: '{language}.ts',
|
|
26
44
|
languageReplacer: {},
|
|
45
|
+
deletion: {
|
|
46
|
+
ignoredExtensions: [],
|
|
47
|
+
autoDelete: false,
|
|
48
|
+
},
|
|
27
49
|
};
|
|
28
50
|
}
|
|
29
51
|
function isRecord(value) {
|
|
@@ -48,13 +70,66 @@ function normalizeStringRecord(value) {
|
|
|
48
70
|
.filter((entry) => typeof entry[1] === 'string')
|
|
49
71
|
.map(([key, item]) => [key, item.trim()]));
|
|
50
72
|
}
|
|
73
|
+
export function normalizeDeletionConfig(value) {
|
|
74
|
+
if (value === false)
|
|
75
|
+
return false;
|
|
76
|
+
const input = isRecord(value) ? value : {};
|
|
77
|
+
const ignoredExtensions = Array.isArray(input.ignoredExtensions)
|
|
78
|
+
? [...new Set(input.ignoredExtensions
|
|
79
|
+
.filter((extension) => typeof extension === 'string')
|
|
80
|
+
.map((extension) => extension.trim().toLowerCase())
|
|
81
|
+
.filter(Boolean)
|
|
82
|
+
.map((extension) => extension.startsWith('.') ? extension : `.${extension}`))]
|
|
83
|
+
: [];
|
|
84
|
+
return {
|
|
85
|
+
ignoredExtensions,
|
|
86
|
+
autoDelete: input.autoDelete === true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function normalizeCodeFormat(value, legacyExportConfig) {
|
|
90
|
+
const defaults = createDefaultProjectConfig().exportConfig.codeFormat;
|
|
91
|
+
const input = isRecord(value) ? value : {};
|
|
92
|
+
const indentation = isRecord(input.indentation) ? input.indentation : {};
|
|
93
|
+
const rawIndentationSize = Number.parseInt(String(indentation.size ?? defaults.indentation.size), 10);
|
|
94
|
+
const rawPrintWidth = Number.parseInt(String(input.printWidth ?? defaults.printWidth), 10);
|
|
95
|
+
const rawMaxObjectInlineItems = Number.parseInt(String(input.maxObjectInlineItems ?? defaults.maxObjectInlineItems), 10);
|
|
96
|
+
const rawMaxArrayInlineItems = Number.parseInt(String(input.maxArrayInlineItems ?? defaults.maxArrayInlineItems), 10);
|
|
97
|
+
return {
|
|
98
|
+
useDoubleQuotes: (input.useDoubleQuotes ?? legacyExportConfig.useDoubleQuotes) === true,
|
|
99
|
+
useSemicolons: input.useSemicolons !== false,
|
|
100
|
+
useShorthandProperties: input.useShorthandProperties !== false,
|
|
101
|
+
useTrailingCommas: input.useTrailingCommas !== false,
|
|
102
|
+
printWidth: Number.isFinite(rawPrintWidth)
|
|
103
|
+
? Math.min(400, Math.max(40, rawPrintWidth))
|
|
104
|
+
: defaults.printWidth,
|
|
105
|
+
maxObjectInlineItems: Number.isFinite(rawMaxObjectInlineItems)
|
|
106
|
+
? Math.min(100, Math.max(0, rawMaxObjectInlineItems))
|
|
107
|
+
: defaults.maxObjectInlineItems,
|
|
108
|
+
maxArrayInlineItems: Number.isFinite(rawMaxArrayInlineItems)
|
|
109
|
+
? Math.min(100, Math.max(0, rawMaxArrayInlineItems))
|
|
110
|
+
: defaults.maxArrayInlineItems,
|
|
111
|
+
objectLayout: input.objectLayout === 'multiline' ? 'multiline' : 'fit',
|
|
112
|
+
arrayLayout: input.arrayLayout === 'multiline' ? 'multiline' : 'fit',
|
|
113
|
+
indentation: {
|
|
114
|
+
character: indentation.character === 'tab' ? 'tab' : 'space',
|
|
115
|
+
size: Number.isFinite(rawIndentationSize)
|
|
116
|
+
? Math.min(8, Math.max(1, rawIndentationSize))
|
|
117
|
+
: defaults.indentation.size,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
51
121
|
export function normalizeProjectConfig(value = {}) {
|
|
52
122
|
const defaults = createDefaultProjectConfig();
|
|
53
123
|
const levelCount = Math.max(0, Number.parseInt(String(value.levelCount ?? defaults.levelCount), 10) || 0);
|
|
54
124
|
const inputImports = Array.isArray(value.levelImports) ? value.levelImports : [];
|
|
125
|
+
const inputRecord = value;
|
|
126
|
+
const exportConfig = isRecord(value.exportConfig) ? value.exportConfig : {};
|
|
55
127
|
return {
|
|
56
128
|
format: PROJECT_CONFIG_FORMAT,
|
|
57
129
|
version: PROJECT_CONFIG_VERSION,
|
|
130
|
+
catalogFile: typeof value.catalogFile === 'string' && value.catalogFile.trim()
|
|
131
|
+
? value.catalogFile.trim()
|
|
132
|
+
: defaults.catalogFile,
|
|
58
133
|
levelCount,
|
|
59
134
|
levelNames: typeof value.levelNames === 'string' ? value.levelNames : defaults.levelNames,
|
|
60
135
|
levelImports: Array.from({ length: levelCount + 1 }, (_, index) => {
|
|
@@ -66,9 +141,12 @@ export function normalizeProjectConfig(value = {}) {
|
|
|
66
141
|
fullReplacer: normalizeReplacer(input.fullReplacer),
|
|
67
142
|
};
|
|
68
143
|
}),
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
144
|
+
exportConfig: {
|
|
145
|
+
importAliases: {
|
|
146
|
+
...defaults.exportConfig.importAliases,
|
|
147
|
+
...normalizeStringRecord(exportConfig.importAliases ?? inputRecord.importAliases),
|
|
148
|
+
},
|
|
149
|
+
codeFormat: normalizeCodeFormat(exportConfig.codeFormat, exportConfig),
|
|
72
150
|
},
|
|
73
151
|
translationsDirectory: typeof value.translationsDirectory === 'string' && value.translationsDirectory.trim()
|
|
74
152
|
? value.translationsDirectory.trim()
|
|
@@ -77,6 +155,7 @@ export function normalizeProjectConfig(value = {}) {
|
|
|
77
155
|
? value.languageFileTemplate.trim()
|
|
78
156
|
: defaults.languageFileTemplate,
|
|
79
157
|
languageReplacer: normalizeStringRecord(value.languageReplacer),
|
|
158
|
+
deletion: normalizeDeletionConfig(value.deletion),
|
|
80
159
|
};
|
|
81
160
|
}
|
|
82
161
|
export function getLevelName(config, level) {
|
package/docs/BUNDLE_WORKFLOW.md
CHANGED
|
@@ -27,7 +27,7 @@ The catalog module must export `Langs`. When `--config` is supplied, the normali
|
|
|
27
27
|
|
|
28
28
|
## Review and edit
|
|
29
29
|
|
|
30
|
-
The Editor loads the bundle as one in-memory object and uses `i18n.config.json` to present structural levels such as modules and features. Reviewers can navigate all languages together, compare values and edit text without understanding the source repository.
|
|
30
|
+
The Editor loads the bundle as one in-memory object and uses `i18n.config.json` to present structural levels such as modules and features. When it runs from the project root and the bundle is missing, it can use the configured `catalogFile` to generate the bundle automatically. Reviewers can navigate all languages together, compare values and edit text without understanding the source repository.
|
|
31
31
|
|
|
32
32
|
The intended collaboration cycle is:
|
|
33
33
|
|
package/docs/CONFIGURATION.md
CHANGED
|
@@ -14,6 +14,7 @@ The application runtime does not read this file. Its primary consumers are:
|
|
|
14
14
|
{
|
|
15
15
|
"format": "wads-i18n-project-config",
|
|
16
16
|
"version": 1,
|
|
17
|
+
"catalogFile": "src/shared/i18n/index.ts",
|
|
17
18
|
"levelCount": 2,
|
|
18
19
|
"levelNames": "Module, Feature",
|
|
19
20
|
"levelImports": [
|
|
@@ -39,14 +40,35 @@ The application runtime does not read this file. Its primary consumers are:
|
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
],
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
43
|
+
"exportConfig": {
|
|
44
|
+
"importAliases": {
|
|
45
|
+
"@design/": "src/shared/design-system/",
|
|
46
|
+
"@/": "src/"
|
|
47
|
+
},
|
|
48
|
+
"codeFormat": {
|
|
49
|
+
"useDoubleQuotes": false,
|
|
50
|
+
"useSemicolons": true,
|
|
51
|
+
"useShorthandProperties": true,
|
|
52
|
+
"useTrailingCommas": true,
|
|
53
|
+
"printWidth": 120,
|
|
54
|
+
"maxObjectInlineItems": 4,
|
|
55
|
+
"maxArrayInlineItems": 8,
|
|
56
|
+
"objectLayout": "fit",
|
|
57
|
+
"arrayLayout": "fit",
|
|
58
|
+
"indentation": {
|
|
59
|
+
"character": "space",
|
|
60
|
+
"size": 2
|
|
61
|
+
}
|
|
62
|
+
}
|
|
45
63
|
},
|
|
46
64
|
"translationsDirectory": "i18n",
|
|
47
65
|
"languageFileTemplate": "{language}.ts",
|
|
48
66
|
"languageReplacer": {
|
|
49
67
|
"pt": "ptBR"
|
|
68
|
+
},
|
|
69
|
+
"deletion": {
|
|
70
|
+
"ignoredExtensions": [".md"],
|
|
71
|
+
"autoDelete": false
|
|
50
72
|
}
|
|
51
73
|
}
|
|
52
74
|
```
|
|
@@ -59,13 +81,15 @@ JSON does not support comments. Keep explanations in documentation rather than a
|
|
|
59
81
|
| --- | --- | --- |
|
|
60
82
|
| `format` | string | Contract identifier. Currently `wads-i18n-project-config`. |
|
|
61
83
|
| `version` | number | Configuration schema version. Currently `1`. |
|
|
84
|
+
| `catalogFile` | string | Project-root-relative TypeScript module that exports `Langs`. The Editor uses it to generate a missing bundle. |
|
|
62
85
|
| `levelCount` | number | Structural key levels, excluding root. |
|
|
63
86
|
| `levelNames` | string | Comma-separated display names used by tools. Missing entries become `Level N`. |
|
|
64
87
|
| `levelImports` | array | Root entry plus one entry for each structural level. Its length is `levelCount + 1`. |
|
|
65
|
-
| `
|
|
88
|
+
| `exportConfig` | object | Controls generated source formatting and project-path aliases used during export. |
|
|
66
89
|
| `translationsDirectory` | string | Directory appended to every resolved translation owner. |
|
|
67
90
|
| `languageFileTemplate` | string | Locale filename template with `{language}`. |
|
|
68
91
|
| `languageReplacer` | object | Maps catalog language keys to actual filename values. |
|
|
92
|
+
| `deletion` | `false` or object | Controls detection, warnings and removal of files outside the generated plan. |
|
|
69
93
|
|
|
70
94
|
## Root and structural levels
|
|
71
95
|
|
|
@@ -137,17 +161,69 @@ Like `valueReplacer`, it accepts dotted keys and nested objects.
|
|
|
137
161
|
|
|
138
162
|
## Import aliases
|
|
139
163
|
|
|
140
|
-
|
|
164
|
+
`exportConfig.importAliases` maps configuration paths to project-relative directories. The longest matching prefix wins.
|
|
141
165
|
|
|
142
166
|
```json
|
|
143
167
|
{
|
|
144
|
-
"
|
|
145
|
-
|
|
168
|
+
"exportConfig": {
|
|
169
|
+
"importAliases": {
|
|
170
|
+
"@design/": "src/shared/design-system/",
|
|
171
|
+
"@/": "src/"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
146
174
|
}
|
|
147
175
|
```
|
|
148
176
|
|
|
149
177
|
With this definition, use `@/modules/{value}`, not `@/src/modules/{value}`. Adding `src` to both sides would incorrectly produce `src/src/modules/...`.
|
|
150
178
|
|
|
179
|
+
## Generated TypeScript formatting
|
|
180
|
+
|
|
181
|
+
`exportConfig.codeFormat` controls the TypeScript emitted by the Editor. Its complete defaults are:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"exportConfig": {
|
|
186
|
+
"codeFormat": {
|
|
187
|
+
"useDoubleQuotes": false,
|
|
188
|
+
"useSemicolons": true,
|
|
189
|
+
"useShorthandProperties": true,
|
|
190
|
+
"useTrailingCommas": true,
|
|
191
|
+
"printWidth": 120,
|
|
192
|
+
"maxObjectInlineItems": 4,
|
|
193
|
+
"maxArrayInlineItems": 8,
|
|
194
|
+
"objectLayout": "fit",
|
|
195
|
+
"arrayLayout": "fit",
|
|
196
|
+
"indentation": {
|
|
197
|
+
"character": "space",
|
|
198
|
+
"size": 2
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
| Field | Type | Default | Meaning |
|
|
206
|
+
| --- | --- | --- | --- |
|
|
207
|
+
| `useDoubleQuotes` | boolean | `false` | Uses double quotes instead of single quotes for generated strings, quoted keys, imports, metadata and language unions. |
|
|
208
|
+
| `useSemicolons` | boolean | `true` | Terminates generated declarations, imports, exports and type members with semicolons. |
|
|
209
|
+
| `useShorthandProperties` | boolean | `true` | Emits `feature,` instead of `feature: feature,` when the property and imported identifier match. |
|
|
210
|
+
| `useTrailingCommas` | boolean | `true` | Keeps a comma after the final item in multiline objects and arrays. Required separators between earlier items are always emitted. |
|
|
211
|
+
| `printWidth` | integer from 40 to 400 | `120` | Maximum generated line width used when deciding whether a collection fits inline. |
|
|
212
|
+
| `maxObjectInlineItems` | integer from 0 to 100 | `4` | Maximum number of properties allowed in a shallow inline object. `0` disables inline objects. |
|
|
213
|
+
| `maxArrayInlineItems` | integer from 0 to 100 | `8` | Maximum number of items allowed in a shallow inline array. `0` disables inline arrays. |
|
|
214
|
+
| `objectLayout` | `"fit"` or `"multiline"` | `"fit"` | Keeps a shallow object inline when it fits both `printWidth` and `maxObjectInlineItems`, or always expands it. |
|
|
215
|
+
| `arrayLayout` | `"fit"` or `"multiline"` | `"fit"` | Keeps a shallow array inline when it fits both `printWidth` and `maxArrayInlineItems`, or always expands it. |
|
|
216
|
+
|
|
217
|
+
Only shallow collections can be rendered inline. An object or array that directly contains another object or array is always multiline; this rule is not configurable. The nested shallow collection may still be inline on its own property or item line.
|
|
218
|
+
| `indentation.character` | `"space"` or `"tab"` | `"space"` | Selects the indentation character. |
|
|
219
|
+
| `indentation.size` | integer from 1 to 8 | `2` | Number of indentation characters per nesting level. |
|
|
220
|
+
|
|
221
|
+
Function bodies stored in bundles retain their original source text and are not reformatted internally.
|
|
222
|
+
|
|
223
|
+
Generated imports follow the corresponding structural path configuration. Aliased `levelImports` and `fullReplacer` paths generate the most specific matching alias, while relative level paths generate relative imports. Child imports use the child key segment as their local identifier, enabling shorthand composition such as `finance,`.
|
|
224
|
+
|
|
225
|
+
The built-in options intentionally cover deterministic source generation without depending on one formatter. A future integration may read established formatter settings or run a configured post-export command. Such a command must remain explicit, project-controlled and separate from source generation because it executes code in the consuming repository.
|
|
226
|
+
|
|
151
227
|
## Language filenames
|
|
152
228
|
|
|
153
229
|
`languageFileTemplate` controls the generated filename:
|
|
@@ -164,6 +240,44 @@ When a catalog key differs from the existing filename, use `languageReplacer`:
|
|
|
164
240
|
|
|
165
241
|
The catalog language `pt` then generates `ptBR.ts`.
|
|
166
242
|
|
|
243
|
+
## Divergent files and deletion
|
|
244
|
+
|
|
245
|
+
Translation directories are treated as managed project structure. A file found inside one of these directories but absent from the generated plan is a deletion candidate.
|
|
246
|
+
|
|
247
|
+
The safe default detects and reports every candidate, but does not delete it automatically:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"deletion": {
|
|
252
|
+
"ignoredExtensions": [],
|
|
253
|
+
"autoDelete": false
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Use `ignoredExtensions` for files that are intentionally colocated with translations and must not appear as deletion candidates. Extensions are case-insensitive and may be written with or without the leading dot:
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"deletion": {
|
|
263
|
+
"ignoredExtensions": [".md"],
|
|
264
|
+
"autoDelete": false
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
With this configuration, documentation such as `ARCHITECTURE.md` is preserved while divergent TypeScript files are still reported. An ignored file is never deleted, and its containing directory remains while it is nonempty.
|
|
270
|
+
|
|
271
|
+
Set `autoDelete` to `true` only when the project intentionally allows every non-ignored candidate to be removed during export without the CLI `--delete` option. Interactive export confirmation still applies unless `--yes` is used.
|
|
272
|
+
|
|
273
|
+
Set `deletion` to `false` to disable candidate detection, deletion warnings and automatic deletion entirely:
|
|
274
|
+
|
|
275
|
+
```json
|
|
276
|
+
{ "deletion": false }
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Without `autoDelete`, use `i18n-edit export --delete` to apply the reported deletions for a single export. Preview remains read-only.
|
|
280
|
+
|
|
167
281
|
## Generated destinations
|
|
168
282
|
|
|
169
283
|
For every resolved owner, the Editor export plan currently includes:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wads.dev/i18n-ts",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.1",
|
|
4
4
|
"description": "Dependency-free typed i18n contracts, bundle tools and language loading.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"typescript": ">=5"
|
|
58
|
+
"typescript": ">=5 <7"
|
|
59
59
|
},
|
|
60
60
|
"peerDependenciesMeta": {
|
|
61
61
|
"typescript": {
|