@flusys/nestjs-localization 4.0.0-lts

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.
Files changed (89) hide show
  1. package/README.md +870 -0
  2. package/cjs/config/index.js +19 -0
  3. package/cjs/config/localization.constants.js +20 -0
  4. package/cjs/config/message-keys.js +77 -0
  5. package/cjs/controllers/index.js +20 -0
  6. package/cjs/controllers/language.controller.js +188 -0
  7. package/cjs/controllers/translation-key.controller.js +174 -0
  8. package/cjs/controllers/translation.controller.js +254 -0
  9. package/cjs/dtos/index.js +20 -0
  10. package/cjs/dtos/language.dto.js +205 -0
  11. package/cjs/dtos/translation-key.dto.js +233 -0
  12. package/cjs/dtos/translation.dto.js +298 -0
  13. package/cjs/entities/index.js +42 -0
  14. package/cjs/entities/language.entity.js +126 -0
  15. package/cjs/entities/translation-key.entity.js +125 -0
  16. package/cjs/entities/translation.entity.js +120 -0
  17. package/cjs/index.js +24 -0
  18. package/cjs/interfaces/index.js +21 -0
  19. package/cjs/interfaces/language.interface.js +4 -0
  20. package/cjs/interfaces/localization-module-options.interface.js +4 -0
  21. package/cjs/interfaces/translation-key.interface.js +4 -0
  22. package/cjs/interfaces/translation.interface.js +4 -0
  23. package/cjs/modules/index.js +18 -0
  24. package/cjs/modules/localization.module.js +115 -0
  25. package/cjs/services/index.js +22 -0
  26. package/cjs/services/language.service.js +108 -0
  27. package/cjs/services/localization-config.service.js +66 -0
  28. package/cjs/services/localization-datasource.provider.js +122 -0
  29. package/cjs/services/translation-key.service.js +184 -0
  30. package/cjs/services/translation.service.js +222 -0
  31. package/config/index.d.ts +2 -0
  32. package/config/localization.constants.d.ts +2 -0
  33. package/config/message-keys.d.ts +96 -0
  34. package/controllers/index.d.ts +3 -0
  35. package/controllers/language.controller.d.ts +25 -0
  36. package/controllers/translation-key.controller.d.ts +22 -0
  37. package/controllers/translation.controller.d.ts +25 -0
  38. package/dtos/index.d.ts +3 -0
  39. package/dtos/language.dto.d.ts +24 -0
  40. package/dtos/translation-key.dto.d.ts +29 -0
  41. package/dtos/translation.dto.d.ts +42 -0
  42. package/entities/index.d.ts +8 -0
  43. package/entities/language.entity.d.ts +13 -0
  44. package/entities/translation-key.entity.d.ts +13 -0
  45. package/entities/translation.entity.d.ts +12 -0
  46. package/fesm/config/index.js +2 -0
  47. package/fesm/config/localization.constants.js +2 -0
  48. package/fesm/config/message-keys.js +54 -0
  49. package/fesm/controllers/index.js +3 -0
  50. package/fesm/controllers/language.controller.js +178 -0
  51. package/fesm/controllers/translation-key.controller.js +164 -0
  52. package/fesm/controllers/translation.controller.js +244 -0
  53. package/fesm/dtos/index.js +3 -0
  54. package/fesm/dtos/language.dto.js +184 -0
  55. package/fesm/dtos/translation-key.dto.js +209 -0
  56. package/fesm/dtos/translation.dto.js +265 -0
  57. package/fesm/entities/index.js +14 -0
  58. package/fesm/entities/language.entity.js +116 -0
  59. package/fesm/entities/translation-key.entity.js +115 -0
  60. package/fesm/entities/translation.entity.js +110 -0
  61. package/fesm/index.js +7 -0
  62. package/fesm/interfaces/index.js +4 -0
  63. package/fesm/interfaces/language.interface.js +1 -0
  64. package/fesm/interfaces/localization-module-options.interface.js +1 -0
  65. package/fesm/interfaces/translation-key.interface.js +1 -0
  66. package/fesm/interfaces/translation.interface.js +1 -0
  67. package/fesm/modules/index.js +1 -0
  68. package/fesm/modules/localization.module.js +105 -0
  69. package/fesm/services/index.js +5 -0
  70. package/fesm/services/language.service.js +98 -0
  71. package/fesm/services/localization-config.service.js +56 -0
  72. package/fesm/services/localization-datasource.provider.js +112 -0
  73. package/fesm/services/translation-key.service.js +174 -0
  74. package/fesm/services/translation.service.js +212 -0
  75. package/index.d.ts +7 -0
  76. package/interfaces/index.d.ts +4 -0
  77. package/interfaces/language.interface.d.ts +10 -0
  78. package/interfaces/localization-module-options.interface.d.ts +21 -0
  79. package/interfaces/translation-key.interface.d.ts +11 -0
  80. package/interfaces/translation.interface.d.ts +13 -0
  81. package/modules/index.d.ts +1 -0
  82. package/modules/localization.module.d.ts +8 -0
  83. package/package.json +81 -0
  84. package/services/index.d.ts +5 -0
  85. package/services/language.service.d.ts +18 -0
  86. package/services/localization-config.service.d.ts +11 -0
  87. package/services/localization-datasource.provider.d.ts +16 -0
  88. package/services/translation-key.service.d.ts +23 -0
  89. 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,2 @@
1
+ export * from './localization.constants';
2
+ export * from './message-keys';
@@ -0,0 +1,2 @@
1
+ export declare const LOCALIZATION_MODULE_OPTIONS = "LOCALIZATION_MODULE_OPTIONS";
2
+ export declare const DEFAULT_LANGUAGE_CODE = "en";
@@ -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,3 @@
1
+ export * from './language.controller';
2
+ export * from './translation-key.controller';
3
+ export * from './translation.controller';
@@ -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 {};