@flusys/nestjs-localization 4.0.0-rc
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 +870 -0
- package/cjs/config/index.js +19 -0
- package/cjs/config/localization.constants.js +20 -0
- package/cjs/config/message-keys.js +77 -0
- package/cjs/controllers/index.js +20 -0
- package/cjs/controllers/language.controller.js +188 -0
- package/cjs/controllers/translation-key.controller.js +174 -0
- package/cjs/controllers/translation.controller.js +254 -0
- package/cjs/dtos/index.js +20 -0
- package/cjs/dtos/language.dto.js +205 -0
- package/cjs/dtos/translation-key.dto.js +233 -0
- package/cjs/dtos/translation.dto.js +298 -0
- package/cjs/entities/index.js +42 -0
- package/cjs/entities/language.entity.js +126 -0
- package/cjs/entities/translation-key.entity.js +125 -0
- package/cjs/entities/translation.entity.js +120 -0
- package/cjs/index.js +24 -0
- package/cjs/interfaces/index.js +21 -0
- package/cjs/interfaces/language.interface.js +4 -0
- package/cjs/interfaces/localization-module-options.interface.js +4 -0
- package/cjs/interfaces/translation-key.interface.js +4 -0
- package/cjs/interfaces/translation.interface.js +4 -0
- package/cjs/modules/index.js +18 -0
- package/cjs/modules/localization.module.js +115 -0
- package/cjs/services/index.js +22 -0
- package/cjs/services/language.service.js +108 -0
- package/cjs/services/localization-config.service.js +66 -0
- package/cjs/services/localization-datasource.provider.js +122 -0
- package/cjs/services/translation-key.service.js +184 -0
- package/cjs/services/translation.service.js +222 -0
- package/config/index.d.ts +2 -0
- package/config/localization.constants.d.ts +2 -0
- package/config/message-keys.d.ts +96 -0
- package/controllers/index.d.ts +3 -0
- package/controllers/language.controller.d.ts +25 -0
- package/controllers/translation-key.controller.d.ts +22 -0
- package/controllers/translation.controller.d.ts +25 -0
- package/dtos/index.d.ts +3 -0
- package/dtos/language.dto.d.ts +24 -0
- package/dtos/translation-key.dto.d.ts +29 -0
- package/dtos/translation.dto.d.ts +42 -0
- package/entities/index.d.ts +8 -0
- package/entities/language.entity.d.ts +13 -0
- package/entities/translation-key.entity.d.ts +13 -0
- package/entities/translation.entity.d.ts +12 -0
- package/fesm/config/index.js +2 -0
- package/fesm/config/localization.constants.js +2 -0
- package/fesm/config/message-keys.js +54 -0
- package/fesm/controllers/index.js +3 -0
- package/fesm/controllers/language.controller.js +178 -0
- package/fesm/controllers/translation-key.controller.js +164 -0
- package/fesm/controllers/translation.controller.js +244 -0
- package/fesm/dtos/index.js +3 -0
- package/fesm/dtos/language.dto.js +184 -0
- package/fesm/dtos/translation-key.dto.js +209 -0
- package/fesm/dtos/translation.dto.js +265 -0
- package/fesm/entities/index.js +14 -0
- package/fesm/entities/language.entity.js +116 -0
- package/fesm/entities/translation-key.entity.js +115 -0
- package/fesm/entities/translation.entity.js +110 -0
- package/fesm/index.js +7 -0
- package/fesm/interfaces/index.js +4 -0
- package/fesm/interfaces/language.interface.js +1 -0
- package/fesm/interfaces/localization-module-options.interface.js +1 -0
- package/fesm/interfaces/translation-key.interface.js +1 -0
- package/fesm/interfaces/translation.interface.js +1 -0
- package/fesm/modules/index.js +1 -0
- package/fesm/modules/localization.module.js +105 -0
- package/fesm/services/index.js +5 -0
- package/fesm/services/language.service.js +98 -0
- package/fesm/services/localization-config.service.js +56 -0
- package/fesm/services/localization-datasource.provider.js +112 -0
- package/fesm/services/translation-key.service.js +174 -0
- package/fesm/services/translation.service.js +212 -0
- package/index.d.ts +7 -0
- package/interfaces/index.d.ts +4 -0
- package/interfaces/language.interface.d.ts +10 -0
- package/interfaces/localization-module-options.interface.d.ts +21 -0
- package/interfaces/translation-key.interface.d.ts +11 -0
- package/interfaces/translation.interface.d.ts +13 -0
- package/modules/index.d.ts +1 -0
- package/modules/localization.module.d.ts +8 -0
- package/package.json +80 -0
- package/services/index.d.ts +5 -0
- package/services/language.service.d.ts +18 -0
- package/services/localization-config.service.d.ts +11 -0
- package/services/localization-datasource.provider.d.ts +16 -0
- package/services/translation-key.service.d.ts +23 -0
- package/services/translation.service.d.ts +30 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "LocalizationDataSourceProvider", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return LocalizationDataSourceProvider;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
12
|
+
const _constants = require("@flusys/nestjs-shared/constants");
|
|
13
|
+
const _common = require("@nestjs/common");
|
|
14
|
+
const _core = require("@nestjs/core");
|
|
15
|
+
const _express = require("express");
|
|
16
|
+
const _entities = require("../entities");
|
|
17
|
+
const _localizationconfigservice = require("./localization-config.service");
|
|
18
|
+
function _define_property(obj, key, value) {
|
|
19
|
+
if (key in obj) {
|
|
20
|
+
Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
32
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
34
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
35
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
36
|
+
}
|
|
37
|
+
function _ts_metadata(k, v) {
|
|
38
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
39
|
+
}
|
|
40
|
+
function _ts_param(paramIndex, decorator) {
|
|
41
|
+
return function(target, key) {
|
|
42
|
+
decorator(target, key, paramIndex);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
let LocalizationDataSourceProvider = class LocalizationDataSourceProvider extends _modules.MultiTenantDataSourceService {
|
|
46
|
+
static buildParentOptions(options) {
|
|
47
|
+
return {
|
|
48
|
+
bootstrapAppConfig: options.bootstrapAppConfig,
|
|
49
|
+
defaultDatabaseConfig: options.config?.defaultDatabaseConfig,
|
|
50
|
+
tenantDefaultDatabaseConfig: options.config?.tenantDefaultDatabaseConfig,
|
|
51
|
+
tenants: options.config?.tenants
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async createDataSourceFromConfig(config) {
|
|
55
|
+
const entities = (0, _entities.getLocalizationEntities)();
|
|
56
|
+
return super.createDataSourceFromConfig(config, entities);
|
|
57
|
+
}
|
|
58
|
+
async getSingleDataSource() {
|
|
59
|
+
if (LocalizationDataSourceProvider.singleDataSource?.isInitialized) {
|
|
60
|
+
return LocalizationDataSourceProvider.singleDataSource;
|
|
61
|
+
}
|
|
62
|
+
if (LocalizationDataSourceProvider.singleConnectionLock) {
|
|
63
|
+
return LocalizationDataSourceProvider.singleConnectionLock;
|
|
64
|
+
}
|
|
65
|
+
const config = this.getDefaultDatabaseConfig();
|
|
66
|
+
if (!config) {
|
|
67
|
+
throw new _common.InternalServerErrorException({
|
|
68
|
+
message: 'No database config available. Provide defaultDatabaseConfig or tenantDefaultDatabaseConfig.',
|
|
69
|
+
messageKey: _constants.SYSTEM_MESSAGES.DATABASE_CONFIG_NOT_AVAILABLE
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
73
|
+
LocalizationDataSourceProvider.singleConnectionLock = connectionPromise;
|
|
74
|
+
try {
|
|
75
|
+
const dataSource = await connectionPromise;
|
|
76
|
+
LocalizationDataSourceProvider.singleDataSource = dataSource;
|
|
77
|
+
return dataSource;
|
|
78
|
+
} finally{
|
|
79
|
+
LocalizationDataSourceProvider.singleConnectionLock = null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async getOrCreateTenantConnection(tenant) {
|
|
83
|
+
const existing = LocalizationDataSourceProvider.tenantConnections.get(tenant.id);
|
|
84
|
+
if (existing?.isInitialized) {
|
|
85
|
+
return existing;
|
|
86
|
+
}
|
|
87
|
+
const pendingConnection = LocalizationDataSourceProvider.connectionLocks.get(tenant.id);
|
|
88
|
+
if (pendingConnection) {
|
|
89
|
+
return pendingConnection;
|
|
90
|
+
}
|
|
91
|
+
const config = this.buildTenantDatabaseConfig(tenant);
|
|
92
|
+
const connectionPromise = this.createDataSourceFromConfig(config);
|
|
93
|
+
LocalizationDataSourceProvider.connectionLocks.set(tenant.id, connectionPromise);
|
|
94
|
+
try {
|
|
95
|
+
const dataSource = await connectionPromise;
|
|
96
|
+
LocalizationDataSourceProvider.tenantConnections.set(tenant.id, dataSource);
|
|
97
|
+
return dataSource;
|
|
98
|
+
} finally{
|
|
99
|
+
LocalizationDataSourceProvider.connectionLocks.delete(tenant.id);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
constructor(configService, request){
|
|
103
|
+
super(LocalizationDataSourceProvider.buildParentOptions(configService.getOptions()), request);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
_define_property(LocalizationDataSourceProvider, "tenantConnections", new Map());
|
|
107
|
+
_define_property(LocalizationDataSourceProvider, "singleDataSource", null);
|
|
108
|
+
_define_property(LocalizationDataSourceProvider, "connectionLocks", new Map());
|
|
109
|
+
_define_property(LocalizationDataSourceProvider, "singleConnectionLock", null);
|
|
110
|
+
LocalizationDataSourceProvider = _ts_decorate([
|
|
111
|
+
(0, _common.Injectable)({
|
|
112
|
+
scope: _common.Scope.REQUEST
|
|
113
|
+
}),
|
|
114
|
+
_ts_param(0, (0, _common.Inject)(_localizationconfigservice.LocalizationConfigService)),
|
|
115
|
+
_ts_param(1, (0, _common.Optional)()),
|
|
116
|
+
_ts_param(1, (0, _common.Inject)(_core.REQUEST)),
|
|
117
|
+
_ts_metadata("design:type", Function),
|
|
118
|
+
_ts_metadata("design:paramtypes", [
|
|
119
|
+
typeof _localizationconfigservice.LocalizationConfigService === "undefined" ? Object : _localizationconfigservice.LocalizationConfigService,
|
|
120
|
+
typeof _express.Request === "undefined" ? Object : _express.Request
|
|
121
|
+
])
|
|
122
|
+
], LocalizationDataSourceProvider);
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "TranslationKeyService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return TranslationKeyService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _config = require("../config");
|
|
13
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
14
|
+
const _common = require("@nestjs/common");
|
|
15
|
+
const _typeorm = require("typeorm");
|
|
16
|
+
const _entities = require("../entities");
|
|
17
|
+
const _localizationdatasourceprovider = require("./localization-datasource.provider");
|
|
18
|
+
function _define_property(obj, key, value) {
|
|
19
|
+
if (key in obj) {
|
|
20
|
+
Object.defineProperty(obj, key, {
|
|
21
|
+
value: value,
|
|
22
|
+
enumerable: true,
|
|
23
|
+
configurable: true,
|
|
24
|
+
writable: true
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
obj[key] = value;
|
|
28
|
+
}
|
|
29
|
+
return obj;
|
|
30
|
+
}
|
|
31
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
32
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
33
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
34
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
35
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
36
|
+
}
|
|
37
|
+
function _ts_metadata(k, v) {
|
|
38
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
39
|
+
}
|
|
40
|
+
function _ts_param(paramIndex, decorator) {
|
|
41
|
+
return function(target, key) {
|
|
42
|
+
decorator(target, key, paramIndex);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
let TranslationKeyService = class TranslationKeyService extends _classes.RequestScopedApiService {
|
|
46
|
+
resolveEntity() {
|
|
47
|
+
return _entities.TranslationKey;
|
|
48
|
+
}
|
|
49
|
+
getDataSourceProvider() {
|
|
50
|
+
return this.dataSourceProvider;
|
|
51
|
+
}
|
|
52
|
+
async beforeInsertOperation(dto, _user, _queryRunner) {
|
|
53
|
+
const dtos = Array.isArray(dto) ? dto : [
|
|
54
|
+
dto
|
|
55
|
+
];
|
|
56
|
+
await this.validateNoDuplicateKeys(dtos.map((d)=>({
|
|
57
|
+
module: d.module,
|
|
58
|
+
key: d.key
|
|
59
|
+
})));
|
|
60
|
+
}
|
|
61
|
+
async beforeUpdateOperation(dto, _user, _queryRunner) {
|
|
62
|
+
const dtos = Array.isArray(dto) ? dto : [
|
|
63
|
+
dto
|
|
64
|
+
];
|
|
65
|
+
const ids = dtos.map((d)=>d.id);
|
|
66
|
+
await this.ensureRepositoryInitialized();
|
|
67
|
+
const existingKeys = await this.repository.find({
|
|
68
|
+
where: {
|
|
69
|
+
id: (0, _typeorm.In)(ids),
|
|
70
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
// Check if any readonly keys are being updated with key/module changes
|
|
74
|
+
for (const d of dtos){
|
|
75
|
+
const existing = existingKeys.find((e)=>e.id === d.id);
|
|
76
|
+
if (existing?.isReadonly && (d.key || d.module)) {
|
|
77
|
+
throw new _common.ForbiddenException({
|
|
78
|
+
message: `Cannot modify key or module of readonly translation key "${existing.key}"`,
|
|
79
|
+
messageKey: _config.TRANSLATION_KEY_MESSAGES.READONLY_UPDATE_FORBIDDEN,
|
|
80
|
+
messageParams: {
|
|
81
|
+
key: existing.key
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Validate no duplicates for keys being changed
|
|
87
|
+
const keysToValidate = dtos.filter((d)=>d.key || d.module).map((d)=>{
|
|
88
|
+
const existing = existingKeys.find((e)=>e.id === d.id);
|
|
89
|
+
return {
|
|
90
|
+
module: d.module ?? existing?.module ?? '',
|
|
91
|
+
key: d.key ?? existing?.key ?? '',
|
|
92
|
+
excludeId: d.id
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
if (keysToValidate.length > 0) {
|
|
96
|
+
await this.validateNoDuplicateKeys(keysToValidate);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
async beforeDeleteOperation(option, _user, _queryRunner) {
|
|
100
|
+
const ids = Array.isArray(option.id) ? option.id : [
|
|
101
|
+
option.id
|
|
102
|
+
];
|
|
103
|
+
await this.ensureRepositoryInitialized();
|
|
104
|
+
const readonlyKeys = await this.repository.find({
|
|
105
|
+
where: {
|
|
106
|
+
id: (0, _typeorm.In)(ids),
|
|
107
|
+
isReadonly: true,
|
|
108
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
if (readonlyKeys.length > 0) {
|
|
112
|
+
const keys = readonlyKeys.map((k)=>k.key).join(', ');
|
|
113
|
+
throw new _common.ForbiddenException({
|
|
114
|
+
message: `Cannot delete readonly translation keys: ${keys}`,
|
|
115
|
+
messageKey: _config.TRANSLATION_KEY_MESSAGES.READONLY_DELETE_FORBIDDEN,
|
|
116
|
+
messageParams: {
|
|
117
|
+
keys
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async findByModule(module) {
|
|
123
|
+
await this.ensureRepositoryInitialized();
|
|
124
|
+
return this.repository.find({
|
|
125
|
+
where: {
|
|
126
|
+
module,
|
|
127
|
+
isActive: true,
|
|
128
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
129
|
+
},
|
|
130
|
+
order: {
|
|
131
|
+
serial: 'ASC',
|
|
132
|
+
key: 'ASC'
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async getModules() {
|
|
137
|
+
await this.ensureRepositoryInitialized();
|
|
138
|
+
const result = await this.repository.createQueryBuilder('tk').select('DISTINCT tk.module', 'module').where('tk.deleted_at IS NULL').getRawMany();
|
|
139
|
+
return result.map((r)=>r.module);
|
|
140
|
+
}
|
|
141
|
+
async validateNoDuplicateKeys(keys) {
|
|
142
|
+
await this.ensureRepositoryInitialized();
|
|
143
|
+
for (const { module, key, excludeId } of keys){
|
|
144
|
+
const query = this.repository.createQueryBuilder('tk').where('tk.module = :module', {
|
|
145
|
+
module
|
|
146
|
+
}).andWhere('tk.key = :key', {
|
|
147
|
+
key
|
|
148
|
+
}).andWhere('tk.deleted_at IS NULL');
|
|
149
|
+
if (excludeId) {
|
|
150
|
+
query.andWhere('tk.id != :excludeId', {
|
|
151
|
+
excludeId
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
const existing = await query.getOne();
|
|
155
|
+
if (existing) {
|
|
156
|
+
throw new _common.BadRequestException({
|
|
157
|
+
message: `Translation key "${key}" already exists in module "${module}"`,
|
|
158
|
+
messageKey: _config.TRANSLATION_KEY_MESSAGES.DUPLICATE_KEY_IN_MODULE,
|
|
159
|
+
messageParams: {
|
|
160
|
+
key,
|
|
161
|
+
module
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
168
|
+
super('translationKey', null, cacheManager, utilsService, TranslationKeyService.name, true, 'localization'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
TranslationKeyService = _ts_decorate([
|
|
172
|
+
(0, _common.Injectable)({
|
|
173
|
+
scope: _common.Scope.REQUEST
|
|
174
|
+
}),
|
|
175
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
176
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
177
|
+
_ts_param(2, (0, _common.Inject)(_localizationdatasourceprovider.LocalizationDataSourceProvider)),
|
|
178
|
+
_ts_metadata("design:type", Function),
|
|
179
|
+
_ts_metadata("design:paramtypes", [
|
|
180
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
181
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
182
|
+
typeof _localizationdatasourceprovider.LocalizationDataSourceProvider === "undefined" ? Object : _localizationdatasourceprovider.LocalizationDataSourceProvider
|
|
183
|
+
])
|
|
184
|
+
], TranslationKeyService);
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "TranslationService", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return TranslationService;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _classes = require("@flusys/nestjs-shared/classes");
|
|
12
|
+
const _modules = require("@flusys/nestjs-shared/modules");
|
|
13
|
+
const _common = require("@nestjs/common");
|
|
14
|
+
const _typeorm = require("typeorm");
|
|
15
|
+
const _entities = require("../entities");
|
|
16
|
+
const _localizationdatasourceprovider = require("./localization-datasource.provider");
|
|
17
|
+
function _define_property(obj, key, value) {
|
|
18
|
+
if (key in obj) {
|
|
19
|
+
Object.defineProperty(obj, key, {
|
|
20
|
+
value: value,
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true
|
|
24
|
+
});
|
|
25
|
+
} else {
|
|
26
|
+
obj[key] = value;
|
|
27
|
+
}
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
31
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
32
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
33
|
+
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
34
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
35
|
+
}
|
|
36
|
+
function _ts_metadata(k, v) {
|
|
37
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
38
|
+
}
|
|
39
|
+
function _ts_param(paramIndex, decorator) {
|
|
40
|
+
return function(target, key) {
|
|
41
|
+
decorator(target, key, paramIndex);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
let TranslationService = class TranslationService extends _classes.RequestScopedApiService {
|
|
45
|
+
resolveEntity() {
|
|
46
|
+
return _entities.Translation;
|
|
47
|
+
}
|
|
48
|
+
getDataSourceProvider() {
|
|
49
|
+
return this.dataSourceProvider;
|
|
50
|
+
}
|
|
51
|
+
async getFilterQuery(query, filter, _user) {
|
|
52
|
+
// Handle module filter by joining to translation_key table
|
|
53
|
+
if (filter.module) {
|
|
54
|
+
query.innerJoin('translation.translationKey', 'tk');
|
|
55
|
+
query.andWhere('tk.module = :module', {
|
|
56
|
+
module: filter.module
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// Handle standard filters on translation table
|
|
60
|
+
if (filter.languageId) {
|
|
61
|
+
query.andWhere('translation.languageId = :languageId', {
|
|
62
|
+
languageId: filter.languageId
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (filter.translationKeyId) {
|
|
66
|
+
query.andWhere('translation.translationKeyId = :translationKeyId', {
|
|
67
|
+
translationKeyId: filter.translationKeyId
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
query,
|
|
72
|
+
isRaw: false
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
async ensureAllReposInitialized() {
|
|
76
|
+
await this.ensureRepositoryInitialized();
|
|
77
|
+
if (!this.languageRepo) {
|
|
78
|
+
const ds = await this.dataSourceProvider.getDataSource();
|
|
79
|
+
this.languageRepo = ds.getRepository(_entities.Language);
|
|
80
|
+
this.translationKeyRepo = ds.getRepository(_entities.TranslationKey);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async getByLanguageCode(languageCode, modules) {
|
|
84
|
+
await this.ensureAllReposInitialized();
|
|
85
|
+
const language = await this.findActiveLanguageByCode(languageCode);
|
|
86
|
+
if (!language) return {};
|
|
87
|
+
const qb = this.repository.createQueryBuilder('t').innerJoinAndSelect('t.translationKey', 'tk').where('t.language_id = :languageId', {
|
|
88
|
+
languageId: language.id
|
|
89
|
+
}).andWhere('t.is_active = true').andWhere('t.deleted_at IS NULL').andWhere('tk.is_active = true').andWhere('tk.deleted_at IS NULL');
|
|
90
|
+
if (modules && modules.length > 0) {
|
|
91
|
+
qb.andWhere('tk.module IN (:...modules)', {
|
|
92
|
+
modules
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return this.toTranslationsMap(await qb.getMany());
|
|
96
|
+
}
|
|
97
|
+
async getByModuleAndLanguage(module, languageCode) {
|
|
98
|
+
await this.ensureAllReposInitialized();
|
|
99
|
+
const language = await this.findActiveLanguageByCode(languageCode);
|
|
100
|
+
if (!language) return {};
|
|
101
|
+
const translations = await this.repository.createQueryBuilder('t').innerJoinAndSelect('t.translationKey', 'tk').where('t.language_id = :languageId', {
|
|
102
|
+
languageId: language.id
|
|
103
|
+
}).andWhere('tk.module = :module', {
|
|
104
|
+
module
|
|
105
|
+
}).andWhere('t.is_active = true').andWhere('t.deleted_at IS NULL').andWhere('tk.is_active = true').andWhere('tk.deleted_at IS NULL').getMany();
|
|
106
|
+
return this.toTranslationsMap(translations);
|
|
107
|
+
}
|
|
108
|
+
async bulkUpdate(updates) {
|
|
109
|
+
await this.ensureRepositoryInitialized();
|
|
110
|
+
if (updates.length === 0) return [];
|
|
111
|
+
const ds = await this.dataSourceProvider.getDataSource();
|
|
112
|
+
const queryRunner = ds.createQueryRunner();
|
|
113
|
+
await queryRunner.connect();
|
|
114
|
+
await queryRunner.startTransaction();
|
|
115
|
+
try {
|
|
116
|
+
const resultIds = [];
|
|
117
|
+
for (const update of updates){
|
|
118
|
+
if (update.id) {
|
|
119
|
+
// Update existing translation
|
|
120
|
+
await queryRunner.manager.update(_entities.Translation, {
|
|
121
|
+
id: update.id
|
|
122
|
+
}, {
|
|
123
|
+
value: update.value,
|
|
124
|
+
isVerified: update.isVerified ?? false
|
|
125
|
+
});
|
|
126
|
+
resultIds.push(update.id);
|
|
127
|
+
} else {
|
|
128
|
+
// Create new translation
|
|
129
|
+
const newTranslation = queryRunner.manager.create(_entities.Translation, {
|
|
130
|
+
languageId: update.languageId,
|
|
131
|
+
translationKeyId: update.translationKeyId,
|
|
132
|
+
value: update.value,
|
|
133
|
+
isVerified: update.isVerified ?? false,
|
|
134
|
+
isActive: true
|
|
135
|
+
});
|
|
136
|
+
const saved = await queryRunner.manager.save(newTranslation);
|
|
137
|
+
resultIds.push(saved.id);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
await queryRunner.commitTransaction();
|
|
141
|
+
return this.repository.find({
|
|
142
|
+
where: {
|
|
143
|
+
id: (0, _typeorm.In)(resultIds)
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
} catch (error) {
|
|
147
|
+
await queryRunner.rollbackTransaction();
|
|
148
|
+
throw error;
|
|
149
|
+
} finally{
|
|
150
|
+
await queryRunner.release();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async getMissingTranslations(languageCode) {
|
|
154
|
+
await this.ensureAllReposInitialized();
|
|
155
|
+
const language = await this.findActiveLanguageByCode(languageCode);
|
|
156
|
+
if (!language) return [];
|
|
157
|
+
if (!this.translationKeyRepo) return [];
|
|
158
|
+
const allKeys = await this.translationKeyRepo.find({
|
|
159
|
+
where: {
|
|
160
|
+
isActive: true,
|
|
161
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
const existingTranslations = await this.repository.find({
|
|
165
|
+
where: {
|
|
166
|
+
languageId: language.id,
|
|
167
|
+
isActive: true,
|
|
168
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
169
|
+
},
|
|
170
|
+
select: [
|
|
171
|
+
'translationKeyId'
|
|
172
|
+
]
|
|
173
|
+
});
|
|
174
|
+
const existingKeyIds = new Set(existingTranslations.map((t)=>t.translationKeyId));
|
|
175
|
+
return allKeys.filter((k)=>!existingKeyIds.has(k.id));
|
|
176
|
+
}
|
|
177
|
+
async getTranslationCounts() {
|
|
178
|
+
await this.ensureRepositoryInitialized();
|
|
179
|
+
const counts = await this.repository.createQueryBuilder('t').select('t.translation_key_id', 'keyId').addSelect('COUNT(t.id)', 'count').where('t.is_active = true').andWhere('t.deleted_at IS NULL').groupBy('t.translation_key_id').getRawMany();
|
|
180
|
+
const result = {};
|
|
181
|
+
for (const row of counts){
|
|
182
|
+
result[row.keyId] = parseInt(row.count, 10);
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
async findActiveLanguageByCode(code) {
|
|
187
|
+
if (!this.languageRepo) return null;
|
|
188
|
+
return this.languageRepo.findOne({
|
|
189
|
+
where: {
|
|
190
|
+
code,
|
|
191
|
+
isActive: true,
|
|
192
|
+
deletedAt: (0, _typeorm.IsNull)()
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
toTranslationsMap(translations) {
|
|
197
|
+
const result = {};
|
|
198
|
+
for (const t of translations){
|
|
199
|
+
if (t.translationKey) {
|
|
200
|
+
result[t.translationKey.key] = t.value;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
constructor(cacheManager, utilsService, dataSourceProvider){
|
|
206
|
+
super('translation', null, cacheManager, utilsService, TranslationService.name, true, 'localization'), _define_property(this, "cacheManager", void 0), _define_property(this, "utilsService", void 0), _define_property(this, "dataSourceProvider", void 0), _define_property(this, "languageRepo", void 0), _define_property(this, "translationKeyRepo", void 0), this.cacheManager = cacheManager, this.utilsService = utilsService, this.dataSourceProvider = dataSourceProvider, this.languageRepo = null, this.translationKeyRepo = null;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
TranslationService = _ts_decorate([
|
|
210
|
+
(0, _common.Injectable)({
|
|
211
|
+
scope: _common.Scope.REQUEST
|
|
212
|
+
}),
|
|
213
|
+
_ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
|
|
214
|
+
_ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
|
|
215
|
+
_ts_param(2, (0, _common.Inject)(_localizationdatasourceprovider.LocalizationDataSourceProvider)),
|
|
216
|
+
_ts_metadata("design:type", Function),
|
|
217
|
+
_ts_metadata("design:paramtypes", [
|
|
218
|
+
typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
|
|
219
|
+
typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
|
|
220
|
+
typeof _localizationdatasourceprovider.LocalizationDataSourceProvider === "undefined" ? Object : _localizationdatasourceprovider.LocalizationDataSourceProvider
|
|
221
|
+
])
|
|
222
|
+
], TranslationService);
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export declare const LANGUAGE_MESSAGES: {
|
|
2
|
+
readonly CREATE_SUCCESS: "language.create.success";
|
|
3
|
+
readonly CREATE_MANY_SUCCESS: "language.create.many.success";
|
|
4
|
+
readonly GET_SUCCESS: "language.get.success";
|
|
5
|
+
readonly GET_ALL_SUCCESS: "language.get.all.success";
|
|
6
|
+
readonly UPDATE_SUCCESS: "language.update.success";
|
|
7
|
+
readonly UPDATE_MANY_SUCCESS: "language.update.many.success";
|
|
8
|
+
readonly DELETE_SUCCESS: "language.delete.success";
|
|
9
|
+
readonly RESTORE_SUCCESS: "language.restore.success";
|
|
10
|
+
readonly NOT_FOUND: "language.not.found";
|
|
11
|
+
readonly ACTIVE_SUCCESS: "language.active.success";
|
|
12
|
+
readonly SET_DEFAULT_SUCCESS: "language.set.default.success";
|
|
13
|
+
readonly GET_DEFAULT_SUCCESS: "language.get.default.success";
|
|
14
|
+
};
|
|
15
|
+
export declare const TRANSLATION_KEY_MESSAGES: {
|
|
16
|
+
readonly CREATE_SUCCESS: "translation.key.create.success";
|
|
17
|
+
readonly CREATE_MANY_SUCCESS: "translation.key.create.many.success";
|
|
18
|
+
readonly GET_SUCCESS: "translation.key.get.success";
|
|
19
|
+
readonly GET_ALL_SUCCESS: "translation.key.get.all.success";
|
|
20
|
+
readonly UPDATE_SUCCESS: "translation.key.update.success";
|
|
21
|
+
readonly UPDATE_MANY_SUCCESS: "translation.key.update.many.success";
|
|
22
|
+
readonly DELETE_SUCCESS: "translation.key.delete.success";
|
|
23
|
+
readonly RESTORE_SUCCESS: "translation.key.restore.success";
|
|
24
|
+
readonly NOT_FOUND: "translation.key.not.found";
|
|
25
|
+
readonly IMPORT_SUCCESS: "translation.key.import.success";
|
|
26
|
+
readonly EXPORT_SUCCESS: "translation.key.export.success";
|
|
27
|
+
readonly MODULES_SUCCESS: "translation.key.modules.success";
|
|
28
|
+
readonly READONLY_DELETE_FORBIDDEN: "translation.key.readonly.delete.forbidden";
|
|
29
|
+
readonly READONLY_UPDATE_FORBIDDEN: "translation.key.readonly.update.forbidden";
|
|
30
|
+
readonly DUPLICATE_KEY_IN_MODULE: "translation.key.duplicate.key.in.module";
|
|
31
|
+
};
|
|
32
|
+
export declare const TRANSLATION_MESSAGES: {
|
|
33
|
+
readonly CREATE_SUCCESS: "translation.create.success";
|
|
34
|
+
readonly CREATE_MANY_SUCCESS: "translation.create.many.success";
|
|
35
|
+
readonly GET_SUCCESS: "translation.get.success";
|
|
36
|
+
readonly GET_ALL_SUCCESS: "translation.get.all.success";
|
|
37
|
+
readonly UPDATE_SUCCESS: "translation.update.success";
|
|
38
|
+
readonly UPDATE_MANY_SUCCESS: "translation.update.many.success";
|
|
39
|
+
readonly DELETE_SUCCESS: "translation.delete.success";
|
|
40
|
+
readonly RESTORE_SUCCESS: "translation.restore.success";
|
|
41
|
+
readonly NOT_FOUND: "translation.not.found";
|
|
42
|
+
readonly BY_LANGUAGE_SUCCESS: "translation.by.language.success";
|
|
43
|
+
readonly BY_MODULE_SUCCESS: "translation.by.module.success";
|
|
44
|
+
readonly MISSING_SUCCESS: "translation.missing.success";
|
|
45
|
+
readonly SYNC_SUCCESS: "translation.sync.success";
|
|
46
|
+
readonly UPDATE_VALUES_SUCCESS: "translation.update.values.success";
|
|
47
|
+
};
|
|
48
|
+
export declare const LOCALIZATION_MODULE_MESSAGES: {
|
|
49
|
+
readonly LANGUAGE: {
|
|
50
|
+
readonly CREATE_SUCCESS: "language.create.success";
|
|
51
|
+
readonly CREATE_MANY_SUCCESS: "language.create.many.success";
|
|
52
|
+
readonly GET_SUCCESS: "language.get.success";
|
|
53
|
+
readonly GET_ALL_SUCCESS: "language.get.all.success";
|
|
54
|
+
readonly UPDATE_SUCCESS: "language.update.success";
|
|
55
|
+
readonly UPDATE_MANY_SUCCESS: "language.update.many.success";
|
|
56
|
+
readonly DELETE_SUCCESS: "language.delete.success";
|
|
57
|
+
readonly RESTORE_SUCCESS: "language.restore.success";
|
|
58
|
+
readonly NOT_FOUND: "language.not.found";
|
|
59
|
+
readonly ACTIVE_SUCCESS: "language.active.success";
|
|
60
|
+
readonly SET_DEFAULT_SUCCESS: "language.set.default.success";
|
|
61
|
+
readonly GET_DEFAULT_SUCCESS: "language.get.default.success";
|
|
62
|
+
};
|
|
63
|
+
readonly TRANSLATION_KEY: {
|
|
64
|
+
readonly CREATE_SUCCESS: "translation.key.create.success";
|
|
65
|
+
readonly CREATE_MANY_SUCCESS: "translation.key.create.many.success";
|
|
66
|
+
readonly GET_SUCCESS: "translation.key.get.success";
|
|
67
|
+
readonly GET_ALL_SUCCESS: "translation.key.get.all.success";
|
|
68
|
+
readonly UPDATE_SUCCESS: "translation.key.update.success";
|
|
69
|
+
readonly UPDATE_MANY_SUCCESS: "translation.key.update.many.success";
|
|
70
|
+
readonly DELETE_SUCCESS: "translation.key.delete.success";
|
|
71
|
+
readonly RESTORE_SUCCESS: "translation.key.restore.success";
|
|
72
|
+
readonly NOT_FOUND: "translation.key.not.found";
|
|
73
|
+
readonly IMPORT_SUCCESS: "translation.key.import.success";
|
|
74
|
+
readonly EXPORT_SUCCESS: "translation.key.export.success";
|
|
75
|
+
readonly MODULES_SUCCESS: "translation.key.modules.success";
|
|
76
|
+
readonly READONLY_DELETE_FORBIDDEN: "translation.key.readonly.delete.forbidden";
|
|
77
|
+
readonly READONLY_UPDATE_FORBIDDEN: "translation.key.readonly.update.forbidden";
|
|
78
|
+
readonly DUPLICATE_KEY_IN_MODULE: "translation.key.duplicate.key.in.module";
|
|
79
|
+
};
|
|
80
|
+
readonly TRANSLATION: {
|
|
81
|
+
readonly CREATE_SUCCESS: "translation.create.success";
|
|
82
|
+
readonly CREATE_MANY_SUCCESS: "translation.create.many.success";
|
|
83
|
+
readonly GET_SUCCESS: "translation.get.success";
|
|
84
|
+
readonly GET_ALL_SUCCESS: "translation.get.all.success";
|
|
85
|
+
readonly UPDATE_SUCCESS: "translation.update.success";
|
|
86
|
+
readonly UPDATE_MANY_SUCCESS: "translation.update.many.success";
|
|
87
|
+
readonly DELETE_SUCCESS: "translation.delete.success";
|
|
88
|
+
readonly RESTORE_SUCCESS: "translation.restore.success";
|
|
89
|
+
readonly NOT_FOUND: "translation.not.found";
|
|
90
|
+
readonly BY_LANGUAGE_SUCCESS: "translation.by.language.success";
|
|
91
|
+
readonly BY_MODULE_SUCCESS: "translation.by.module.success";
|
|
92
|
+
readonly MISSING_SUCCESS: "translation.missing.success";
|
|
93
|
+
readonly SYNC_SUCCESS: "translation.sync.success";
|
|
94
|
+
readonly UPDATE_VALUES_SUCCESS: "translation.update.values.success";
|
|
95
|
+
};
|
|
96
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ListResponseDto, SingleResponseDto } from '@flusys/nestjs-shared/dtos';
|
|
2
|
+
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
3
|
+
import { CreateLanguageDto, LanguageResponseDto, UpdateLanguageDto } from '../dtos';
|
|
4
|
+
import { ILanguage } from '../interfaces';
|
|
5
|
+
import { LanguageService } from '../services';
|
|
6
|
+
declare const LanguageController_base: abstract new (service: LanguageService) => {
|
|
7
|
+
service: LanguageService;
|
|
8
|
+
insert(addDto: CreateLanguageDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<LanguageResponseDto>>;
|
|
9
|
+
insertMany(addDto: CreateLanguageDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<LanguageResponseDto>>;
|
|
10
|
+
getById(id: string, body: import("@flusys/nestjs-shared/dtos").GetByIdBodyDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<LanguageResponseDto>>;
|
|
11
|
+
update(updateDto: UpdateLanguageDto, user: ILoggedUserInfo | null): Promise<SingleResponseDto<LanguageResponseDto>>;
|
|
12
|
+
updateMany(updateDtos: UpdateLanguageDto[], user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").BulkResponseDto<LanguageResponseDto>>;
|
|
13
|
+
getAll(filterAndPaginationDto: import("@flusys/nestjs-shared/dtos").FilterAndPaginationDto, user: ILoggedUserInfo | null, search?: string): Promise<ListResponseDto<LanguageResponseDto>>;
|
|
14
|
+
delete(deleteDto: import("@flusys/nestjs-shared/dtos").DeleteDto, user: ILoggedUserInfo | null): Promise<import("@flusys/nestjs-shared/dtos").MessageResponseDto>;
|
|
15
|
+
};
|
|
16
|
+
export declare class LanguageController extends LanguageController_base {
|
|
17
|
+
service: LanguageService;
|
|
18
|
+
constructor(service: LanguageService);
|
|
19
|
+
getActive(): Promise<ListResponseDto<ILanguage>>;
|
|
20
|
+
getDefault(): Promise<SingleResponseDto<ILanguage>>;
|
|
21
|
+
setDefault(body: {
|
|
22
|
+
id: string;
|
|
23
|
+
}, _user: ILoggedUserInfo): Promise<SingleResponseDto<ILanguage>>;
|
|
24
|
+
}
|
|
25
|
+
export {};
|