@flusys/nestjs-localization 7.0.2 → 8.0.0-beta.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.
Files changed (117) hide show
  1. package/config/index.d.ts +3 -3
  2. package/controllers/index.d.ts +3 -3
  3. package/controllers/language.controller.d.ts +4 -4
  4. package/controllers/translation-key.controller.d.ts +3 -3
  5. package/controllers/translation.controller.d.ts +4 -4
  6. package/docs/index.d.ts +1 -1
  7. package/docs/localization-swagger.config.d.ts +1 -1
  8. package/dtos/index.d.ts +3 -3
  9. package/dtos/translation.dto.d.ts +2 -2
  10. package/entities/index.d.ts +6 -6
  11. package/entities/language.entity.d.ts +1 -1
  12. package/entities/translation-key.entity.d.ts +1 -1
  13. package/entities/translation.entity.d.ts +2 -2
  14. package/fesm/349.js +1179 -0
  15. package/fesm/692.js +1205 -0
  16. package/fesm/config/index.js +101 -3
  17. package/fesm/controllers/index.js +15 -3
  18. package/fesm/docs/index.js +126 -1
  19. package/fesm/dtos/index.js +680 -3
  20. package/fesm/entities/index.js +405 -8
  21. package/fesm/index.js +257 -7
  22. package/fesm/interfaces/index.js +18 -4
  23. package/fesm/modules/index.js +152 -1
  24. package/fesm/runtime.js +85 -0
  25. package/fesm/services/index.js +15 -5
  26. package/index.d.ts +7 -7
  27. package/interfaces/index.d.ts +4 -4
  28. package/interfaces/language.interface.d.ts +1 -1
  29. package/interfaces/localization-module-options.interface.d.ts +3 -3
  30. package/interfaces/translation-key.interface.d.ts +1 -1
  31. package/interfaces/translation.interface.d.ts +3 -3
  32. package/modules/index.d.ts +1 -1
  33. package/modules/localization.module.d.ts +2 -2
  34. package/package.json +25 -34
  35. package/services/index.d.ts +5 -5
  36. package/services/language.service.d.ts +6 -6
  37. package/services/localization-config.service.d.ts +3 -3
  38. package/services/localization-datasource.provider.d.ts +3 -3
  39. package/services/translation-key.service.d.ts +6 -6
  40. package/services/translation.service.d.ts +5 -5
  41. package/cjs/config/event-actions.js +0 -33
  42. package/cjs/config/index.js +0 -20
  43. package/cjs/config/localization.constants.js +0 -11
  44. package/cjs/config/message-keys.js +0 -41
  45. package/cjs/controllers/index.js +0 -20
  46. package/cjs/controllers/language.controller.js +0 -188
  47. package/cjs/controllers/language.controller.spec.js +0 -154
  48. package/cjs/controllers/translation-key.controller.js +0 -135
  49. package/cjs/controllers/translation-key.controller.spec.js +0 -70
  50. package/cjs/controllers/translation.controller.js +0 -195
  51. package/cjs/controllers/translation.controller.spec.js +0 -169
  52. package/cjs/docs/index.js +0 -11
  53. package/cjs/docs/localization-swagger.config.js +0 -111
  54. package/cjs/docs/localization-swagger.config.spec.js +0 -30
  55. package/cjs/dtos/index.js +0 -20
  56. package/cjs/dtos/language.dto.js +0 -213
  57. package/cjs/dtos/translation-key.dto.js +0 -215
  58. package/cjs/dtos/translation.dto.js +0 -269
  59. package/cjs/entities/index.js +0 -42
  60. package/cjs/entities/index.spec.js +0 -18
  61. package/cjs/entities/language.entity.js +0 -126
  62. package/cjs/entities/translation-key.entity.js +0 -126
  63. package/cjs/entities/translation.entity.js +0 -120
  64. package/cjs/index.js +0 -24
  65. package/cjs/interfaces/index.js +0 -21
  66. package/cjs/interfaces/language.interface.js +0 -4
  67. package/cjs/interfaces/localization-module-options.interface.js +0 -4
  68. package/cjs/interfaces/translation-key.interface.js +0 -4
  69. package/cjs/interfaces/translation.interface.js +0 -4
  70. package/cjs/modules/index.js +0 -18
  71. package/cjs/modules/localization.module.js +0 -116
  72. package/cjs/modules/localization.module.spec.js +0 -132
  73. package/cjs/services/index.js +0 -22
  74. package/cjs/services/language.service.js +0 -181
  75. package/cjs/services/language.service.spec.js +0 -256
  76. package/cjs/services/localization-config.service.js +0 -66
  77. package/cjs/services/localization-config.service.spec.js +0 -80
  78. package/cjs/services/localization-datasource.provider.js +0 -79
  79. package/cjs/services/localization-datasource.provider.spec.js +0 -85
  80. package/cjs/services/translation-key.service.js +0 -179
  81. package/cjs/services/translation-key.service.spec.js +0 -303
  82. package/cjs/services/translation.service.js +0 -228
  83. package/cjs/services/translation.service.spec.js +0 -530
  84. package/fesm/config/event-actions.js +0 -12
  85. package/fesm/config/localization.constants.js +0 -1
  86. package/fesm/config/message-keys.js +0 -20
  87. package/fesm/controllers/language.controller.js +0 -178
  88. package/fesm/controllers/language.controller.spec.js +0 -150
  89. package/fesm/controllers/translation-key.controller.js +0 -125
  90. package/fesm/controllers/translation-key.controller.spec.js +0 -66
  91. package/fesm/controllers/translation.controller.js +0 -185
  92. package/fesm/controllers/translation.controller.spec.js +0 -165
  93. package/fesm/docs/localization-swagger.config.js +0 -101
  94. package/fesm/docs/localization-swagger.config.spec.js +0 -26
  95. package/fesm/dtos/language.dto.js +0 -192
  96. package/fesm/dtos/translation-key.dto.js +0 -194
  97. package/fesm/dtos/translation.dto.js +0 -239
  98. package/fesm/entities/index.spec.js +0 -14
  99. package/fesm/entities/language.entity.js +0 -116
  100. package/fesm/entities/translation-key.entity.js +0 -116
  101. package/fesm/entities/translation.entity.js +0 -110
  102. package/fesm/interfaces/language.interface.js +0 -1
  103. package/fesm/interfaces/localization-module-options.interface.js +0 -1
  104. package/fesm/interfaces/translation-key.interface.js +0 -1
  105. package/fesm/interfaces/translation.interface.js +0 -1
  106. package/fesm/modules/localization.module.js +0 -106
  107. package/fesm/modules/localization.module.spec.js +0 -128
  108. package/fesm/services/language.service.js +0 -171
  109. package/fesm/services/language.service.spec.js +0 -252
  110. package/fesm/services/localization-config.service.js +0 -56
  111. package/fesm/services/localization-config.service.spec.js +0 -76
  112. package/fesm/services/localization-datasource.provider.js +0 -69
  113. package/fesm/services/localization-datasource.provider.spec.js +0 -81
  114. package/fesm/services/translation-key.service.js +0 -169
  115. package/fesm/services/translation-key.service.spec.js +0 -299
  116. package/fesm/services/translation.service.js +0 -218
  117. package/fesm/services/translation.service.spec.js +0 -526
