@lang-tag/cli 0.11.0 → 0.11.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/README.md +2 -2
- package/algorithms/config-generation/path-based-config-generator.d.ts +12 -12
- package/algorithms/index.cjs +15 -15
- package/algorithms/index.js +15 -15
- package/index.cjs +3 -3
- package/index.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ The core is optimized for performance, with a bundle size of just **~1KB** ([che
|
|
|
14
14
|
|
|
15
15
|
### Effortless translation structure
|
|
16
16
|
|
|
17
|
-
Instead of manually managing centralized translation files, `lang-tag` lets you colocate keys within components and automatically organizes them into namespaces based on your project structure. For example, all components in `components/orders` or pages in `pages/order` share the `orders` namespace. You define a simple
|
|
17
|
+
Instead of manually managing centralized translation files, `lang-tag` lets you colocate keys within components and automatically organizes them into namespaces based on your project structure. For example, all components in `components/orders` or pages in `pages/order` share the `orders` namespace. You define a simple directory-to-namespace mapping once, and `lang-tag` handles merging and file organization—while you retain full control over how namespaces are merged.
|
|
18
18
|
|
|
19
19
|
> Set your rules, then let `lang-tag` do the rest.
|
|
20
20
|
|
|
@@ -23,7 +23,7 @@ Instead of manually managing centralized translation files, `lang-tag` lets you
|
|
|
23
23
|
Full functionality is available through an advanced CLI that keeps your application bundle size untouched:
|
|
24
24
|
|
|
25
25
|
- **Automatic translation collection** – `lang-tag collect` scans your project for translation tags and aggregates them into organized JSON files (e.g., `public/locales/en/common.json`), based on your configuration
|
|
26
|
-
- **Dynamic configuration updates** – `lang-tag regenerate-tags` automatically refreshes translation settings in your code, using rules defined in your configuration (e.g., mapping namespaces based on
|
|
26
|
+
- **Dynamic configuration updates** – `lang-tag regenerate-tags` automatically refreshes translation settings in your code, using rules defined in your configuration (e.g., mapping namespaces based on directory structure)
|
|
27
27
|
- **Third-party translation import** – `lang-tag import` detects and integrates translations from external libraries, adapting them to your project’s translation system
|
|
28
28
|
- **Watch mode** – `lang-tag watch` monitors your source files for changes and automatically re-collects/re-generates translations when needed
|
|
29
29
|
|
|
@@ -6,26 +6,26 @@ export interface PathBasedConfigGeneratorOptions {
|
|
|
6
6
|
*/
|
|
7
7
|
includeFileName?: boolean;
|
|
8
8
|
/**
|
|
9
|
-
* Whether to completely remove
|
|
10
|
-
* If false, only the brackets are removed from
|
|
9
|
+
* Whether to completely remove directories wrapped in brackets () or [].
|
|
10
|
+
* If false, only the brackets are removed from directory names.
|
|
11
11
|
* @default true
|
|
12
12
|
*
|
|
13
13
|
* @example
|
|
14
14
|
* - true: 'app/(admin)/users' -> 'app/users'
|
|
15
15
|
* - false: 'app/(admin)/users' -> 'app/admin/users'
|
|
16
16
|
*/
|
|
17
|
-
|
|
17
|
+
removeBracketedDirectories?: boolean;
|
|
18
18
|
/**
|
|
19
|
-
* List of
|
|
19
|
+
* List of directory names to completely ignore globally.
|
|
20
20
|
* These will be removed from all paths regardless of their position.
|
|
21
21
|
* @default []
|
|
22
22
|
*
|
|
23
23
|
* @example ['src', 'app', 'components']
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
ignoreDirectories?: string[];
|
|
26
26
|
/**
|
|
27
|
-
* When true, automatically extracts root
|
|
28
|
-
* and adds them to the
|
|
27
|
+
* When true, automatically extracts root directory names from the config.includes patterns
|
|
28
|
+
* and adds them to the ignoreDirectories list.
|
|
29
29
|
*
|
|
30
30
|
* @default false
|
|
31
31
|
*
|
|
@@ -36,9 +36,9 @@ export interface PathBasedConfigGeneratorOptions {
|
|
|
36
36
|
* // With includes: ['(src|app)/**\/*.{js,ts,jsx,tsx}', 'components/**\/*.{jsx,tsx}']
|
|
37
37
|
* // Automatically ignores: ['src', 'app', 'components']
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
ignoreIncludesRootDirectories?: boolean;
|
|
40
40
|
/**
|
|
41
|
-
* Hierarchical structure for ignoring specific
|
|
41
|
+
* Hierarchical structure for ignoring specific directory patterns.
|
|
42
42
|
* Keys represent path segments to match, values indicate what to ignore at that level.
|
|
43
43
|
*
|
|
44
44
|
* @example
|
|
@@ -98,9 +98,9 @@ export interface PathBasedConfigGeneratorOptions {
|
|
|
98
98
|
* export default {
|
|
99
99
|
* onConfigGeneration: pathBasedConfigGenerator({
|
|
100
100
|
* includeFileName: false,
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
101
|
+
* removeBracketedDirectories: true,
|
|
102
|
+
* ignoreDirectories: ['lib', 'utils'],
|
|
103
|
+
* ignoreIncludesRootDirectories: true, // Auto-ignores root directories from includes
|
|
104
104
|
* lowercaseNamespace: true,
|
|
105
105
|
* fallbackNamespace: 'common'
|
|
106
106
|
* })
|
package/algorithms/index.cjs
CHANGED
|
@@ -22,9 +22,9 @@ const caseLib__namespace = /* @__PURE__ */ _interopNamespaceDefault(caseLib);
|
|
|
22
22
|
function pathBasedConfigGenerator(options = {}) {
|
|
23
23
|
const {
|
|
24
24
|
includeFileName = false,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
removeBracketedDirectories = true,
|
|
26
|
+
ignoreDirectories = [],
|
|
27
|
+
ignoreIncludesRootDirectories = false,
|
|
28
28
|
ignoreStructured = {},
|
|
29
29
|
lowercaseNamespace = false,
|
|
30
30
|
namespaceCase,
|
|
@@ -35,10 +35,10 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
35
35
|
return async (event) => {
|
|
36
36
|
const { relativePath, langTagConfig } = event;
|
|
37
37
|
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
38
|
-
let
|
|
39
|
-
if (
|
|
40
|
-
const
|
|
41
|
-
|
|
38
|
+
let finalIgnoreDirectories = [...ignoreDirectories];
|
|
39
|
+
if (ignoreIncludesRootDirectories && langTagConfig.includes) {
|
|
40
|
+
const extractedDirectories = extractRootDirectoriesFromIncludes(langTagConfig.includes);
|
|
41
|
+
finalIgnoreDirectories = [.../* @__PURE__ */ new Set([...finalIgnoreDirectories, ...extractedDirectories])];
|
|
42
42
|
}
|
|
43
43
|
let pathSegments = relativePath.split(path.sep).filter(Boolean);
|
|
44
44
|
if (pathSegments.length === 0) {
|
|
@@ -54,12 +54,12 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
54
54
|
pathSegments = pathSegments.map((segment) => {
|
|
55
55
|
const bracketMatch = segment.match(/^[\(\[](.+)[\)\]]$/);
|
|
56
56
|
if (bracketMatch) {
|
|
57
|
-
return
|
|
57
|
+
return removeBracketedDirectories ? null : bracketMatch[1];
|
|
58
58
|
}
|
|
59
59
|
return segment;
|
|
60
60
|
}).filter((seg) => seg !== null);
|
|
61
61
|
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
62
|
-
pathSegments = pathSegments.filter((seg) => !
|
|
62
|
+
pathSegments = pathSegments.filter((seg) => !finalIgnoreDirectories.includes(seg));
|
|
63
63
|
let namespace;
|
|
64
64
|
let path$1;
|
|
65
65
|
if (pathSegments.length >= 1) {
|
|
@@ -139,8 +139,8 @@ function applyCaseTransform(str, caseType) {
|
|
|
139
139
|
}
|
|
140
140
|
return str;
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
const
|
|
142
|
+
function extractRootDirectoriesFromIncludes(includes) {
|
|
143
|
+
const directories = /* @__PURE__ */ new Set();
|
|
144
144
|
for (const pattern of includes) {
|
|
145
145
|
let cleanPattern = pattern.replace(/^\.\//, "");
|
|
146
146
|
const match = cleanPattern.match(/^([^/]+)/);
|
|
@@ -148,12 +148,12 @@ function extractRootFoldersFromIncludes(includes) {
|
|
|
148
148
|
const firstSegment = match[1];
|
|
149
149
|
const groupMatch = firstSegment.match(/^[\(\[]([^\)\]]+)[\)\]]$/);
|
|
150
150
|
if (groupMatch) {
|
|
151
|
-
const
|
|
152
|
-
|
|
151
|
+
const groupDirectories = groupMatch[1].split("|").map((f) => f.trim());
|
|
152
|
+
groupDirectories.forEach((directory) => directories.add(directory));
|
|
153
153
|
} else {
|
|
154
|
-
|
|
154
|
+
directories.add(firstSegment);
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
return Array.from(
|
|
157
|
+
return Array.from(directories);
|
|
158
158
|
}
|
|
159
159
|
exports.pathBasedConfigGenerator = pathBasedConfigGenerator;
|
package/algorithms/index.js
CHANGED
|
@@ -3,9 +3,9 @@ import * as caseLib from "case";
|
|
|
3
3
|
function pathBasedConfigGenerator(options = {}) {
|
|
4
4
|
const {
|
|
5
5
|
includeFileName = false,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
removeBracketedDirectories = true,
|
|
7
|
+
ignoreDirectories = [],
|
|
8
|
+
ignoreIncludesRootDirectories = false,
|
|
9
9
|
ignoreStructured = {},
|
|
10
10
|
lowercaseNamespace = false,
|
|
11
11
|
namespaceCase,
|
|
@@ -16,10 +16,10 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
16
16
|
return async (event) => {
|
|
17
17
|
const { relativePath, langTagConfig } = event;
|
|
18
18
|
const actualFallbackNamespace = fallbackNamespace ?? langTagConfig.collect?.defaultNamespace;
|
|
19
|
-
let
|
|
20
|
-
if (
|
|
21
|
-
const
|
|
22
|
-
|
|
19
|
+
let finalIgnoreDirectories = [...ignoreDirectories];
|
|
20
|
+
if (ignoreIncludesRootDirectories && langTagConfig.includes) {
|
|
21
|
+
const extractedDirectories = extractRootDirectoriesFromIncludes(langTagConfig.includes);
|
|
22
|
+
finalIgnoreDirectories = [.../* @__PURE__ */ new Set([...finalIgnoreDirectories, ...extractedDirectories])];
|
|
23
23
|
}
|
|
24
24
|
let pathSegments = relativePath.split(sep).filter(Boolean);
|
|
25
25
|
if (pathSegments.length === 0) {
|
|
@@ -35,12 +35,12 @@ function pathBasedConfigGenerator(options = {}) {
|
|
|
35
35
|
pathSegments = pathSegments.map((segment) => {
|
|
36
36
|
const bracketMatch = segment.match(/^[\(\[](.+)[\)\]]$/);
|
|
37
37
|
if (bracketMatch) {
|
|
38
|
-
return
|
|
38
|
+
return removeBracketedDirectories ? null : bracketMatch[1];
|
|
39
39
|
}
|
|
40
40
|
return segment;
|
|
41
41
|
}).filter((seg) => seg !== null);
|
|
42
42
|
pathSegments = applyStructuredIgnore(pathSegments, ignoreStructured);
|
|
43
|
-
pathSegments = pathSegments.filter((seg) => !
|
|
43
|
+
pathSegments = pathSegments.filter((seg) => !finalIgnoreDirectories.includes(seg));
|
|
44
44
|
let namespace;
|
|
45
45
|
let path;
|
|
46
46
|
if (pathSegments.length >= 1) {
|
|
@@ -120,8 +120,8 @@ function applyCaseTransform(str, caseType) {
|
|
|
120
120
|
}
|
|
121
121
|
return str;
|
|
122
122
|
}
|
|
123
|
-
function
|
|
124
|
-
const
|
|
123
|
+
function extractRootDirectoriesFromIncludes(includes) {
|
|
124
|
+
const directories = /* @__PURE__ */ new Set();
|
|
125
125
|
for (const pattern of includes) {
|
|
126
126
|
let cleanPattern = pattern.replace(/^\.\//, "");
|
|
127
127
|
const match = cleanPattern.match(/^([^/]+)/);
|
|
@@ -129,13 +129,13 @@ function extractRootFoldersFromIncludes(includes) {
|
|
|
129
129
|
const firstSegment = match[1];
|
|
130
130
|
const groupMatch = firstSegment.match(/^[\(\[]([^\)\]]+)[\)\]]$/);
|
|
131
131
|
if (groupMatch) {
|
|
132
|
-
const
|
|
133
|
-
|
|
132
|
+
const groupDirectories = groupMatch[1].split("|").map((f) => f.trim());
|
|
133
|
+
groupDirectories.forEach((directory) => directories.add(directory));
|
|
134
134
|
} else {
|
|
135
|
-
|
|
135
|
+
directories.add(firstSegment);
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
|
-
return Array.from(
|
|
138
|
+
return Array.from(directories);
|
|
139
139
|
}
|
|
140
140
|
export {
|
|
141
141
|
pathBasedConfigGenerator
|
package/index.cjs
CHANGED
|
@@ -1422,12 +1422,12 @@ async function generateDefaultConfig() {
|
|
|
1422
1422
|
return `${importStatement}
|
|
1423
1423
|
|
|
1424
1424
|
const generationAlgorithm = pathBasedConfigGenerator({
|
|
1425
|
-
|
|
1426
|
-
|
|
1425
|
+
ignoreIncludesRootDirectories: true,
|
|
1426
|
+
removeBracketedDirectories: true,
|
|
1427
1427
|
namespaceCase: 'kebab',
|
|
1428
1428
|
pathCase: 'camel',
|
|
1429
1429
|
clearOnDefaultNamespace: true,
|
|
1430
|
-
|
|
1430
|
+
ignoreDirectories: ['core', 'utils', 'helpers']
|
|
1431
1431
|
});
|
|
1432
1432
|
|
|
1433
1433
|
/** @type {import('@lang-tag/cli/config').LangTagCLIConfig} */
|
package/index.js
CHANGED
|
@@ -1402,12 +1402,12 @@ async function generateDefaultConfig() {
|
|
|
1402
1402
|
return `${importStatement}
|
|
1403
1403
|
|
|
1404
1404
|
const generationAlgorithm = pathBasedConfigGenerator({
|
|
1405
|
-
|
|
1406
|
-
|
|
1405
|
+
ignoreIncludesRootDirectories: true,
|
|
1406
|
+
removeBracketedDirectories: true,
|
|
1407
1407
|
namespaceCase: 'kebab',
|
|
1408
1408
|
pathCase: 'camel',
|
|
1409
1409
|
clearOnDefaultNamespace: true,
|
|
1410
|
-
|
|
1410
|
+
ignoreDirectories: ['core', 'utils', 'helpers']
|
|
1411
1411
|
});
|
|
1412
1412
|
|
|
1413
1413
|
/** @type {import('@lang-tag/cli/config').LangTagCLIConfig} */
|