nestjs-ddd-cli 2.2.0 → 3.2.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 +247 -408
- package/ddd.schema.json +111 -0
- package/dist/commands/aggregate-validator.d.ts +9 -0
- package/dist/commands/aggregate-validator.js +953 -0
- package/dist/commands/aggregate-validator.js.map +1 -0
- package/dist/commands/ai-assist.d.ts +8 -0
- package/dist/commands/ai-assist.js +337 -0
- package/dist/commands/ai-assist.js.map +1 -0
- package/dist/commands/api-contracts.d.ts +9 -0
- package/dist/commands/api-contracts.js +1368 -0
- package/dist/commands/api-contracts.js.map +1 -0
- package/dist/commands/api-docs.d.ts +8 -0
- package/dist/commands/api-docs.js +408 -0
- package/dist/commands/api-docs.js.map +1 -0
- package/dist/commands/api-versioning.d.ts +11 -0
- package/dist/commands/api-versioning.js +643 -0
- package/dist/commands/api-versioning.js.map +1 -0
- package/dist/commands/audit-logging.d.ts +9 -0
- package/dist/commands/audit-logging.js +1129 -0
- package/dist/commands/audit-logging.js.map +1 -0
- package/dist/commands/batch-generate.d.ts +10 -0
- package/dist/commands/batch-generate.js +405 -0
- package/dist/commands/batch-generate.js.map +1 -0
- package/dist/commands/caching-strategies.d.ts +9 -0
- package/dist/commands/caching-strategies.js +874 -0
- package/dist/commands/caching-strategies.js.map +1 -0
- package/dist/commands/code-analyzer.d.ts +42 -0
- package/dist/commands/code-analyzer.js +474 -0
- package/dist/commands/code-analyzer.js.map +1 -0
- package/dist/commands/database-seeding.d.ts +6 -0
- package/dist/commands/database-seeding.js +621 -0
- package/dist/commands/database-seeding.js.map +1 -0
- package/dist/commands/db-optimization.d.ts +7 -0
- package/dist/commands/db-optimization.js +687 -0
- package/dist/commands/db-optimization.js.map +1 -0
- package/dist/commands/dependency-graph.d.ts +6 -0
- package/dist/commands/dependency-graph.js +329 -0
- package/dist/commands/dependency-graph.js.map +1 -0
- package/dist/commands/doctor-enhanced.d.ts +22 -0
- package/dist/commands/doctor-enhanced.js +543 -0
- package/dist/commands/doctor-enhanced.js.map +1 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +151 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/env-manager.d.ts +6 -0
- package/dist/commands/env-manager.js +419 -0
- package/dist/commands/env-manager.js.map +1 -0
- package/dist/commands/event-sourcing-full.d.ts +10 -0
- package/dist/commands/event-sourcing-full.js +1107 -0
- package/dist/commands/event-sourcing-full.js.map +1 -0
- package/dist/commands/feature-flags.d.ts +9 -0
- package/dist/commands/feature-flags.js +824 -0
- package/dist/commands/feature-flags.js.map +1 -0
- package/dist/commands/filter-dsl.d.ts +10 -0
- package/dist/commands/filter-dsl.js +1407 -0
- package/dist/commands/filter-dsl.js.map +1 -0
- package/dist/commands/generate-all.js +485 -32
- package/dist/commands/generate-all.js.map +1 -1
- package/dist/commands/generate-deployment.d.ts +8 -0
- package/dist/commands/generate-deployment.js +746 -0
- package/dist/commands/generate-deployment.js.map +1 -0
- package/dist/commands/generate-domain-service.d.ts +14 -0
- package/dist/commands/generate-domain-service.js +796 -0
- package/dist/commands/generate-domain-service.js.map +1 -0
- package/dist/commands/generate-entity.js +82 -24
- package/dist/commands/generate-entity.js.map +1 -1
- package/dist/commands/generate-from-schema.d.ts +56 -0
- package/dist/commands/generate-from-schema.js +222 -0
- package/dist/commands/generate-from-schema.js.map +1 -0
- package/dist/commands/generate-orchestrator.d.ts +14 -0
- package/dist/commands/generate-orchestrator.js +887 -0
- package/dist/commands/generate-orchestrator.js.map +1 -0
- package/dist/commands/generate-repository.d.ts +14 -0
- package/dist/commands/generate-repository.js +1019 -0
- package/dist/commands/generate-repository.js.map +1 -0
- package/dist/commands/generate-shared.d.ts +4 -0
- package/dist/commands/generate-shared.js +388 -0
- package/dist/commands/generate-shared.js.map +1 -0
- package/dist/commands/generate-value-object.d.ts +32 -0
- package/dist/commands/generate-value-object.js +700 -0
- package/dist/commands/generate-value-object.js.map +1 -0
- package/dist/commands/graphql-subscriptions.d.ts +6 -0
- package/dist/commands/graphql-subscriptions.js +607 -0
- package/dist/commands/graphql-subscriptions.js.map +1 -0
- package/dist/commands/graphql-types.d.ts +5 -0
- package/dist/commands/graphql-types.js +423 -0
- package/dist/commands/graphql-types.js.map +1 -0
- package/dist/commands/health-probes-advanced.d.ts +6 -0
- package/dist/commands/health-probes-advanced.js +655 -0
- package/dist/commands/health-probes-advanced.js.map +1 -0
- package/dist/commands/i18n-setup.d.ts +10 -0
- package/dist/commands/i18n-setup.js +677 -0
- package/dist/commands/i18n-setup.js.map +1 -0
- package/dist/commands/init-config.d.ts +6 -0
- package/dist/commands/init-config.js +370 -0
- package/dist/commands/init-config.js.map +1 -0
- package/dist/commands/init-project.js +56 -6
- package/dist/commands/init-project.js.map +1 -1
- package/dist/commands/interactive-scaffold.d.ts +5 -0
- package/dist/commands/interactive-scaffold.js +271 -0
- package/dist/commands/interactive-scaffold.js.map +1 -0
- package/dist/commands/metrics-prometheus.d.ts +6 -0
- package/dist/commands/metrics-prometheus.js +681 -0
- package/dist/commands/metrics-prometheus.js.map +1 -0
- package/dist/commands/migration-engine.d.ts +6 -0
- package/dist/commands/migration-engine.js +446 -0
- package/dist/commands/migration-engine.js.map +1 -0
- package/dist/commands/migration.d.ts +12 -0
- package/dist/commands/migration.js +484 -0
- package/dist/commands/migration.js.map +1 -0
- package/dist/commands/monorepo.d.ts +8 -0
- package/dist/commands/monorepo.js +483 -0
- package/dist/commands/monorepo.js.map +1 -0
- package/dist/commands/multi-database.d.ts +5 -0
- package/dist/commands/multi-database.js +439 -0
- package/dist/commands/multi-database.js.map +1 -0
- package/dist/commands/observability-tracing.d.ts +10 -0
- package/dist/commands/observability-tracing.js +740 -0
- package/dist/commands/observability-tracing.js.map +1 -0
- package/dist/commands/openapi-export.d.ts +8 -0
- package/dist/commands/openapi-export.js +359 -0
- package/dist/commands/openapi-export.js.map +1 -0
- package/dist/commands/perf-analyzer.d.ts +8 -0
- package/dist/commands/perf-analyzer.js +423 -0
- package/dist/commands/perf-analyzer.js.map +1 -0
- package/dist/commands/rate-limiting.d.ts +10 -0
- package/dist/commands/rate-limiting.js +953 -0
- package/dist/commands/rate-limiting.js.map +1 -0
- package/dist/commands/recipe-plugin.d.ts +56 -0
- package/dist/commands/recipe-plugin.js +315 -0
- package/dist/commands/recipe-plugin.js.map +1 -0
- package/dist/commands/recipe.d.ts +6 -0
- package/dist/commands/recipe.js +3941 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
- package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
- package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
- package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
- package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
- package/dist/commands/recipes/index.d.ts +7 -0
- package/dist/commands/recipes/index.js +24 -0
- package/dist/commands/recipes/index.js.map +1 -0
- package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
- package/dist/commands/recipes/message-queue.recipe.js +706 -0
- package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
- package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
- package/dist/commands/recipes/middleware.recipe.js +383 -0
- package/dist/commands/recipes/middleware.recipe.js.map +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
- package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
- package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
- package/dist/commands/recipes/oauth2.recipe.js +472 -0
- package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
- package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
- package/dist/commands/recipes/websocket.recipe.js +453 -0
- package/dist/commands/recipes/websocket.recipe.js.map +1 -0
- package/dist/commands/resilience-patterns.d.ts +13 -0
- package/dist/commands/resilience-patterns.js +1029 -0
- package/dist/commands/resilience-patterns.js.map +1 -0
- package/dist/commands/security-patterns.d.ts +11 -0
- package/dist/commands/security-patterns.js +2233 -0
- package/dist/commands/security-patterns.js.map +1 -0
- package/dist/commands/template-debug.d.ts +27 -0
- package/dist/commands/template-debug.js +388 -0
- package/dist/commands/template-debug.js.map +1 -0
- package/dist/commands/test-factory-full.d.ts +9 -0
- package/dist/commands/test-factory-full.js +1570 -0
- package/dist/commands/test-factory-full.js.map +1 -0
- package/dist/commands/test-scaffold.d.ts +7 -0
- package/dist/commands/test-scaffold.js +621 -0
- package/dist/commands/test-scaffold.js.map +1 -0
- package/dist/index.js +1088 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
- package/dist/templates/ai-context/conventions.md.hbs +154 -0
- package/dist/templates/command/create-command.hbs +6 -14
- package/dist/templates/command/delete-command.hbs +19 -0
- package/dist/templates/command/update-command.hbs +24 -0
- package/dist/templates/controller/controller.hbs +64 -17
- package/dist/templates/dto/create-dto.hbs +29 -5
- package/dist/templates/dto/filter-dto.hbs +52 -0
- package/dist/templates/dto/filter-query.dto.hbs +148 -0
- package/dist/templates/dto/paginated-response.dto.hbs +29 -0
- package/dist/templates/dto/pagination-query.dto.hbs +30 -0
- package/dist/templates/dto/response-dto.hbs +38 -0
- package/dist/templates/dto/update-dto.hbs +11 -0
- package/dist/templates/entity/entity.hbs +32 -1
- package/dist/templates/event/domain-event.hbs +33 -7
- package/dist/templates/event/event-handler.hbs +40 -0
- package/dist/templates/exception/base-exceptions.hbs +69 -0
- package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
- package/dist/templates/mapper/mapper.hbs +49 -24
- package/dist/templates/module/module.hbs +34 -10
- package/dist/templates/orm-entity/orm-entity.hbs +63 -12
- package/dist/templates/prisma/prisma-mapper.hbs +71 -0
- package/dist/templates/prisma/prisma-repository.hbs +114 -0
- package/dist/templates/prisma/prisma-schema.hbs +20 -0
- package/dist/templates/prisma/prisma-service.hbs +51 -0
- package/dist/templates/query/get-all.query.hbs +50 -0
- package/dist/templates/query/get-by-id.query.hbs +31 -0
- package/dist/templates/repository/repository.hbs +55 -13
- package/dist/templates/resolver/graphql-input.hbs +54 -0
- package/dist/templates/resolver/graphql-type.hbs +58 -0
- package/dist/templates/resolver/pagination-args.hbs +33 -0
- package/dist/templates/resolver/resolver.hbs +62 -0
- package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
- package/dist/templates/shared/query-builder.util.hbs +218 -0
- package/dist/templates/test/controller.spec.hbs +124 -0
- package/dist/templates/test/repository.spec.hbs +158 -0
- package/dist/templates/test/usecase.spec.hbs +116 -0
- package/dist/templates/usecase/create-usecase.hbs +19 -7
- package/dist/templates/usecase/delete-usecase.hbs +17 -0
- package/dist/templates/usecase/update-usecase.hbs +31 -0
- package/dist/utils/config.utils.d.ts +45 -0
- package/dist/utils/config.utils.js +211 -0
- package/dist/utils/config.utils.js.map +1 -0
- package/dist/utils/error.utils.d.ts +145 -0
- package/dist/utils/error.utils.js +422 -0
- package/dist/utils/error.utils.js.map +1 -0
- package/dist/utils/field.utils.d.ts +54 -0
- package/dist/utils/field.utils.js +389 -0
- package/dist/utils/field.utils.js.map +1 -0
- package/dist/utils/file.utils.d.ts +19 -8
- package/dist/utils/file.utils.js +135 -4
- package/dist/utils/file.utils.js.map +1 -1
- package/dist/utils/idempotency.utils.d.ts +123 -0
- package/dist/utils/idempotency.utils.js +444 -0
- package/dist/utils/idempotency.utils.js.map +1 -0
- package/dist/utils/naming.utils.js +26 -3
- package/dist/utils/naming.utils.js.map +1 -1
- package/dist/utils/performance.utils.d.ts +37 -0
- package/dist/utils/performance.utils.js +158 -0
- package/dist/utils/performance.utils.js.map +1 -0
- package/dist/utils/relation.utils.d.ts +92 -0
- package/dist/utils/relation.utils.js +388 -0
- package/dist/utils/relation.utils.js.map +1 -0
- package/dist/utils/rollback.utils.d.ts +49 -0
- package/dist/utils/rollback.utils.js +306 -0
- package/dist/utils/rollback.utils.js.map +1 -0
- package/dist/utils/schema.utils.d.ts +123 -0
- package/dist/utils/schema.utils.js +419 -0
- package/dist/utils/schema.utils.js.map +1 -0
- package/dist/utils/security.utils.d.ts +57 -0
- package/dist/utils/security.utils.js +315 -0
- package/dist/utils/security.utils.js.map +1 -0
- package/dist/utils/template-engine.utils.d.ts +80 -0
- package/dist/utils/template-engine.utils.js +463 -0
- package/dist/utils/template-engine.utils.js.map +1 -0
- package/dist/utils/validation-registry.utils.d.ts +160 -0
- package/dist/utils/validation-registry.utils.js +526 -0
- package/dist/utils/validation-registry.utils.js.map +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Internationalization (i18n) & Localization Engine Generator
|
|
4
|
+
* Generates comprehensive i18n infrastructure
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.setupI18n = setupI18n;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
47
|
+
async function setupI18n(basePath, options = {}) {
|
|
48
|
+
console.log(chalk_1.default.bold.blue('\n🌍 Setting up i18n Infrastructure\n'));
|
|
49
|
+
const sharedPath = path.join(basePath, 'src/shared/i18n');
|
|
50
|
+
const localesPath = path.join(basePath, 'src/locales');
|
|
51
|
+
for (const dir of [sharedPath, localesPath]) {
|
|
52
|
+
if (!fs.existsSync(dir)) {
|
|
53
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Generate i18n module
|
|
57
|
+
const moduleContent = generateI18nModule(options);
|
|
58
|
+
fs.writeFileSync(path.join(sharedPath, 'i18n.module.ts'), moduleContent);
|
|
59
|
+
console.log(chalk_1.default.green(` ✓ Created i18n module`));
|
|
60
|
+
// Generate i18n service
|
|
61
|
+
const serviceContent = generateI18nService();
|
|
62
|
+
fs.writeFileSync(path.join(sharedPath, 'i18n.service.ts'), serviceContent);
|
|
63
|
+
console.log(chalk_1.default.green(` ✓ Created i18n service`));
|
|
64
|
+
// Generate translation loader
|
|
65
|
+
const loaderContent = generateTranslationLoader();
|
|
66
|
+
fs.writeFileSync(path.join(sharedPath, 'translation.loader.ts'), loaderContent);
|
|
67
|
+
console.log(chalk_1.default.green(` ✓ Created translation loader`));
|
|
68
|
+
// Generate locale interceptor
|
|
69
|
+
const interceptorContent = generateLocaleInterceptor();
|
|
70
|
+
fs.writeFileSync(path.join(sharedPath, 'locale.interceptor.ts'), interceptorContent);
|
|
71
|
+
console.log(chalk_1.default.green(` ✓ Created locale interceptor`));
|
|
72
|
+
// Generate i18n decorators
|
|
73
|
+
const decoratorContent = generateI18nDecorators();
|
|
74
|
+
fs.writeFileSync(path.join(sharedPath, 'i18n.decorators.ts'), decoratorContent);
|
|
75
|
+
console.log(chalk_1.default.green(` ✓ Created i18n decorators`));
|
|
76
|
+
// Generate sample locale files
|
|
77
|
+
generateSampleLocales(localesPath, options);
|
|
78
|
+
console.log(chalk_1.default.bold.green('\n✅ i18n infrastructure ready!\n'));
|
|
79
|
+
}
|
|
80
|
+
function generateI18nModule(options) {
|
|
81
|
+
const defaultLocale = options.defaultLocale || 'en';
|
|
82
|
+
const supportedLocales = options.supportedLocales || ['en', 'fr', 'es'];
|
|
83
|
+
return `import { Module, Global, DynamicModule } from '@nestjs/common';
|
|
84
|
+
import { APP_INTERCEPTOR } from '@nestjs/core';
|
|
85
|
+
import { I18nService } from './i18n.service';
|
|
86
|
+
import { TranslationLoader } from './translation.loader';
|
|
87
|
+
import { LocaleInterceptor } from './locale.interceptor';
|
|
88
|
+
|
|
89
|
+
export interface I18nModuleOptions {
|
|
90
|
+
defaultLocale: string;
|
|
91
|
+
supportedLocales: string[];
|
|
92
|
+
fallbackLocale?: string;
|
|
93
|
+
localesPath: string;
|
|
94
|
+
resolvers?: LocaleResolver[];
|
|
95
|
+
enableCaching?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type LocaleResolver = 'header' | 'query' | 'cookie' | 'accept-language';
|
|
99
|
+
|
|
100
|
+
@Global()
|
|
101
|
+
@Module({})
|
|
102
|
+
export class I18nModule {
|
|
103
|
+
static forRoot(options: I18nModuleOptions): DynamicModule {
|
|
104
|
+
return {
|
|
105
|
+
module: I18nModule,
|
|
106
|
+
providers: [
|
|
107
|
+
{
|
|
108
|
+
provide: 'I18N_OPTIONS',
|
|
109
|
+
useValue: options,
|
|
110
|
+
},
|
|
111
|
+
TranslationLoader,
|
|
112
|
+
I18nService,
|
|
113
|
+
{
|
|
114
|
+
provide: APP_INTERCEPTOR,
|
|
115
|
+
useClass: LocaleInterceptor,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
exports: [I18nService, TranslationLoader],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Default i18n configuration
|
|
125
|
+
*/
|
|
126
|
+
export const DEFAULT_I18N_OPTIONS: Partial<I18nModuleOptions> = {
|
|
127
|
+
defaultLocale: '${defaultLocale}',
|
|
128
|
+
supportedLocales: ${JSON.stringify(supportedLocales)},
|
|
129
|
+
fallbackLocale: '${defaultLocale}',
|
|
130
|
+
resolvers: ['header', 'accept-language'],
|
|
131
|
+
enableCaching: true,
|
|
132
|
+
};
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
function generateI18nService() {
|
|
136
|
+
return `import { Injectable, Inject, Logger, OnModuleInit } from '@nestjs/common';
|
|
137
|
+
import { TranslationLoader } from './translation.loader';
|
|
138
|
+
|
|
139
|
+
export interface TranslateOptions {
|
|
140
|
+
locale?: string;
|
|
141
|
+
defaultValue?: string;
|
|
142
|
+
args?: Record<string, any>;
|
|
143
|
+
count?: number;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@Injectable()
|
|
147
|
+
export class I18nService implements OnModuleInit {
|
|
148
|
+
private readonly logger = new Logger(I18nService.name);
|
|
149
|
+
private currentLocale: string;
|
|
150
|
+
private translations: Map<string, Record<string, any>> = new Map();
|
|
151
|
+
|
|
152
|
+
constructor(
|
|
153
|
+
@Inject('I18N_OPTIONS') private readonly options: any,
|
|
154
|
+
private readonly loader: TranslationLoader,
|
|
155
|
+
) {
|
|
156
|
+
this.currentLocale = options.defaultLocale;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async onModuleInit() {
|
|
160
|
+
await this.loadTranslations();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private async loadTranslations(): Promise<void> {
|
|
164
|
+
for (const locale of this.options.supportedLocales) {
|
|
165
|
+
try {
|
|
166
|
+
const translations = await this.loader.load(locale);
|
|
167
|
+
this.translations.set(locale, translations);
|
|
168
|
+
this.logger.log(\`Loaded translations for locale: \${locale}\`);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
this.logger.warn(\`Failed to load translations for locale: \${locale}\`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Translate a key
|
|
177
|
+
*/
|
|
178
|
+
t(key: string, options?: TranslateOptions): string {
|
|
179
|
+
const locale = options?.locale || this.currentLocale;
|
|
180
|
+
const translations = this.translations.get(locale);
|
|
181
|
+
|
|
182
|
+
if (!translations) {
|
|
183
|
+
return this.fallback(key, options);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let value = this.getNestedValue(translations, key);
|
|
187
|
+
|
|
188
|
+
if (value === undefined) {
|
|
189
|
+
return this.fallback(key, options);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Handle pluralization
|
|
193
|
+
if (typeof value === 'object' && options?.count !== undefined) {
|
|
194
|
+
value = this.pluralize(value, options.count);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Handle interpolation
|
|
198
|
+
if (options?.args) {
|
|
199
|
+
value = this.interpolate(value, options.args);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return value;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Translate with context
|
|
207
|
+
*/
|
|
208
|
+
translate(key: string, options?: TranslateOptions): string {
|
|
209
|
+
return this.t(key, options);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Check if translation exists
|
|
214
|
+
*/
|
|
215
|
+
exists(key: string, locale?: string): boolean {
|
|
216
|
+
const translations = this.translations.get(locale || this.currentLocale);
|
|
217
|
+
return translations ? this.getNestedValue(translations, key) !== undefined : false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get all translations for a namespace
|
|
222
|
+
*/
|
|
223
|
+
getNamespace(namespace: string, locale?: string): Record<string, any> {
|
|
224
|
+
const translations = this.translations.get(locale || this.currentLocale);
|
|
225
|
+
return translations ? this.getNestedValue(translations, namespace) || {} : {};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Set current locale
|
|
230
|
+
*/
|
|
231
|
+
setLocale(locale: string): void {
|
|
232
|
+
if (this.options.supportedLocales.includes(locale)) {
|
|
233
|
+
this.currentLocale = locale;
|
|
234
|
+
} else {
|
|
235
|
+
this.logger.warn(\`Unsupported locale: \${locale}\`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get current locale
|
|
241
|
+
*/
|
|
242
|
+
getLocale(): string {
|
|
243
|
+
return this.currentLocale;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get supported locales
|
|
248
|
+
*/
|
|
249
|
+
getSupportedLocales(): string[] {
|
|
250
|
+
return this.options.supportedLocales;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Format date
|
|
255
|
+
*/
|
|
256
|
+
formatDate(date: Date, format?: Intl.DateTimeFormatOptions, locale?: string): string {
|
|
257
|
+
return new Intl.DateTimeFormat(locale || this.currentLocale, format).format(date);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Format number
|
|
262
|
+
*/
|
|
263
|
+
formatNumber(value: number, options?: Intl.NumberFormatOptions, locale?: string): string {
|
|
264
|
+
return new Intl.NumberFormat(locale || this.currentLocale, options).format(value);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Format currency
|
|
269
|
+
*/
|
|
270
|
+
formatCurrency(amount: number, currency: string, locale?: string): string {
|
|
271
|
+
return new Intl.NumberFormat(locale || this.currentLocale, {
|
|
272
|
+
style: 'currency',
|
|
273
|
+
currency,
|
|
274
|
+
}).format(amount);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Format relative time
|
|
279
|
+
*/
|
|
280
|
+
formatRelativeTime(value: number, unit: Intl.RelativeTimeFormatUnit, locale?: string): string {
|
|
281
|
+
return new Intl.RelativeTimeFormat(locale || this.currentLocale, {
|
|
282
|
+
numeric: 'auto',
|
|
283
|
+
}).format(value, unit);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private fallback(key: string, options?: TranslateOptions): string {
|
|
287
|
+
// Try fallback locale
|
|
288
|
+
if (this.options.fallbackLocale && this.options.fallbackLocale !== this.currentLocale) {
|
|
289
|
+
const fallbackTranslations = this.translations.get(this.options.fallbackLocale);
|
|
290
|
+
if (fallbackTranslations) {
|
|
291
|
+
const value = this.getNestedValue(fallbackTranslations, key);
|
|
292
|
+
if (value !== undefined) {
|
|
293
|
+
return typeof value === 'string' ? value : key;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return options?.defaultValue || key;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private getNestedValue(obj: Record<string, any>, path: string): any {
|
|
302
|
+
return path.split('.').reduce((current, key) => {
|
|
303
|
+
return current && current[key] !== undefined ? current[key] : undefined;
|
|
304
|
+
}, obj);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
private pluralize(value: Record<string, string>, count: number): string {
|
|
308
|
+
if (count === 0 && value.zero) return value.zero;
|
|
309
|
+
if (count === 1 && value.one) return value.one;
|
|
310
|
+
if (value.other) return value.other;
|
|
311
|
+
return Object.values(value)[0] || '';
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private interpolate(text: string, args: Record<string, any>): string {
|
|
315
|
+
return text.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key) => {
|
|
316
|
+
return args[key] !== undefined ? String(args[key]) : match;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Reload translations
|
|
322
|
+
*/
|
|
323
|
+
async reload(): Promise<void> {
|
|
324
|
+
this.translations.clear();
|
|
325
|
+
await this.loadTranslations();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
`;
|
|
329
|
+
}
|
|
330
|
+
function generateTranslationLoader() {
|
|
331
|
+
return `import { Injectable, Inject, Logger } from '@nestjs/common';
|
|
332
|
+
import * as fs from 'fs';
|
|
333
|
+
import * as path from 'path';
|
|
334
|
+
|
|
335
|
+
@Injectable()
|
|
336
|
+
export class TranslationLoader {
|
|
337
|
+
private readonly logger = new Logger(TranslationLoader.name);
|
|
338
|
+
private cache: Map<string, Record<string, any>> = new Map();
|
|
339
|
+
|
|
340
|
+
constructor(@Inject('I18N_OPTIONS') private readonly options: any) {}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Load translations for a locale
|
|
344
|
+
*/
|
|
345
|
+
async load(locale: string): Promise<Record<string, any>> {
|
|
346
|
+
// Check cache
|
|
347
|
+
if (this.options.enableCaching && this.cache.has(locale)) {
|
|
348
|
+
return this.cache.get(locale)!;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const translations: Record<string, any> = {};
|
|
352
|
+
const localeDir = path.join(this.options.localesPath, locale);
|
|
353
|
+
|
|
354
|
+
if (!fs.existsSync(localeDir)) {
|
|
355
|
+
// Try single file format
|
|
356
|
+
const singleFile = path.join(this.options.localesPath, \`\${locale}.json\`);
|
|
357
|
+
if (fs.existsSync(singleFile)) {
|
|
358
|
+
const content = fs.readFileSync(singleFile, 'utf-8');
|
|
359
|
+
const parsed = JSON.parse(content);
|
|
360
|
+
if (this.options.enableCaching) {
|
|
361
|
+
this.cache.set(locale, parsed);
|
|
362
|
+
}
|
|
363
|
+
return parsed;
|
|
364
|
+
}
|
|
365
|
+
throw new Error(\`Locale directory or file not found: \${locale}\`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Load all JSON files in locale directory
|
|
369
|
+
const files = fs.readdirSync(localeDir).filter(f => f.endsWith('.json'));
|
|
370
|
+
|
|
371
|
+
for (const file of files) {
|
|
372
|
+
const namespace = path.basename(file, '.json');
|
|
373
|
+
const filePath = path.join(localeDir, file);
|
|
374
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
375
|
+
translations[namespace] = JSON.parse(content);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (this.options.enableCaching) {
|
|
379
|
+
this.cache.set(locale, translations);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return translations;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Clear cache
|
|
387
|
+
*/
|
|
388
|
+
clearCache(): void {
|
|
389
|
+
this.cache.clear();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Get available locales
|
|
394
|
+
*/
|
|
395
|
+
getAvailableLocales(): string[] {
|
|
396
|
+
const localesPath = this.options.localesPath;
|
|
397
|
+
|
|
398
|
+
if (!fs.existsSync(localesPath)) {
|
|
399
|
+
return [];
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const entries = fs.readdirSync(localesPath, { withFileTypes: true });
|
|
403
|
+
const locales: string[] = [];
|
|
404
|
+
|
|
405
|
+
for (const entry of entries) {
|
|
406
|
+
if (entry.isDirectory()) {
|
|
407
|
+
locales.push(entry.name);
|
|
408
|
+
} else if (entry.name.endsWith('.json')) {
|
|
409
|
+
locales.push(entry.name.replace('.json', ''));
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return locales;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`;
|
|
417
|
+
}
|
|
418
|
+
function generateLocaleInterceptor() {
|
|
419
|
+
return `import {
|
|
420
|
+
Injectable,
|
|
421
|
+
NestInterceptor,
|
|
422
|
+
ExecutionContext,
|
|
423
|
+
CallHandler,
|
|
424
|
+
Inject,
|
|
425
|
+
} from '@nestjs/common';
|
|
426
|
+
import { Observable } from 'rxjs';
|
|
427
|
+
import { I18nService } from './i18n.service';
|
|
428
|
+
|
|
429
|
+
@Injectable()
|
|
430
|
+
export class LocaleInterceptor implements NestInterceptor {
|
|
431
|
+
constructor(
|
|
432
|
+
private readonly i18n: I18nService,
|
|
433
|
+
@Inject('I18N_OPTIONS') private readonly options: any,
|
|
434
|
+
) {}
|
|
435
|
+
|
|
436
|
+
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
|
|
437
|
+
const request = context.switchToHttp().getRequest();
|
|
438
|
+
const response = context.switchToHttp().getResponse();
|
|
439
|
+
|
|
440
|
+
// Detect locale from request
|
|
441
|
+
const locale = this.detectLocale(request);
|
|
442
|
+
|
|
443
|
+
// Set locale for this request
|
|
444
|
+
request.locale = locale;
|
|
445
|
+
request.i18n = this.i18n;
|
|
446
|
+
|
|
447
|
+
// Set locale header in response
|
|
448
|
+
response.setHeader('Content-Language', locale);
|
|
449
|
+
|
|
450
|
+
return next.handle();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
private detectLocale(request: any): string {
|
|
454
|
+
const resolvers = this.options.resolvers || ['header', 'accept-language'];
|
|
455
|
+
const supportedLocales = this.options.supportedLocales;
|
|
456
|
+
|
|
457
|
+
for (const resolver of resolvers) {
|
|
458
|
+
const locale = this.resolveLocale(resolver, request);
|
|
459
|
+
if (locale && supportedLocales.includes(locale)) {
|
|
460
|
+
return locale;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return this.options.defaultLocale;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private resolveLocale(resolver: string, request: any): string | null {
|
|
468
|
+
switch (resolver) {
|
|
469
|
+
case 'header':
|
|
470
|
+
return request.headers['x-locale'] || request.headers['x-lang'];
|
|
471
|
+
|
|
472
|
+
case 'query':
|
|
473
|
+
return request.query.locale || request.query.lang;
|
|
474
|
+
|
|
475
|
+
case 'cookie':
|
|
476
|
+
return request.cookies?.locale;
|
|
477
|
+
|
|
478
|
+
case 'accept-language':
|
|
479
|
+
return this.parseAcceptLanguage(request.headers['accept-language']);
|
|
480
|
+
|
|
481
|
+
default:
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
private parseAcceptLanguage(header: string | undefined): string | null {
|
|
487
|
+
if (!header) return null;
|
|
488
|
+
|
|
489
|
+
const locales = header.split(',').map(lang => {
|
|
490
|
+
const [locale, priority = 'q=1.0'] = lang.trim().split(';');
|
|
491
|
+
const q = parseFloat(priority.replace('q=', ''));
|
|
492
|
+
return { locale: locale.split('-')[0], priority: q };
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
locales.sort((a, b) => b.priority - a.priority);
|
|
496
|
+
|
|
497
|
+
return locales[0]?.locale || null;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
`;
|
|
501
|
+
}
|
|
502
|
+
function generateI18nDecorators() {
|
|
503
|
+
return `import { createParamDecorator, ExecutionContext, SetMetadata } from '@nestjs/common';
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Get current locale from request
|
|
507
|
+
*/
|
|
508
|
+
export const CurrentLocale = createParamDecorator(
|
|
509
|
+
(data: unknown, ctx: ExecutionContext): string => {
|
|
510
|
+
const request = ctx.switchToHttp().getRequest();
|
|
511
|
+
return request.locale;
|
|
512
|
+
},
|
|
513
|
+
);
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Get i18n service from request
|
|
517
|
+
*/
|
|
518
|
+
export const I18n = createParamDecorator(
|
|
519
|
+
(data: unknown, ctx: ExecutionContext) => {
|
|
520
|
+
const request = ctx.switchToHttp().getRequest();
|
|
521
|
+
return request.i18n;
|
|
522
|
+
},
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Get translation function from request
|
|
527
|
+
*/
|
|
528
|
+
export const T = createParamDecorator(
|
|
529
|
+
(data: unknown, ctx: ExecutionContext) => {
|
|
530
|
+
const request = ctx.switchToHttp().getRequest();
|
|
531
|
+
const locale = request.locale;
|
|
532
|
+
return (key: string, args?: Record<string, any>) => {
|
|
533
|
+
return request.i18n?.t(key, { locale, args }) || key;
|
|
534
|
+
};
|
|
535
|
+
},
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Set required locale for endpoint
|
|
540
|
+
*/
|
|
541
|
+
export function RequireLocale(...locales: string[]) {
|
|
542
|
+
return SetMetadata('requiredLocales', locales);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Mark endpoint as locale-specific
|
|
547
|
+
*/
|
|
548
|
+
export function LocaleSpecific() {
|
|
549
|
+
return SetMetadata('localeSpecific', true);
|
|
550
|
+
}
|
|
551
|
+
`;
|
|
552
|
+
}
|
|
553
|
+
function generateSampleLocales(localesPath, options) {
|
|
554
|
+
const locales = options.supportedLocales || ['en', 'fr', 'es'];
|
|
555
|
+
const translations = {
|
|
556
|
+
en: {
|
|
557
|
+
common: {
|
|
558
|
+
welcome: 'Welcome',
|
|
559
|
+
hello: 'Hello, {{name}}!',
|
|
560
|
+
goodbye: 'Goodbye',
|
|
561
|
+
yes: 'Yes',
|
|
562
|
+
no: 'No',
|
|
563
|
+
save: 'Save',
|
|
564
|
+
cancel: 'Cancel',
|
|
565
|
+
delete: 'Delete',
|
|
566
|
+
edit: 'Edit',
|
|
567
|
+
loading: 'Loading...',
|
|
568
|
+
error: 'An error occurred',
|
|
569
|
+
success: 'Success',
|
|
570
|
+
},
|
|
571
|
+
errors: {
|
|
572
|
+
notFound: 'Resource not found',
|
|
573
|
+
unauthorized: 'Unauthorized access',
|
|
574
|
+
forbidden: 'Access forbidden',
|
|
575
|
+
validation: 'Validation error',
|
|
576
|
+
serverError: 'Internal server error',
|
|
577
|
+
},
|
|
578
|
+
validation: {
|
|
579
|
+
required: '{{field}} is required',
|
|
580
|
+
email: 'Invalid email format',
|
|
581
|
+
minLength: '{{field}} must be at least {{min}} characters',
|
|
582
|
+
maxLength: '{{field}} must not exceed {{max}} characters',
|
|
583
|
+
},
|
|
584
|
+
plurals: {
|
|
585
|
+
items: {
|
|
586
|
+
zero: 'No items',
|
|
587
|
+
one: '1 item',
|
|
588
|
+
other: '{{count}} items',
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
},
|
|
592
|
+
fr: {
|
|
593
|
+
common: {
|
|
594
|
+
welcome: 'Bienvenue',
|
|
595
|
+
hello: 'Bonjour, {{name}} !',
|
|
596
|
+
goodbye: 'Au revoir',
|
|
597
|
+
yes: 'Oui',
|
|
598
|
+
no: 'Non',
|
|
599
|
+
save: 'Enregistrer',
|
|
600
|
+
cancel: 'Annuler',
|
|
601
|
+
delete: 'Supprimer',
|
|
602
|
+
edit: 'Modifier',
|
|
603
|
+
loading: 'Chargement...',
|
|
604
|
+
error: 'Une erreur est survenue',
|
|
605
|
+
success: 'Succès',
|
|
606
|
+
},
|
|
607
|
+
errors: {
|
|
608
|
+
notFound: 'Ressource non trouvée',
|
|
609
|
+
unauthorized: 'Accès non autorisé',
|
|
610
|
+
forbidden: 'Accès interdit',
|
|
611
|
+
validation: 'Erreur de validation',
|
|
612
|
+
serverError: 'Erreur interne du serveur',
|
|
613
|
+
},
|
|
614
|
+
validation: {
|
|
615
|
+
required: '{{field}} est requis',
|
|
616
|
+
email: 'Format email invalide',
|
|
617
|
+
minLength: '{{field}} doit contenir au moins {{min}} caractères',
|
|
618
|
+
maxLength: '{{field}} ne doit pas dépasser {{max}} caractères',
|
|
619
|
+
},
|
|
620
|
+
plurals: {
|
|
621
|
+
items: {
|
|
622
|
+
zero: 'Aucun élément',
|
|
623
|
+
one: '1 élément',
|
|
624
|
+
other: '{{count}} éléments',
|
|
625
|
+
},
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
es: {
|
|
629
|
+
common: {
|
|
630
|
+
welcome: 'Bienvenido',
|
|
631
|
+
hello: '¡Hola, {{name}}!',
|
|
632
|
+
goodbye: 'Adiós',
|
|
633
|
+
yes: 'Sí',
|
|
634
|
+
no: 'No',
|
|
635
|
+
save: 'Guardar',
|
|
636
|
+
cancel: 'Cancelar',
|
|
637
|
+
delete: 'Eliminar',
|
|
638
|
+
edit: 'Editar',
|
|
639
|
+
loading: 'Cargando...',
|
|
640
|
+
error: 'Se produjo un error',
|
|
641
|
+
success: 'Éxito',
|
|
642
|
+
},
|
|
643
|
+
errors: {
|
|
644
|
+
notFound: 'Recurso no encontrado',
|
|
645
|
+
unauthorized: 'Acceso no autorizado',
|
|
646
|
+
forbidden: 'Acceso prohibido',
|
|
647
|
+
validation: 'Error de validación',
|
|
648
|
+
serverError: 'Error interno del servidor',
|
|
649
|
+
},
|
|
650
|
+
validation: {
|
|
651
|
+
required: '{{field}} es requerido',
|
|
652
|
+
email: 'Formato de email inválido',
|
|
653
|
+
minLength: '{{field}} debe tener al menos {{min}} caracteres',
|
|
654
|
+
maxLength: '{{field}} no debe exceder {{max}} caracteres',
|
|
655
|
+
},
|
|
656
|
+
plurals: {
|
|
657
|
+
items: {
|
|
658
|
+
zero: 'Ningún elemento',
|
|
659
|
+
one: '1 elemento',
|
|
660
|
+
other: '{{count}} elementos',
|
|
661
|
+
},
|
|
662
|
+
},
|
|
663
|
+
},
|
|
664
|
+
};
|
|
665
|
+
for (const locale of locales) {
|
|
666
|
+
const localeDir = path.join(localesPath, locale);
|
|
667
|
+
if (!fs.existsSync(localeDir)) {
|
|
668
|
+
fs.mkdirSync(localeDir, { recursive: true });
|
|
669
|
+
}
|
|
670
|
+
const trans = translations[locale] || translations.en;
|
|
671
|
+
for (const [namespace, content] of Object.entries(trans)) {
|
|
672
|
+
fs.writeFileSync(path.join(localeDir, `${namespace}.json`), JSON.stringify(content, null, 2));
|
|
673
|
+
}
|
|
674
|
+
console.log(chalk_1.default.green(` ✓ Created locale files for: ${locale}`));
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
//# sourceMappingURL=i18n-setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n-setup.js","sourceRoot":"","sources":["../../src/commands/i18n-setup.ts"],"names":[],"mappings":"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"}
|