@@ -1,303 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", {
3
- value: true
4
- });
5
- const _testing = require("@nestjs/testing");
6
- const _modules = require("@flusys/nestjs-shared/modules");
7
- const _common = require("@nestjs/common");
8
- const _repositorymock = require("@test-utils/mocks/repository.mock");
9
- const _loggedusermock = require("@test-utils/mocks/logged-user.mock");
10
- const _translationkeyservice = require("./translation-key.service");
11
- const _localizationdatasourceprovider = require("./localization-datasource.provider");
12
- function buildTranslationKey(overrides = {}) {
13
- return {
14
- id: 'tkey-uuid-1',
15
- module: 'auth',
16
- key: 'auth.login.success',
17
- defaultMessage: 'Login successful',
18
- description: null,
19
- variables: null,
20
- isActive: true,
21
- isReadonly: false,
22
- serial: 1,
23
- createdAt: new Date(),
24
- updatedAt: new Date(),
25
- deletedAt: null,
26
- createdById: null,
27
- updatedById: null,
28
- deletedById: null,
29
- ...overrides
30
- };
31
- }
32
- describe('TranslationKeyService', ()=>{
33
- let service;
34
- let mockRepo;
35
- let qb;
36
- let queryRunner;
37
- beforeEach(async ()=>{
38
- mockRepo = (0, _repositorymock.createMockRepository)();
39
- qb = mockRepo.createQueryBuilder();
40
- const mockDataSourceProvider = (0, _repositorymock.createMockDataSourceProvider)(mockRepo);
41
- // executeInTransaction()/delete() always grab a QueryRunner off repository.manager.connection
42
- // before running the before*Operation hooks, so every test (success or rejection) needs one.
43
- queryRunner = {
44
- connect: jest.fn(),
45
- startTransaction: jest.fn(),
46
- commitTransaction: jest.fn(),
47
- rollbackTransaction: jest.fn(),
48
- release: jest.fn(),
49
- manager: {
50
- save: jest.fn(),
51
- softDelete: jest.fn(),
52
- update: jest.fn(),
53
- delete: jest.fn(),
54
- restore: jest.fn()
55
- }
56
- };
57
- mockRepo.manager.connection.createQueryRunner.mockReturnValue(queryRunner);
58
- const mockUtilsService = {
59
- clearCache: jest.fn(),
60
- getCacheKey: jest.fn().mockReturnValue('cache-key'),
61
- trackCacheKey: jest.fn()
62
- };
63
- const module = await _testing.Test.createTestingModule({
64
- providers: [
65
- _translationkeyservice.TranslationKeyService,
66
- {
67
- provide: 'CACHE_INSTANCE',
68
- useValue: {
69
- get: jest.fn(),
70
- set: jest.fn()
71
- }
72
- },
73
- {
74
- provide: _modules.UtilsService,
75
- useValue: mockUtilsService
76
- },
77
- {
78
- provide: _localizationdatasourceprovider.LocalizationDataSourceProvider,
79
- useValue: mockDataSourceProvider
80
- }
81
- ]
82
- }).compile();
83
- service = await module.resolve(_translationkeyservice.TranslationKeyService);
84
- });
85
- describe('findByModule', ()=>{
86
- it('returns active, non-deleted keys for the module ordered by serial then key', async ()=>{
87
- const keys = [
88
- buildTranslationKey({
89
- key: 'auth.login.success',
90
- serial: 1
91
- })
92
- ];
93
- mockRepo.find.mockResolvedValue(keys);
94
- const result = await service.findByModule('auth');
95
- expect(mockRepo.find).toHaveBeenCalledWith({
96
- where: {
97
- module: 'auth',
98
- isActive: true,
99
- deletedAt: expect.anything()
100
- },
101
- order: {
102
- serial: 'ASC',
103
- key: 'ASC'
104
- }
105
- });
106
- expect(result).toEqual(keys);
107
- });
108
- it('returns an empty array for an unknown module', async ()=>{
109
- mockRepo.find.mockResolvedValue([]);
110
- const result = await service.findByModule('does-not-exist');
111
- expect(result).toEqual([]);
112
- });
113
- });
114
- describe('getModules', ()=>{
115
- it('returns distinct module names', async ()=>{
116
- // `getRawMany` isn't part of the shared MockQueryBuilder — attach it for this raw-query path.
117
- const getRawMany = jest.fn().mockResolvedValue([
118
- {
119
- module: 'auth'
120
- },
121
- {
122
- module: 'shared'
123
- }
124
- ]);
125
- qb.getRawMany = getRawMany;
126
- const result = await service.getModules();
127
- expect(result).toEqual([
128
- 'auth',
129
- 'shared'
130
- ]);
131
- });
132
- it('returns an empty array when there are no translation keys yet', async ()=>{
133
- const getRawMany = jest.fn().mockResolvedValue([]);
134
- qb.getRawMany = getRawMany;
135
- const result = await service.getModules();
136
- expect(result).toEqual([]);
137
- });
138
- });
139
- describe('beforeInsertOperation (via insert) — duplicate key validation', ()=>{
140
- it('allows insert when no key with the same module+key exists', async ()=>{
141
- qb.getOne.mockResolvedValue(null);
142
- const created = buildTranslationKey();
143
- mockRepo.create.mockReturnValue({});
144
- queryRunner.manager.save.mockResolvedValue(created);
145
- await expect(service.insert({
146
- module: 'auth',
147
- key: 'auth.login.success',
148
- defaultMessage: 'Login successful'
149
- }, (0, _loggedusermock.buildMockUser)())).resolves.toBeDefined();
150
- });
151
- it('rejects with BadRequestException + messageKey when the module+key combination already exists', async ()=>{
152
- qb.getOne.mockResolvedValue(buildTranslationKey());
153
- await expect(service.insert({
154
- module: 'auth',
155
- key: 'auth.login.success',
156
- defaultMessage: 'Login successful'
157
- }, (0, _loggedusermock.buildMockUser)())).rejects.toMatchObject({
158
- response: expect.objectContaining({
159
- messageKey: 'translation.key.duplicate.key.in.module'
160
- })
161
- });
162
- });
163
- it('rejects with BadRequestException for duplicate module+key in insertMany', async ()=>{
164
- qb.getOne.mockResolvedValueOnce(null).mockResolvedValueOnce(buildTranslationKey({
165
- key: 'auth.logout.success'
166
- }));
167
- await expect(service.insertMany([
168
- {
169
- module: 'auth',
170
- key: 'auth.login.success',
171
- defaultMessage: 'A'
172
- },
173
- {
174
- module: 'auth',
175
- key: 'auth.logout.success',
176
- defaultMessage: 'B'
177
- }
178
- ], (0, _loggedusermock.buildMockUser)())).rejects.toBeInstanceOf(_common.BadRequestException);
179
- });
180
- });
181
- describe('beforeUpdateOperation (via update)', ()=>{
182
- it('rejects with ForbiddenException when modifying key/module of a readonly translation key', async ()=>{
183
- const existing = buildTranslationKey({
184
- id: 'tkey-1',
185
- isReadonly: true,
186
- key: 'system.ready'
187
- });
188
- mockRepo.find.mockResolvedValue([
189
- existing
190
- ]);
191
- await expect(service.update({
192
- id: 'tkey-1',
193
- key: 'system.changed'
194
- }, (0, _loggedusermock.buildMockUser)())).rejects.toBeInstanceOf(_common.ForbiddenException);
195
- await expect(service.update({
196
- id: 'tkey-1',
197
- key: 'system.changed'
198
- }, (0, _loggedusermock.buildMockUser)())).rejects.toMatchObject({
199
- response: expect.objectContaining({
200
- messageKey: 'translation.key.readonly.update.forbidden'
201
- })
202
- });
203
- });
204
- it('allows updating non key/module fields of a readonly translation key', async ()=>{
205
- const existing = buildTranslationKey({
206
- id: 'tkey-1',
207
- isReadonly: true,
208
- key: 'system.ready'
209
- });
210
- mockRepo.find.mockResolvedValue([
211
- existing
212
- ]);
213
- mockRepo.findOne.mockResolvedValue(existing);
214
- queryRunner.manager.save.mockResolvedValue(existing);
215
- await expect(service.update({
216
- id: 'tkey-1',
217
- defaultMessage: 'Updated readonly message'
218
- }, (0, _loggedusermock.buildMockUser)())).resolves.toBeDefined();
219
- });
220
- it('allows resubmitting the same unchanged key/module of a readonly translation key', async ()=>{
221
- // Regression test: the edit form always resends key + module even when only
222
- // other fields changed, so the check must compare values, not just presence.
223
- const existing = buildTranslationKey({
224
- id: 'tkey-1',
225
- isReadonly: true,
226
- key: 'system.ready',
227
- module: 'system'
228
- });
229
- mockRepo.find.mockResolvedValue([
230
- existing
231
- ]);
232
- mockRepo.findOne.mockResolvedValue(existing);
233
- queryRunner.manager.save.mockResolvedValue(existing);
234
- await expect(service.update({
235
- id: 'tkey-1',
236
- key: 'system.ready',
237
- module: 'system',
238
- defaultMessage: 'Updated readonly message'
239
- }, (0, _loggedusermock.buildMockUser)())).resolves.toBeDefined();
240
- });
241
- it('rejects with BadRequestException when the new key/module already exists on another row', async ()=>{
242
- const existing = buildTranslationKey({
243
- id: 'tkey-1',
244
- isReadonly: false,
245
- key: 'auth.old',
246
- module: 'auth'
247
- });
248
- mockRepo.find.mockResolvedValue([
249
- existing
250
- ]);
251
- qb.getOne.mockResolvedValue(buildTranslationKey({
252
- id: 'tkey-other',
253
- key: 'auth.new'
254
- }));
255
- await expect(service.update({
256
- id: 'tkey-1',
257
- key: 'auth.new'
258
- }, (0, _loggedusermock.buildMockUser)())).rejects.toMatchObject({
259
- response: expect.objectContaining({
260
- messageKey: 'translation.key.duplicate.key.in.module'
261
- })
262
- });
263
- // excludeId must be used so the row being updated doesn't collide with itself
264
- expect(qb.andWhere).toHaveBeenCalledWith('tk.id != :excludeId', {
265
- excludeId: 'tkey-1'
266
- });
267
- });
268
- });
269
- describe('beforeDeleteOperation (via delete)', ()=>{
270
- it('rejects with ForbiddenException + messageKey when any target id is readonly', async ()=>{
271
- const readonlyKey = buildTranslationKey({
272
- id: 'tkey-1',
273
- isReadonly: true,
274
- key: 'system.core'
275
- });
276
- mockRepo.find.mockResolvedValue([
277
- readonlyKey
278
- ]);
279
- const dto = {
280
- id: [
281
- 'tkey-1'
282
- ],
283
- type: 'delete'
284
- };
285
- await expect(service.delete(dto, (0, _loggedusermock.buildMockUser)())).rejects.toMatchObject({
286
- response: expect.objectContaining({
287
- messageKey: 'translation.key.readonly.delete.forbidden'
288
- })
289
- });
290
- });
291
- it('allows delete when none of the targeted ids are readonly', async ()=>{
292
- mockRepo.find.mockResolvedValue([]);
293
- const dto = {
294
- id: [
295
- 'tkey-1'
296
- ],
297
- type: 'delete'
298
- };
299
- await expect(service.delete(dto, (0, _loggedusermock.buildMockUser)())).resolves.toBeNull();
300
- expect(queryRunner.manager.softDelete).toHaveBeenCalled();
301
- });
302
- });
303
- });
@@ -1,228 +0,0 @@
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 _config = require("../config");
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 TranslationService = class TranslationService extends _classes.ApiService {
46
- async getFilterQuery(query, filter, _user) {
47
- // Handle module filter by joining to translation_key table
48
- if (filter.module) {
49
- query.innerJoin('translation.translationKey', 'tk');
50
- query.andWhere('tk.module = :module', {
51
- module: filter.module
52
- });
53
- }
54
- // Handle standard filters on translation table
55
- if (filter.languageId) {
56
- query.andWhere('translation.languageId = :languageId', {
57
- languageId: filter.languageId
58
- });
59
- }
60
- if (filter.translationKeyId) {
61
- query.andWhere('translation.translationKeyId = :translationKeyId', {
62
- translationKeyId: filter.translationKeyId
63
- });
64
- }
65
- return {
66
- query,
67
- isRaw: false
68
- };
69
- }
70
- async ensureAllReposInitialized() {
71
- await this.ensureDataSourceRepository();
72
- if (!this.languageRepo) {
73
- const ds = await this.dataSourceProvider.getDataSource();
74
- this.languageRepo = ds.getRepository(_entities.Language);
75
- this.translationKeyRepo = ds.getRepository(_entities.TranslationKey);
76
- }
77
- }
78
- async getByLanguageCode(languageCode, modules) {
79
- await this.ensureAllReposInitialized();
80
- const language = await this.findActiveLanguageByCode(languageCode);
81
- if (!language) return {};
82
- const qb = this.repository.createQueryBuilder('t').innerJoinAndSelect('t.translationKey', 'tk').where('t.language_id = :languageId', {
83
- languageId: language.id
84
- }).andWhere('t.is_active = true').andWhere('t.deleted_at IS NULL').andWhere('tk.is_active = true').andWhere('tk.deleted_at IS NULL');
85
- if (modules && modules.length > 0) {
86
- qb.andWhere('tk.module IN (:...modules)', {
87
- modules
88
- });
89
- }
90
- return this.toTranslationsMap(await qb.getMany());
91
- }
92
- async getByModuleAndLanguage(module, languageCode) {
93
- await this.ensureAllReposInitialized();
94
- const language = await this.findActiveLanguageByCode(languageCode);
95
- if (!language) return {};
96
- const translations = await this.repository.createQueryBuilder('t').innerJoinAndSelect('t.translationKey', 'tk').where('t.language_id = :languageId', {
97
- languageId: language.id
98
- }).andWhere('tk.module = :module', {
99
- module
100
- }).andWhere('t.is_active = true').andWhere('t.deleted_at IS NULL').andWhere('tk.is_active = true').andWhere('tk.deleted_at IS NULL').getMany();
101
- return this.toTranslationsMap(translations);
102
- }
103
- async bulkUpdate(updates) {
104
- await this.ensureDataSourceRepository();
105
- if (updates.length === 0) return [];
106
- const ds = await this.dataSourceProvider.getDataSource();
107
- const queryRunner = ds.createQueryRunner();
108
- await queryRunner.connect();
109
- await queryRunner.startTransaction();
110
- try {
111
- const resultIds = [];
112
- for (const update of updates){
113
- if (update.id) {
114
- // Update existing translation
115
- await queryRunner.manager.update(_entities.Translation, {
116
- id: update.id
117
- }, {
118
- value: update.value,
119
- isVerified: update.isVerified ?? false
120
- });
121
- resultIds.push(update.id);
122
- } else {
123
- // Create new translation
124
- const newTranslation = queryRunner.manager.create(_entities.Translation, {
125
- languageId: update.languageId,
126
- translationKeyId: update.translationKeyId,
127
- value: update.value,
128
- isVerified: update.isVerified ?? false,
129
- isActive: true
130
- });
131
- const saved = await queryRunner.manager.save(newTranslation);
132
- resultIds.push(saved.id);
133
- }
134
- }
135
- await queryRunner.commitTransaction();
136
- const saved = await this.repository.find({
137
- where: {
138
- id: (0, _typeorm.In)(resultIds)
139
- }
140
- });
141
- await Promise.all([
142
- this.clearCacheForAll(),
143
- this.clearCacheForId(saved)
144
- ]);
145
- await this.publishDomainAction(_config.LOCALIZATION_EVENT_ACTIONS.BULK_UPDATED, {
146
- ids: saved.map((translation)=>translation.id),
147
- metadata: {
148
- count: saved.length
149
- }
150
- });
151
- return saved;
152
- } catch (error) {
153
- await queryRunner.rollbackTransaction();
154
- throw error;
155
- } finally{
156
- await queryRunner.release();
157
- }
158
- }
159
- async getMissingTranslations(languageCode) {
160
- await this.ensureAllReposInitialized();
161
- const language = await this.findActiveLanguageByCode(languageCode);
162
- if (!language) return [];
163
- if (!this.translationKeyRepo) return [];
164
- const allKeys = await this.translationKeyRepo.find({
165
- where: {
166
- isActive: true,
167
- deletedAt: (0, _typeorm.IsNull)()
168
- }
169
- });
170
- const existingTranslations = await this.repository.find({
171
- where: {
172
- languageId: language.id,
173
- isActive: true,
174
- deletedAt: (0, _typeorm.IsNull)()
175
- },
176
- select: [
177
- 'translationKeyId'
178
- ]
179
- });
180
- const existingKeyIds = new Set(existingTranslations.map((t)=>t.translationKeyId));
181
- return allKeys.filter((k)=>!existingKeyIds.has(k.id));
182
- }
183
- async getTranslationCounts() {
184
- await this.ensureDataSourceRepository();
185
- 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();
186
- const result = {};
187
- for (const row of counts){
188
- result[row.keyId] = parseInt(row.count, 10);
189
- }
190
- return result;
191
- }
192
- async findActiveLanguageByCode(code) {
193
- if (!this.languageRepo) return null;
194
- return this.languageRepo.findOne({
195
- where: {
196
- code,
197
- isActive: true,
198
- deletedAt: (0, _typeorm.IsNull)()
199
- }
200
- });
201
- }
202
- toTranslationsMap(translations) {
203
- const result = {};
204
- for (const t of translations){
205
- if (t.translationKey) {
206
- result[t.translationKey.key] = t.value;
207
- }
208
- }
209
- return result;
210
- }
211
- constructor(cacheManager, utilsService, dataSourceProvider){
212
- super(_config.LOCALIZATION_EVENT_ENTITIES.TRANSLATION, cacheManager, utilsService, TranslationService.name, true, _config.LOCALIZATION_EVENT_MODULE, dataSourceProvider, _entities.Translation), _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;
213
- }
214
- };
215
- TranslationService = _ts_decorate([
216
- (0, _common.Injectable)({
217
- scope: _common.Scope.REQUEST
218
- }),
219
- _ts_param(0, (0, _common.Inject)('CACHE_INSTANCE')),
220
- _ts_param(1, (0, _common.Inject)(_modules.UtilsService)),
221
- _ts_param(2, (0, _common.Inject)(_localizationdatasourceprovider.LocalizationDataSourceProvider)),
222
- _ts_metadata("design:type", Function),
223
- _ts_metadata("design:paramtypes", [
224
- typeof _classes.HybridCache === "undefined" ? Object : _classes.HybridCache,
225
- typeof _modules.UtilsService === "undefined" ? Object : _modules.UtilsService,
226
- typeof _localizationdatasourceprovider.LocalizationDataSourceProvider === "undefined" ? Object : _localizationdatasourceprovider.LocalizationDataSourceProvider
227
- ])
228
- ], TranslationService);