@abpjs/language-management 0.7.2
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/LICENSE +165 -0
- package/README.md +337 -0
- package/dist/index.d.mts +476 -0
- package/dist/index.d.ts +476 -0
- package/dist/index.js +1186 -0
- package/dist/index.mjs +1175 -0
- package/package.json +89 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,1175 @@
|
|
|
1
|
+
// src/constants/routes.ts
|
|
2
|
+
var LANGUAGE_MANAGEMENT_ROUTES = {
|
|
3
|
+
routes: [
|
|
4
|
+
{
|
|
5
|
+
name: "Languages",
|
|
6
|
+
path: "language-management",
|
|
7
|
+
layout: "application",
|
|
8
|
+
order: 101,
|
|
9
|
+
children: [
|
|
10
|
+
{
|
|
11
|
+
name: "Languages",
|
|
12
|
+
path: "languages",
|
|
13
|
+
order: 1
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "Language Texts",
|
|
17
|
+
path: "texts",
|
|
18
|
+
order: 2
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/services/language-management.service.ts
|
|
26
|
+
var LanguageManagementService = class {
|
|
27
|
+
constructor(rest) {
|
|
28
|
+
this.rest = rest;
|
|
29
|
+
}
|
|
30
|
+
// ========================
|
|
31
|
+
// Language Operations
|
|
32
|
+
// ========================
|
|
33
|
+
/**
|
|
34
|
+
* Get all languages with optional pagination
|
|
35
|
+
* @param params - Optional query parameters for pagination and filtering
|
|
36
|
+
* @returns Promise with paginated language response
|
|
37
|
+
*/
|
|
38
|
+
getLanguages(params = {}) {
|
|
39
|
+
return this.rest.request({
|
|
40
|
+
method: "GET",
|
|
41
|
+
url: "/api/language-management/languages",
|
|
42
|
+
params
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get a language by ID
|
|
47
|
+
* @param id - The language ID
|
|
48
|
+
* @returns Promise with the language
|
|
49
|
+
*/
|
|
50
|
+
getLanguageById(id) {
|
|
51
|
+
return this.rest.request({
|
|
52
|
+
method: "GET",
|
|
53
|
+
url: `/api/language-management/languages/${id}`
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a new language
|
|
58
|
+
* @param body - The language data to create
|
|
59
|
+
* @returns Promise with the created language
|
|
60
|
+
*/
|
|
61
|
+
createLanguage(body) {
|
|
62
|
+
return this.rest.request({
|
|
63
|
+
method: "POST",
|
|
64
|
+
url: "/api/language-management/languages",
|
|
65
|
+
body
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Update an existing language
|
|
70
|
+
* @param id - The language ID to update
|
|
71
|
+
* @param body - The updated language data
|
|
72
|
+
* @returns Promise with the updated language
|
|
73
|
+
*/
|
|
74
|
+
updateLanguage(id, body) {
|
|
75
|
+
return this.rest.request({
|
|
76
|
+
method: "PUT",
|
|
77
|
+
url: `/api/language-management/languages/${id}`,
|
|
78
|
+
body
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Delete a language
|
|
83
|
+
* @param id - The language ID to delete
|
|
84
|
+
* @returns Promise resolving when complete
|
|
85
|
+
*/
|
|
86
|
+
deleteLanguage(id) {
|
|
87
|
+
return this.rest.request({
|
|
88
|
+
method: "DELETE",
|
|
89
|
+
url: `/api/language-management/languages/${id}`
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set a language as the default language
|
|
94
|
+
* @param id - The language ID to set as default
|
|
95
|
+
* @returns Promise resolving when complete
|
|
96
|
+
*/
|
|
97
|
+
setAsDefaultLanguage(id) {
|
|
98
|
+
return this.rest.request({
|
|
99
|
+
method: "PUT",
|
|
100
|
+
url: `/api/language-management/languages/${id}/set-as-default`
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
// ========================
|
|
104
|
+
// Culture Operations
|
|
105
|
+
// ========================
|
|
106
|
+
/**
|
|
107
|
+
* Get all available cultures
|
|
108
|
+
* @returns Promise with list of cultures
|
|
109
|
+
*/
|
|
110
|
+
getCultures() {
|
|
111
|
+
return this.rest.request({
|
|
112
|
+
method: "GET",
|
|
113
|
+
url: "/api/language-management/languages/culture-list"
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// ========================
|
|
117
|
+
// Resource Operations
|
|
118
|
+
// ========================
|
|
119
|
+
/**
|
|
120
|
+
* Get all available localization resources
|
|
121
|
+
* @returns Promise with list of resources
|
|
122
|
+
*/
|
|
123
|
+
getResources() {
|
|
124
|
+
return this.rest.request({
|
|
125
|
+
method: "GET",
|
|
126
|
+
url: "/api/language-management/languages/resources"
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// ========================
|
|
130
|
+
// Language Text Operations
|
|
131
|
+
// ========================
|
|
132
|
+
/**
|
|
133
|
+
* Get language texts with pagination and filtering
|
|
134
|
+
* @param params - Query parameters including resource name, cultures, and filter options
|
|
135
|
+
* @returns Promise with paginated language text response
|
|
136
|
+
*/
|
|
137
|
+
getLanguageTexts(params) {
|
|
138
|
+
return this.rest.request({
|
|
139
|
+
method: "GET",
|
|
140
|
+
url: "/api/language-management/language-texts",
|
|
141
|
+
params
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get a language text by name
|
|
146
|
+
* @param params - Parameters identifying the language text
|
|
147
|
+
* @returns Promise with the language text
|
|
148
|
+
*/
|
|
149
|
+
getLanguageTextByName(params) {
|
|
150
|
+
return this.rest.request({
|
|
151
|
+
method: "GET",
|
|
152
|
+
url: "/api/language-management/language-texts",
|
|
153
|
+
params
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Update a language text by name
|
|
158
|
+
* @param params - Parameters including the new value
|
|
159
|
+
* @returns Promise with the updated language text
|
|
160
|
+
*/
|
|
161
|
+
updateLanguageTextByName(params) {
|
|
162
|
+
const { resourceName, cultureName, name, value } = params;
|
|
163
|
+
return this.rest.request({
|
|
164
|
+
method: "PUT",
|
|
165
|
+
url: `/api/language-management/language-texts/${resourceName}/${cultureName}/${name}`,
|
|
166
|
+
body: { value }
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Restore a language text to its default value
|
|
171
|
+
* @param params - Parameters identifying the language text
|
|
172
|
+
* @returns Promise resolving when complete
|
|
173
|
+
*/
|
|
174
|
+
restoreLanguageTextByName(params) {
|
|
175
|
+
const { resourceName, cultureName, name } = params;
|
|
176
|
+
return this.rest.request({
|
|
177
|
+
method: "PUT",
|
|
178
|
+
url: `/api/language-management/language-texts/${resourceName}/${cultureName}/${name}/restore`
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/hooks/useLanguages.ts
|
|
184
|
+
import { useState, useCallback, useMemo } from "react";
|
|
185
|
+
import { useRestService } from "@abpjs/core";
|
|
186
|
+
function useLanguages() {
|
|
187
|
+
const restService = useRestService();
|
|
188
|
+
const service = useMemo(() => new LanguageManagementService(restService), [restService]);
|
|
189
|
+
const [languages, setLanguages] = useState([]);
|
|
190
|
+
const [totalCount, setTotalCount] = useState(0);
|
|
191
|
+
const [cultures, setCultures] = useState([]);
|
|
192
|
+
const [selectedLanguage, setSelectedLanguage] = useState(
|
|
193
|
+
null
|
|
194
|
+
);
|
|
195
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
196
|
+
const [error, setError] = useState(null);
|
|
197
|
+
const [sortKey, setSortKey] = useState("displayName");
|
|
198
|
+
const [sortOrder, setSortOrder] = useState("");
|
|
199
|
+
const fetchLanguages = useCallback(
|
|
200
|
+
async (params) => {
|
|
201
|
+
setIsLoading(true);
|
|
202
|
+
setError(null);
|
|
203
|
+
try {
|
|
204
|
+
const response = await service.getLanguages(params);
|
|
205
|
+
setLanguages(response.items || []);
|
|
206
|
+
setTotalCount(response.totalCount || 0);
|
|
207
|
+
setIsLoading(false);
|
|
208
|
+
return { success: true };
|
|
209
|
+
} catch (err) {
|
|
210
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch languages";
|
|
211
|
+
setError(errorMessage);
|
|
212
|
+
setIsLoading(false);
|
|
213
|
+
return { success: false, error: errorMessage };
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
[service]
|
|
217
|
+
);
|
|
218
|
+
const fetchCultures = useCallback(async () => {
|
|
219
|
+
setIsLoading(true);
|
|
220
|
+
setError(null);
|
|
221
|
+
try {
|
|
222
|
+
const response = await service.getCultures();
|
|
223
|
+
setCultures(response || []);
|
|
224
|
+
setIsLoading(false);
|
|
225
|
+
return { success: true };
|
|
226
|
+
} catch (err) {
|
|
227
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch cultures";
|
|
228
|
+
setError(errorMessage);
|
|
229
|
+
setIsLoading(false);
|
|
230
|
+
return { success: false, error: errorMessage };
|
|
231
|
+
}
|
|
232
|
+
}, [service]);
|
|
233
|
+
const getLanguageById = useCallback(
|
|
234
|
+
async (id) => {
|
|
235
|
+
setIsLoading(true);
|
|
236
|
+
setError(null);
|
|
237
|
+
try {
|
|
238
|
+
const language = await service.getLanguageById(id);
|
|
239
|
+
setSelectedLanguage(language);
|
|
240
|
+
setIsLoading(false);
|
|
241
|
+
return { success: true };
|
|
242
|
+
} catch (err) {
|
|
243
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch language";
|
|
244
|
+
setError(errorMessage);
|
|
245
|
+
setIsLoading(false);
|
|
246
|
+
return { success: false, error: errorMessage };
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
[service]
|
|
250
|
+
);
|
|
251
|
+
const createLanguage = useCallback(
|
|
252
|
+
async (language) => {
|
|
253
|
+
setIsLoading(true);
|
|
254
|
+
setError(null);
|
|
255
|
+
try {
|
|
256
|
+
await service.createLanguage(language);
|
|
257
|
+
await fetchLanguages();
|
|
258
|
+
return { success: true };
|
|
259
|
+
} catch (err) {
|
|
260
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to create language";
|
|
261
|
+
setError(errorMessage);
|
|
262
|
+
setIsLoading(false);
|
|
263
|
+
return { success: false, error: errorMessage };
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
[service, fetchLanguages]
|
|
267
|
+
);
|
|
268
|
+
const updateLanguage = useCallback(
|
|
269
|
+
async (id, language) => {
|
|
270
|
+
setIsLoading(true);
|
|
271
|
+
setError(null);
|
|
272
|
+
try {
|
|
273
|
+
await service.updateLanguage(id, language);
|
|
274
|
+
await fetchLanguages();
|
|
275
|
+
return { success: true };
|
|
276
|
+
} catch (err) {
|
|
277
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update language";
|
|
278
|
+
setError(errorMessage);
|
|
279
|
+
setIsLoading(false);
|
|
280
|
+
return { success: false, error: errorMessage };
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
[service, fetchLanguages]
|
|
284
|
+
);
|
|
285
|
+
const deleteLanguage = useCallback(
|
|
286
|
+
async (id) => {
|
|
287
|
+
setIsLoading(true);
|
|
288
|
+
setError(null);
|
|
289
|
+
try {
|
|
290
|
+
await service.deleteLanguage(id);
|
|
291
|
+
await fetchLanguages();
|
|
292
|
+
return { success: true };
|
|
293
|
+
} catch (err) {
|
|
294
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to delete language";
|
|
295
|
+
setError(errorMessage);
|
|
296
|
+
setIsLoading(false);
|
|
297
|
+
return { success: false, error: errorMessage };
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
[service, fetchLanguages]
|
|
301
|
+
);
|
|
302
|
+
const setAsDefaultLanguage = useCallback(
|
|
303
|
+
async (id) => {
|
|
304
|
+
setIsLoading(true);
|
|
305
|
+
setError(null);
|
|
306
|
+
try {
|
|
307
|
+
await service.setAsDefaultLanguage(id);
|
|
308
|
+
await fetchLanguages();
|
|
309
|
+
return { success: true };
|
|
310
|
+
} catch (err) {
|
|
311
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to set language as default";
|
|
312
|
+
setError(errorMessage);
|
|
313
|
+
setIsLoading(false);
|
|
314
|
+
return { success: false, error: errorMessage };
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
[service, fetchLanguages]
|
|
318
|
+
);
|
|
319
|
+
const reset = useCallback(() => {
|
|
320
|
+
setLanguages([]);
|
|
321
|
+
setTotalCount(0);
|
|
322
|
+
setCultures([]);
|
|
323
|
+
setSelectedLanguage(null);
|
|
324
|
+
setIsLoading(false);
|
|
325
|
+
setError(null);
|
|
326
|
+
}, []);
|
|
327
|
+
return {
|
|
328
|
+
languages,
|
|
329
|
+
totalCount,
|
|
330
|
+
cultures,
|
|
331
|
+
selectedLanguage,
|
|
332
|
+
isLoading,
|
|
333
|
+
error,
|
|
334
|
+
sortKey,
|
|
335
|
+
sortOrder,
|
|
336
|
+
fetchLanguages,
|
|
337
|
+
fetchCultures,
|
|
338
|
+
getLanguageById,
|
|
339
|
+
createLanguage,
|
|
340
|
+
updateLanguage,
|
|
341
|
+
deleteLanguage,
|
|
342
|
+
setAsDefaultLanguage,
|
|
343
|
+
setSelectedLanguage,
|
|
344
|
+
setSortKey,
|
|
345
|
+
setSortOrder,
|
|
346
|
+
reset
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/hooks/useLanguageTexts.ts
|
|
351
|
+
import { useState as useState2, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
352
|
+
import { useRestService as useRestService2 } from "@abpjs/core";
|
|
353
|
+
function useLanguageTexts() {
|
|
354
|
+
const restService = useRestService2();
|
|
355
|
+
const service = useMemo2(() => new LanguageManagementService(restService), [restService]);
|
|
356
|
+
const [languageTexts, setLanguageTexts] = useState2([]);
|
|
357
|
+
const [totalCount, setTotalCount] = useState2(0);
|
|
358
|
+
const [resources, setResources] = useState2([]);
|
|
359
|
+
const [selectedLanguageText, setSelectedLanguageText] = useState2(null);
|
|
360
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
361
|
+
const [error, setError] = useState2(null);
|
|
362
|
+
const [sortKey, setSortKey] = useState2("name");
|
|
363
|
+
const [sortOrder, setSortOrder] = useState2("");
|
|
364
|
+
const [lastQueryParams, setLastQueryParams] = useState2(null);
|
|
365
|
+
const fetchLanguageTexts = useCallback2(
|
|
366
|
+
async (params) => {
|
|
367
|
+
setIsLoading(true);
|
|
368
|
+
setError(null);
|
|
369
|
+
setLastQueryParams(params);
|
|
370
|
+
try {
|
|
371
|
+
const response = await service.getLanguageTexts(params);
|
|
372
|
+
setLanguageTexts(response.items || []);
|
|
373
|
+
setTotalCount(response.totalCount || 0);
|
|
374
|
+
setIsLoading(false);
|
|
375
|
+
return { success: true };
|
|
376
|
+
} catch (err) {
|
|
377
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch language texts";
|
|
378
|
+
setError(errorMessage);
|
|
379
|
+
setIsLoading(false);
|
|
380
|
+
return { success: false, error: errorMessage };
|
|
381
|
+
}
|
|
382
|
+
},
|
|
383
|
+
[service]
|
|
384
|
+
);
|
|
385
|
+
const fetchResources = useCallback2(async () => {
|
|
386
|
+
setIsLoading(true);
|
|
387
|
+
setError(null);
|
|
388
|
+
try {
|
|
389
|
+
const response = await service.getResources();
|
|
390
|
+
setResources(response || []);
|
|
391
|
+
setIsLoading(false);
|
|
392
|
+
return { success: true };
|
|
393
|
+
} catch (err) {
|
|
394
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch resources";
|
|
395
|
+
setError(errorMessage);
|
|
396
|
+
setIsLoading(false);
|
|
397
|
+
return { success: false, error: errorMessage };
|
|
398
|
+
}
|
|
399
|
+
}, [service]);
|
|
400
|
+
const getLanguageTextByName = useCallback2(
|
|
401
|
+
async (params) => {
|
|
402
|
+
setIsLoading(true);
|
|
403
|
+
setError(null);
|
|
404
|
+
try {
|
|
405
|
+
const languageText = await service.getLanguageTextByName(params);
|
|
406
|
+
setSelectedLanguageText(languageText);
|
|
407
|
+
setIsLoading(false);
|
|
408
|
+
return { success: true };
|
|
409
|
+
} catch (err) {
|
|
410
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to fetch language text";
|
|
411
|
+
setError(errorMessage);
|
|
412
|
+
setIsLoading(false);
|
|
413
|
+
return { success: false, error: errorMessage };
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
[service]
|
|
417
|
+
);
|
|
418
|
+
const updateLanguageTextByName = useCallback2(
|
|
419
|
+
async (params) => {
|
|
420
|
+
setIsLoading(true);
|
|
421
|
+
setError(null);
|
|
422
|
+
try {
|
|
423
|
+
await service.updateLanguageTextByName(params);
|
|
424
|
+
if (lastQueryParams) {
|
|
425
|
+
await fetchLanguageTexts(lastQueryParams);
|
|
426
|
+
} else {
|
|
427
|
+
setIsLoading(false);
|
|
428
|
+
}
|
|
429
|
+
return { success: true };
|
|
430
|
+
} catch (err) {
|
|
431
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to update language text";
|
|
432
|
+
setError(errorMessage);
|
|
433
|
+
setIsLoading(false);
|
|
434
|
+
return { success: false, error: errorMessage };
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
[service, lastQueryParams, fetchLanguageTexts]
|
|
438
|
+
);
|
|
439
|
+
const restoreLanguageTextByName = useCallback2(
|
|
440
|
+
async (params) => {
|
|
441
|
+
setIsLoading(true);
|
|
442
|
+
setError(null);
|
|
443
|
+
try {
|
|
444
|
+
await service.restoreLanguageTextByName(params);
|
|
445
|
+
if (lastQueryParams) {
|
|
446
|
+
await fetchLanguageTexts(lastQueryParams);
|
|
447
|
+
} else {
|
|
448
|
+
setIsLoading(false);
|
|
449
|
+
}
|
|
450
|
+
return { success: true };
|
|
451
|
+
} catch (err) {
|
|
452
|
+
const errorMessage = err instanceof Error ? err.message : "Failed to restore language text";
|
|
453
|
+
setError(errorMessage);
|
|
454
|
+
setIsLoading(false);
|
|
455
|
+
return { success: false, error: errorMessage };
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
[service, lastQueryParams, fetchLanguageTexts]
|
|
459
|
+
);
|
|
460
|
+
const reset = useCallback2(() => {
|
|
461
|
+
setLanguageTexts([]);
|
|
462
|
+
setTotalCount(0);
|
|
463
|
+
setResources([]);
|
|
464
|
+
setSelectedLanguageText(null);
|
|
465
|
+
setIsLoading(false);
|
|
466
|
+
setError(null);
|
|
467
|
+
setLastQueryParams(null);
|
|
468
|
+
}, []);
|
|
469
|
+
return {
|
|
470
|
+
languageTexts,
|
|
471
|
+
totalCount,
|
|
472
|
+
resources,
|
|
473
|
+
selectedLanguageText,
|
|
474
|
+
isLoading,
|
|
475
|
+
error,
|
|
476
|
+
sortKey,
|
|
477
|
+
sortOrder,
|
|
478
|
+
fetchLanguageTexts,
|
|
479
|
+
fetchResources,
|
|
480
|
+
getLanguageTextByName,
|
|
481
|
+
updateLanguageTextByName,
|
|
482
|
+
restoreLanguageTextByName,
|
|
483
|
+
setSelectedLanguageText,
|
|
484
|
+
setSortKey,
|
|
485
|
+
setSortOrder,
|
|
486
|
+
reset
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/components/Languages/LanguagesComponent.tsx
|
|
491
|
+
import { useEffect, useState as useState3, useCallback as useCallback3 } from "react";
|
|
492
|
+
import { useLocalization } from "@abpjs/core";
|
|
493
|
+
import { Modal, useConfirmation, Toaster, Alert, Button, FormField } from "@abpjs/theme-shared";
|
|
494
|
+
import {
|
|
495
|
+
Box,
|
|
496
|
+
Flex,
|
|
497
|
+
Input,
|
|
498
|
+
Table,
|
|
499
|
+
Spinner,
|
|
500
|
+
VStack,
|
|
501
|
+
Menu,
|
|
502
|
+
Text,
|
|
503
|
+
Badge
|
|
504
|
+
} from "@chakra-ui/react";
|
|
505
|
+
import { NativeSelectRoot, NativeSelectField } from "@chakra-ui/react";
|
|
506
|
+
import { Checkbox } from "@chakra-ui/react";
|
|
507
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
508
|
+
var DEFAULT_FORM_STATE = {
|
|
509
|
+
cultureName: "",
|
|
510
|
+
uiCultureName: "",
|
|
511
|
+
displayName: "",
|
|
512
|
+
flagIcon: "",
|
|
513
|
+
isEnabled: true
|
|
514
|
+
};
|
|
515
|
+
function LanguagesComponent({
|
|
516
|
+
onLanguageCreated,
|
|
517
|
+
onLanguageUpdated,
|
|
518
|
+
onLanguageDeleted
|
|
519
|
+
}) {
|
|
520
|
+
const { t } = useLocalization();
|
|
521
|
+
const confirmation = useConfirmation();
|
|
522
|
+
const {
|
|
523
|
+
languages,
|
|
524
|
+
cultures,
|
|
525
|
+
selectedLanguage,
|
|
526
|
+
isLoading,
|
|
527
|
+
error,
|
|
528
|
+
fetchLanguages,
|
|
529
|
+
fetchCultures,
|
|
530
|
+
getLanguageById,
|
|
531
|
+
createLanguage,
|
|
532
|
+
updateLanguage,
|
|
533
|
+
deleteLanguage,
|
|
534
|
+
setAsDefaultLanguage,
|
|
535
|
+
setSelectedLanguage
|
|
536
|
+
} = useLanguages();
|
|
537
|
+
const [isModalOpen, setIsModalOpen] = useState3(false);
|
|
538
|
+
const [formState, setFormState] = useState3(DEFAULT_FORM_STATE);
|
|
539
|
+
const [isSubmitting, setIsSubmitting] = useState3(false);
|
|
540
|
+
const [isEditing, setIsEditing] = useState3(false);
|
|
541
|
+
const [searchTerm, setSearchTerm] = useState3("");
|
|
542
|
+
useEffect(() => {
|
|
543
|
+
fetchLanguages();
|
|
544
|
+
fetchCultures();
|
|
545
|
+
}, [fetchLanguages, fetchCultures]);
|
|
546
|
+
const filteredLanguages = languages.filter(
|
|
547
|
+
(lang) => !searchTerm || lang.displayName.toLowerCase().includes(searchTerm.toLowerCase()) || lang.cultureName.toLowerCase().includes(searchTerm.toLowerCase())
|
|
548
|
+
);
|
|
549
|
+
const handleAdd = useCallback3(() => {
|
|
550
|
+
setSelectedLanguage(null);
|
|
551
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
552
|
+
setIsEditing(false);
|
|
553
|
+
setIsModalOpen(true);
|
|
554
|
+
}, [setSelectedLanguage]);
|
|
555
|
+
const handleEdit = useCallback3(
|
|
556
|
+
async (id) => {
|
|
557
|
+
const result = await getLanguageById(id);
|
|
558
|
+
if (result.success) {
|
|
559
|
+
setIsEditing(true);
|
|
560
|
+
setIsModalOpen(true);
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
[getLanguageById]
|
|
564
|
+
);
|
|
565
|
+
useEffect(() => {
|
|
566
|
+
if (selectedLanguage && isEditing) {
|
|
567
|
+
setFormState({
|
|
568
|
+
cultureName: selectedLanguage.cultureName || "",
|
|
569
|
+
uiCultureName: selectedLanguage.uiCultureName || "",
|
|
570
|
+
displayName: selectedLanguage.displayName || "",
|
|
571
|
+
flagIcon: selectedLanguage.flagIcon || "",
|
|
572
|
+
isEnabled: selectedLanguage.isEnabled ?? true
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}, [selectedLanguage, isEditing]);
|
|
576
|
+
const handleDelete = useCallback3(
|
|
577
|
+
async (id, displayName) => {
|
|
578
|
+
const status = await confirmation.warn(
|
|
579
|
+
t("AbpLanguageManagement::LanguageDeletionConfirmationMessage", displayName) || `Are you sure you want to delete the language '${displayName}'?`,
|
|
580
|
+
t("AbpLanguageManagement::AreYouSure") || "Are you sure?"
|
|
581
|
+
);
|
|
582
|
+
if (status === Toaster.Status.confirm) {
|
|
583
|
+
const result = await deleteLanguage(id);
|
|
584
|
+
if (result.success) {
|
|
585
|
+
onLanguageDeleted?.(id);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
[confirmation, t, deleteLanguage, onLanguageDeleted]
|
|
590
|
+
);
|
|
591
|
+
const handleSetAsDefault = useCallback3(
|
|
592
|
+
async (id) => {
|
|
593
|
+
const status = await confirmation.info(
|
|
594
|
+
t("AbpLanguageManagement::SetAsDefaultLanguageConfirmationMessage") || "Are you sure you want to set this language as the default?",
|
|
595
|
+
t("AbpLanguageManagement::AreYouSure") || "Are you sure?"
|
|
596
|
+
);
|
|
597
|
+
if (status === Toaster.Status.confirm) {
|
|
598
|
+
await setAsDefaultLanguage(id);
|
|
599
|
+
}
|
|
600
|
+
},
|
|
601
|
+
[confirmation, t, setAsDefaultLanguage]
|
|
602
|
+
);
|
|
603
|
+
const handleSubmit = useCallback3(async () => {
|
|
604
|
+
if (!isEditing && !formState.cultureName) return;
|
|
605
|
+
if (!formState.displayName.trim()) return;
|
|
606
|
+
setIsSubmitting(true);
|
|
607
|
+
let result;
|
|
608
|
+
if (isEditing && selectedLanguage?.id) {
|
|
609
|
+
const updateData = {
|
|
610
|
+
displayName: formState.displayName.trim(),
|
|
611
|
+
flagIcon: formState.flagIcon,
|
|
612
|
+
isEnabled: formState.isEnabled
|
|
613
|
+
};
|
|
614
|
+
result = await updateLanguage(selectedLanguage.id, updateData);
|
|
615
|
+
if (result.success) {
|
|
616
|
+
onLanguageUpdated?.({
|
|
617
|
+
...selectedLanguage,
|
|
618
|
+
...updateData
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
} else {
|
|
622
|
+
const createData = {
|
|
623
|
+
cultureName: formState.cultureName,
|
|
624
|
+
uiCultureName: formState.uiCultureName || formState.cultureName,
|
|
625
|
+
displayName: formState.displayName.trim(),
|
|
626
|
+
flagIcon: formState.flagIcon,
|
|
627
|
+
isEnabled: formState.isEnabled
|
|
628
|
+
};
|
|
629
|
+
result = await createLanguage(createData);
|
|
630
|
+
if (result.success) {
|
|
631
|
+
onLanguageCreated?.({
|
|
632
|
+
id: "",
|
|
633
|
+
creationTime: (/* @__PURE__ */ new Date()).toISOString(),
|
|
634
|
+
creatorId: "",
|
|
635
|
+
isDefaultLanguage: false,
|
|
636
|
+
...createData
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
setIsSubmitting(false);
|
|
641
|
+
if (result.success) {
|
|
642
|
+
setIsModalOpen(false);
|
|
643
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
644
|
+
setSelectedLanguage(null);
|
|
645
|
+
setIsEditing(false);
|
|
646
|
+
}
|
|
647
|
+
}, [
|
|
648
|
+
formState,
|
|
649
|
+
isEditing,
|
|
650
|
+
selectedLanguage,
|
|
651
|
+
updateLanguage,
|
|
652
|
+
createLanguage,
|
|
653
|
+
onLanguageCreated,
|
|
654
|
+
onLanguageUpdated,
|
|
655
|
+
setSelectedLanguage
|
|
656
|
+
]);
|
|
657
|
+
const handleModalClose = useCallback3(() => {
|
|
658
|
+
setIsModalOpen(false);
|
|
659
|
+
setFormState(DEFAULT_FORM_STATE);
|
|
660
|
+
setSelectedLanguage(null);
|
|
661
|
+
setIsEditing(false);
|
|
662
|
+
}, [setSelectedLanguage]);
|
|
663
|
+
const handleInputChange = useCallback3(
|
|
664
|
+
(field, value) => {
|
|
665
|
+
setFormState((prev) => ({ ...prev, [field]: value }));
|
|
666
|
+
},
|
|
667
|
+
[]
|
|
668
|
+
);
|
|
669
|
+
const handleCultureChange = useCallback3(
|
|
670
|
+
(cultureName) => {
|
|
671
|
+
setFormState((prev) => ({
|
|
672
|
+
...prev,
|
|
673
|
+
cultureName,
|
|
674
|
+
uiCultureName: cultureName
|
|
675
|
+
}));
|
|
676
|
+
const culture = cultures.find((c) => c.name === cultureName);
|
|
677
|
+
if (culture) {
|
|
678
|
+
setFormState((prev) => ({
|
|
679
|
+
...prev,
|
|
680
|
+
displayName: culture.displayName
|
|
681
|
+
}));
|
|
682
|
+
}
|
|
683
|
+
},
|
|
684
|
+
[cultures]
|
|
685
|
+
);
|
|
686
|
+
return /* @__PURE__ */ jsxs(Box, { id: "language-management-languages-wrapper", className: "card", p: 4, children: [
|
|
687
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", mb: 4, children: [
|
|
688
|
+
/* @__PURE__ */ jsx(Text, { fontSize: "xl", fontWeight: "bold", children: t("AbpLanguageManagement::Languages") || "Languages" }),
|
|
689
|
+
/* @__PURE__ */ jsx(Button, { colorPalette: "blue", onClick: handleAdd, children: t("AbpLanguageManagement::NewLanguage") || "New Language" })
|
|
690
|
+
] }),
|
|
691
|
+
/* @__PURE__ */ jsx(Box, { mb: 4, children: /* @__PURE__ */ jsx(
|
|
692
|
+
Input,
|
|
693
|
+
{
|
|
694
|
+
placeholder: t("AbpLanguageManagement::Search") || "Search...",
|
|
695
|
+
value: searchTerm,
|
|
696
|
+
onChange: (e) => setSearchTerm(e.target.value),
|
|
697
|
+
maxW: "300px"
|
|
698
|
+
}
|
|
699
|
+
) }),
|
|
700
|
+
error && /* @__PURE__ */ jsx(Alert, { status: "error", mb: 4, children: error }),
|
|
701
|
+
isLoading && languages.length === 0 && /* @__PURE__ */ jsx(Flex, { justify: "center", py: 8, children: /* @__PURE__ */ jsx(Spinner, { size: "lg" }) }),
|
|
702
|
+
languages.length > 0 && /* @__PURE__ */ jsxs(Table.Root, { variant: "outline", children: [
|
|
703
|
+
/* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
704
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::Actions") || "Actions" }),
|
|
705
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::DisplayName") || "Display Name" }),
|
|
706
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::CultureName") || "Culture Name" }),
|
|
707
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::UiCultureName") || "UI Culture Name" }),
|
|
708
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::IsEnabled") || "Enabled" }),
|
|
709
|
+
/* @__PURE__ */ jsx(Table.ColumnHeader, { children: t("AbpLanguageManagement::IsDefaultLanguage") || "Default" })
|
|
710
|
+
] }) }),
|
|
711
|
+
/* @__PURE__ */ jsx(Table.Body, { children: filteredLanguages.map((language) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
|
712
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs(Menu.Root, { children: [
|
|
713
|
+
/* @__PURE__ */ jsx(Menu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "sm", colorPalette: "blue", children: t("AbpLanguageManagement::Actions") || "Actions" }) }),
|
|
714
|
+
/* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsxs(Menu.Content, { children: [
|
|
715
|
+
/* @__PURE__ */ jsx(Menu.Item, { value: "edit", onClick: () => handleEdit(language.id), children: t("AbpLanguageManagement::Edit") || "Edit" }),
|
|
716
|
+
!language.isDefaultLanguage && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
717
|
+
/* @__PURE__ */ jsx(
|
|
718
|
+
Menu.Item,
|
|
719
|
+
{
|
|
720
|
+
value: "setDefault",
|
|
721
|
+
onClick: () => handleSetAsDefault(language.id),
|
|
722
|
+
children: t("AbpLanguageManagement::SetAsDefaultLanguage") || "Set as Default"
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ jsx(
|
|
726
|
+
Menu.Item,
|
|
727
|
+
{
|
|
728
|
+
value: "delete",
|
|
729
|
+
color: "red.500",
|
|
730
|
+
onClick: () => handleDelete(language.id, language.displayName),
|
|
731
|
+
children: t("AbpLanguageManagement::Delete") || "Delete"
|
|
732
|
+
}
|
|
733
|
+
)
|
|
734
|
+
] })
|
|
735
|
+
] }) })
|
|
736
|
+
] }) }),
|
|
737
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
738
|
+
language.flagIcon && /* @__PURE__ */ jsx(Text, { children: language.flagIcon }),
|
|
739
|
+
language.displayName
|
|
740
|
+
] }) }),
|
|
741
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: language.cultureName }),
|
|
742
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: language.uiCultureName }),
|
|
743
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Badge, { colorPalette: language.isEnabled ? "green" : "red", children: language.isEnabled ? t("AbpLanguageManagement::Yes") || "Yes" : t("AbpLanguageManagement::No") || "No" }) }),
|
|
744
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: language.isDefaultLanguage && /* @__PURE__ */ jsx(Badge, { colorPalette: "blue", children: t("AbpLanguageManagement::Default") || "Default" }) })
|
|
745
|
+
] }, language.id)) })
|
|
746
|
+
] }),
|
|
747
|
+
!isLoading && languages.length === 0 && /* @__PURE__ */ jsx(Text, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpLanguageManagement::NoLanguagesFound") || "No languages found" }),
|
|
748
|
+
/* @__PURE__ */ jsx(
|
|
749
|
+
Modal,
|
|
750
|
+
{
|
|
751
|
+
visible: isModalOpen,
|
|
752
|
+
onVisibleChange: setIsModalOpen,
|
|
753
|
+
header: isEditing ? t("AbpLanguageManagement::Edit") || "Edit" : t("AbpLanguageManagement::NewLanguage") || "New Language",
|
|
754
|
+
footer: /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
755
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: handleModalClose, disabled: isSubmitting, children: t("AbpLanguageManagement::Cancel") || "Cancel" }),
|
|
756
|
+
/* @__PURE__ */ jsx(
|
|
757
|
+
Button,
|
|
758
|
+
{
|
|
759
|
+
colorPalette: "blue",
|
|
760
|
+
onClick: handleSubmit,
|
|
761
|
+
loading: isSubmitting,
|
|
762
|
+
disabled: !formState.displayName.trim() || !isEditing && !formState.cultureName,
|
|
763
|
+
children: t("AbpLanguageManagement::Save") || "Save"
|
|
764
|
+
}
|
|
765
|
+
)
|
|
766
|
+
] }),
|
|
767
|
+
children: /* @__PURE__ */ jsxs(VStack, { gap: 4, align: "stretch", children: [
|
|
768
|
+
!isEditing && /* @__PURE__ */ jsx(FormField, { label: t("AbpLanguageManagement::CultureName") || "Culture", required: true, children: /* @__PURE__ */ jsx(NativeSelectRoot, { children: /* @__PURE__ */ jsxs(
|
|
769
|
+
NativeSelectField,
|
|
770
|
+
{
|
|
771
|
+
value: formState.cultureName,
|
|
772
|
+
onChange: (e) => handleCultureChange(e.target.value),
|
|
773
|
+
children: [
|
|
774
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("AbpLanguageManagement::SelectCulture") || "Select a culture..." }),
|
|
775
|
+
cultures.map((culture) => /* @__PURE__ */ jsxs("option", { value: culture.name, children: [
|
|
776
|
+
culture.displayName,
|
|
777
|
+
" (",
|
|
778
|
+
culture.name,
|
|
779
|
+
")"
|
|
780
|
+
] }, culture.name))
|
|
781
|
+
]
|
|
782
|
+
}
|
|
783
|
+
) }) }),
|
|
784
|
+
!isEditing && /* @__PURE__ */ jsx(FormField, { label: t("AbpLanguageManagement::UiCultureName") || "UI Culture", children: /* @__PURE__ */ jsx(NativeSelectRoot, { children: /* @__PURE__ */ jsxs(
|
|
785
|
+
NativeSelectField,
|
|
786
|
+
{
|
|
787
|
+
value: formState.uiCultureName,
|
|
788
|
+
onChange: (e) => handleInputChange("uiCultureName", e.target.value),
|
|
789
|
+
children: [
|
|
790
|
+
/* @__PURE__ */ jsx("option", { value: "", children: t("AbpLanguageManagement::SameAsCulture") || "Same as culture" }),
|
|
791
|
+
cultures.map((culture) => /* @__PURE__ */ jsxs("option", { value: culture.name, children: [
|
|
792
|
+
culture.displayName,
|
|
793
|
+
" (",
|
|
794
|
+
culture.name,
|
|
795
|
+
")"
|
|
796
|
+
] }, culture.name))
|
|
797
|
+
]
|
|
798
|
+
}
|
|
799
|
+
) }) }),
|
|
800
|
+
/* @__PURE__ */ jsx(FormField, { label: t("AbpLanguageManagement::DisplayName") || "Display Name", required: true, children: /* @__PURE__ */ jsx(
|
|
801
|
+
Input,
|
|
802
|
+
{
|
|
803
|
+
value: formState.displayName,
|
|
804
|
+
onChange: (e) => handleInputChange("displayName", e.target.value),
|
|
805
|
+
maxLength: 128,
|
|
806
|
+
placeholder: t("AbpLanguageManagement::DisplayName") || "Display Name"
|
|
807
|
+
}
|
|
808
|
+
) }),
|
|
809
|
+
/* @__PURE__ */ jsx(FormField, { label: t("AbpLanguageManagement::FlagIcon") || "Flag Icon", children: /* @__PURE__ */ jsx(
|
|
810
|
+
Input,
|
|
811
|
+
{
|
|
812
|
+
value: formState.flagIcon,
|
|
813
|
+
onChange: (e) => handleInputChange("flagIcon", e.target.value),
|
|
814
|
+
maxLength: 48,
|
|
815
|
+
placeholder: t("AbpLanguageManagement::FlagIcon") || "Flag icon (e.g., emoji)"
|
|
816
|
+
}
|
|
817
|
+
) }),
|
|
818
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(
|
|
819
|
+
Checkbox.Root,
|
|
820
|
+
{
|
|
821
|
+
checked: formState.isEnabled,
|
|
822
|
+
onCheckedChange: (e) => handleInputChange("isEnabled", !!e.checked),
|
|
823
|
+
children: [
|
|
824
|
+
/* @__PURE__ */ jsx(Checkbox.HiddenInput, {}),
|
|
825
|
+
/* @__PURE__ */ jsx(Checkbox.Control, {}),
|
|
826
|
+
/* @__PURE__ */ jsx(Checkbox.Label, { children: t("AbpLanguageManagement::IsEnabled") || "Enabled" })
|
|
827
|
+
]
|
|
828
|
+
}
|
|
829
|
+
) })
|
|
830
|
+
] })
|
|
831
|
+
}
|
|
832
|
+
)
|
|
833
|
+
] });
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// src/components/LanguageTexts/LanguageTextsComponent.tsx
|
|
837
|
+
import { useEffect as useEffect2, useState as useState4, useCallback as useCallback4 } from "react";
|
|
838
|
+
import { useLocalization as useLocalization2 } from "@abpjs/core";
|
|
839
|
+
import { Modal as Modal2, useConfirmation as useConfirmation2, Toaster as Toaster2, Alert as Alert2, Button as Button2, FormField as FormField2 } from "@abpjs/theme-shared";
|
|
840
|
+
import {
|
|
841
|
+
Box as Box2,
|
|
842
|
+
Flex as Flex2,
|
|
843
|
+
Input as Input2,
|
|
844
|
+
Table as Table2,
|
|
845
|
+
Spinner as Spinner2,
|
|
846
|
+
VStack as VStack2,
|
|
847
|
+
Menu as Menu2,
|
|
848
|
+
Text as Text2,
|
|
849
|
+
Textarea,
|
|
850
|
+
HStack
|
|
851
|
+
} from "@chakra-ui/react";
|
|
852
|
+
import { NativeSelectRoot as NativeSelectRoot2, NativeSelectField as NativeSelectField2 } from "@chakra-ui/react";
|
|
853
|
+
import { Checkbox as Checkbox2 } from "@chakra-ui/react";
|
|
854
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
855
|
+
var DEFAULT_FILTER_STATE = {
|
|
856
|
+
resourceName: "",
|
|
857
|
+
baseCultureName: "",
|
|
858
|
+
targetCultureName: "",
|
|
859
|
+
filter: "",
|
|
860
|
+
getOnlyEmptyValues: false
|
|
861
|
+
};
|
|
862
|
+
function LanguageTextsComponent({
|
|
863
|
+
onLanguageTextUpdated,
|
|
864
|
+
onLanguageTextRestored
|
|
865
|
+
}) {
|
|
866
|
+
const { t } = useLocalization2();
|
|
867
|
+
const confirmation = useConfirmation2();
|
|
868
|
+
const { languages, fetchLanguages } = useLanguages();
|
|
869
|
+
const {
|
|
870
|
+
languageTexts,
|
|
871
|
+
totalCount,
|
|
872
|
+
resources,
|
|
873
|
+
selectedLanguageText,
|
|
874
|
+
isLoading,
|
|
875
|
+
error,
|
|
876
|
+
fetchLanguageTexts,
|
|
877
|
+
fetchResources,
|
|
878
|
+
updateLanguageTextByName,
|
|
879
|
+
restoreLanguageTextByName,
|
|
880
|
+
setSelectedLanguageText
|
|
881
|
+
} = useLanguageTexts();
|
|
882
|
+
const [filterState, setFilterState] = useState4(DEFAULT_FILTER_STATE);
|
|
883
|
+
const [isModalOpen, setIsModalOpen] = useState4(false);
|
|
884
|
+
const [editValue, setEditValue] = useState4("");
|
|
885
|
+
const [isSubmitting, setIsSubmitting] = useState4(false);
|
|
886
|
+
const [currentPage, setCurrentPage] = useState4(0);
|
|
887
|
+
const [pageSize] = useState4(10);
|
|
888
|
+
useEffect2(() => {
|
|
889
|
+
fetchLanguages();
|
|
890
|
+
fetchResources();
|
|
891
|
+
}, [fetchLanguages, fetchResources]);
|
|
892
|
+
useEffect2(() => {
|
|
893
|
+
if (languages.length > 0 && !filterState.baseCultureName) {
|
|
894
|
+
const defaultLanguage = languages.find((l) => l.isDefaultLanguage);
|
|
895
|
+
const baseCulture = defaultLanguage?.cultureName || languages[0]?.cultureName || "en";
|
|
896
|
+
const targetCulture = languages.find((l) => !l.isDefaultLanguage)?.cultureName || baseCulture;
|
|
897
|
+
setFilterState((prev) => ({
|
|
898
|
+
...prev,
|
|
899
|
+
baseCultureName: baseCulture,
|
|
900
|
+
targetCultureName: targetCulture
|
|
901
|
+
}));
|
|
902
|
+
}
|
|
903
|
+
}, [languages, filterState.baseCultureName]);
|
|
904
|
+
const loadLanguageTexts = useCallback4(
|
|
905
|
+
async (page = currentPage) => {
|
|
906
|
+
if (!filterState.baseCultureName || !filterState.targetCultureName) return;
|
|
907
|
+
await fetchLanguageTexts({
|
|
908
|
+
resourceName: filterState.resourceName || void 0,
|
|
909
|
+
baseCultureName: filterState.baseCultureName,
|
|
910
|
+
targetCultureName: filterState.targetCultureName,
|
|
911
|
+
getOnlyEmptyValues: filterState.getOnlyEmptyValues,
|
|
912
|
+
filter: filterState.filter || void 0,
|
|
913
|
+
skipCount: page * pageSize,
|
|
914
|
+
maxResultCount: pageSize
|
|
915
|
+
});
|
|
916
|
+
},
|
|
917
|
+
[filterState, currentPage, pageSize, fetchLanguageTexts]
|
|
918
|
+
);
|
|
919
|
+
useEffect2(() => {
|
|
920
|
+
if (filterState.baseCultureName && filterState.targetCultureName) {
|
|
921
|
+
setCurrentPage(0);
|
|
922
|
+
loadLanguageTexts(0);
|
|
923
|
+
}
|
|
924
|
+
}, [
|
|
925
|
+
filterState.baseCultureName,
|
|
926
|
+
filterState.targetCultureName,
|
|
927
|
+
filterState.resourceName,
|
|
928
|
+
filterState.getOnlyEmptyValues
|
|
929
|
+
]);
|
|
930
|
+
const handleSearch = useCallback4(() => {
|
|
931
|
+
setCurrentPage(0);
|
|
932
|
+
loadLanguageTexts(0);
|
|
933
|
+
}, [loadLanguageTexts]);
|
|
934
|
+
const handleEdit = useCallback4(
|
|
935
|
+
(languageText) => {
|
|
936
|
+
setSelectedLanguageText(languageText);
|
|
937
|
+
setEditValue(languageText.value || "");
|
|
938
|
+
setIsModalOpen(true);
|
|
939
|
+
},
|
|
940
|
+
[setSelectedLanguageText]
|
|
941
|
+
);
|
|
942
|
+
const handleRestore = useCallback4(
|
|
943
|
+
async (languageText) => {
|
|
944
|
+
const status = await confirmation.warn(
|
|
945
|
+
t("AbpLanguageManagement::RestoreToDefaultConfirmationMessage") || "Are you sure you want to restore this text to its default value?",
|
|
946
|
+
t("AbpLanguageManagement::AreYouSure") || "Are you sure?"
|
|
947
|
+
);
|
|
948
|
+
if (status === Toaster2.Status.confirm) {
|
|
949
|
+
const params = {
|
|
950
|
+
resourceName: languageText.resourceName,
|
|
951
|
+
cultureName: languageText.cultureName,
|
|
952
|
+
name: languageText.name
|
|
953
|
+
};
|
|
954
|
+
const result = await restoreLanguageTextByName(params);
|
|
955
|
+
if (result.success) {
|
|
956
|
+
onLanguageTextRestored?.(params);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
},
|
|
960
|
+
[confirmation, t, restoreLanguageTextByName, onLanguageTextRestored]
|
|
961
|
+
);
|
|
962
|
+
const handleSubmit = useCallback4(async () => {
|
|
963
|
+
if (!selectedLanguageText) return;
|
|
964
|
+
setIsSubmitting(true);
|
|
965
|
+
const params = {
|
|
966
|
+
resourceName: selectedLanguageText.resourceName,
|
|
967
|
+
cultureName: selectedLanguageText.cultureName,
|
|
968
|
+
name: selectedLanguageText.name,
|
|
969
|
+
value: editValue
|
|
970
|
+
};
|
|
971
|
+
const result = await updateLanguageTextByName(params);
|
|
972
|
+
setIsSubmitting(false);
|
|
973
|
+
if (result.success) {
|
|
974
|
+
onLanguageTextUpdated?.(params);
|
|
975
|
+
setIsModalOpen(false);
|
|
976
|
+
setSelectedLanguageText(null);
|
|
977
|
+
setEditValue("");
|
|
978
|
+
}
|
|
979
|
+
}, [selectedLanguageText, editValue, updateLanguageTextByName, onLanguageTextUpdated, setSelectedLanguageText]);
|
|
980
|
+
const handleModalClose = useCallback4(() => {
|
|
981
|
+
setIsModalOpen(false);
|
|
982
|
+
setSelectedLanguageText(null);
|
|
983
|
+
setEditValue("");
|
|
984
|
+
}, [setSelectedLanguageText]);
|
|
985
|
+
const handleFilterChange = useCallback4(
|
|
986
|
+
(field, value) => {
|
|
987
|
+
setFilterState((prev) => ({ ...prev, [field]: value }));
|
|
988
|
+
},
|
|
989
|
+
[]
|
|
990
|
+
);
|
|
991
|
+
const handlePageChange = useCallback4(
|
|
992
|
+
(newPage) => {
|
|
993
|
+
setCurrentPage(newPage);
|
|
994
|
+
loadLanguageTexts(newPage);
|
|
995
|
+
},
|
|
996
|
+
[loadLanguageTexts]
|
|
997
|
+
);
|
|
998
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
999
|
+
return /* @__PURE__ */ jsxs2(Box2, { id: "language-management-texts-wrapper", className: "card", p: 4, children: [
|
|
1000
|
+
/* @__PURE__ */ jsx2(Flex2, { justify: "space-between", align: "center", mb: 4, children: /* @__PURE__ */ jsx2(Text2, { fontSize: "xl", fontWeight: "bold", children: t("AbpLanguageManagement::LanguageTexts") || "Language Texts" }) }),
|
|
1001
|
+
/* @__PURE__ */ jsxs2(VStack2, { gap: 4, align: "stretch", mb: 4, children: [
|
|
1002
|
+
/* @__PURE__ */ jsxs2(HStack, { gap: 4, flexWrap: "wrap", children: [
|
|
1003
|
+
/* @__PURE__ */ jsx2(Box2, { flex: "1", minW: "200px", children: /* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::Resource") || "Resource", children: /* @__PURE__ */ jsx2(NativeSelectRoot2, { children: /* @__PURE__ */ jsxs2(
|
|
1004
|
+
NativeSelectField2,
|
|
1005
|
+
{
|
|
1006
|
+
value: filterState.resourceName,
|
|
1007
|
+
onChange: (e) => handleFilterChange("resourceName", e.target.value),
|
|
1008
|
+
children: [
|
|
1009
|
+
/* @__PURE__ */ jsx2("option", { value: "", children: t("AbpLanguageManagement::AllResources") || "All Resources" }),
|
|
1010
|
+
resources.map((resource) => /* @__PURE__ */ jsx2("option", { value: resource.name, children: resource.name }, resource.name))
|
|
1011
|
+
]
|
|
1012
|
+
}
|
|
1013
|
+
) }) }) }),
|
|
1014
|
+
/* @__PURE__ */ jsx2(Box2, { flex: "1", minW: "200px", children: /* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::BaseCulture") || "Base Culture", children: /* @__PURE__ */ jsx2(NativeSelectRoot2, { children: /* @__PURE__ */ jsx2(
|
|
1015
|
+
NativeSelectField2,
|
|
1016
|
+
{
|
|
1017
|
+
value: filterState.baseCultureName,
|
|
1018
|
+
onChange: (e) => handleFilterChange("baseCultureName", e.target.value),
|
|
1019
|
+
children: languages.map((lang) => /* @__PURE__ */ jsxs2("option", { value: lang.cultureName, children: [
|
|
1020
|
+
lang.displayName,
|
|
1021
|
+
" (",
|
|
1022
|
+
lang.cultureName,
|
|
1023
|
+
")"
|
|
1024
|
+
] }, lang.cultureName))
|
|
1025
|
+
}
|
|
1026
|
+
) }) }) }),
|
|
1027
|
+
/* @__PURE__ */ jsx2(Box2, { flex: "1", minW: "200px", children: /* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::TargetCulture") || "Target Culture", children: /* @__PURE__ */ jsx2(NativeSelectRoot2, { children: /* @__PURE__ */ jsx2(
|
|
1028
|
+
NativeSelectField2,
|
|
1029
|
+
{
|
|
1030
|
+
value: filterState.targetCultureName,
|
|
1031
|
+
onChange: (e) => handleFilterChange("targetCultureName", e.target.value),
|
|
1032
|
+
children: languages.map((lang) => /* @__PURE__ */ jsxs2("option", { value: lang.cultureName, children: [
|
|
1033
|
+
lang.displayName,
|
|
1034
|
+
" (",
|
|
1035
|
+
lang.cultureName,
|
|
1036
|
+
")"
|
|
1037
|
+
] }, lang.cultureName))
|
|
1038
|
+
}
|
|
1039
|
+
) }) }) })
|
|
1040
|
+
] }),
|
|
1041
|
+
/* @__PURE__ */ jsxs2(HStack, { gap: 4, children: [
|
|
1042
|
+
/* @__PURE__ */ jsx2(
|
|
1043
|
+
Input2,
|
|
1044
|
+
{
|
|
1045
|
+
placeholder: t("AbpLanguageManagement::Filter") || "Filter by key or value...",
|
|
1046
|
+
value: filterState.filter,
|
|
1047
|
+
onChange: (e) => handleFilterChange("filter", e.target.value),
|
|
1048
|
+
onKeyDown: (e) => e.key === "Enter" && handleSearch(),
|
|
1049
|
+
flex: "1"
|
|
1050
|
+
}
|
|
1051
|
+
),
|
|
1052
|
+
/* @__PURE__ */ jsxs2(
|
|
1053
|
+
Checkbox2.Root,
|
|
1054
|
+
{
|
|
1055
|
+
checked: filterState.getOnlyEmptyValues,
|
|
1056
|
+
onCheckedChange: (e) => handleFilterChange("getOnlyEmptyValues", !!e.checked),
|
|
1057
|
+
children: [
|
|
1058
|
+
/* @__PURE__ */ jsx2(Checkbox2.HiddenInput, {}),
|
|
1059
|
+
/* @__PURE__ */ jsx2(Checkbox2.Control, {}),
|
|
1060
|
+
/* @__PURE__ */ jsx2(Checkbox2.Label, { children: t("AbpLanguageManagement::OnlyEmptyValues") || "Only empty values" })
|
|
1061
|
+
]
|
|
1062
|
+
}
|
|
1063
|
+
),
|
|
1064
|
+
/* @__PURE__ */ jsx2(Button2, { colorPalette: "blue", onClick: handleSearch, children: t("AbpLanguageManagement::Search") || "Search" })
|
|
1065
|
+
] })
|
|
1066
|
+
] }),
|
|
1067
|
+
error && /* @__PURE__ */ jsx2(Alert2, { status: "error", mb: 4, children: error }),
|
|
1068
|
+
isLoading && languageTexts.length === 0 && /* @__PURE__ */ jsx2(Flex2, { justify: "center", py: 8, children: /* @__PURE__ */ jsx2(Spinner2, { size: "lg" }) }),
|
|
1069
|
+
languageTexts.length > 0 && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1070
|
+
/* @__PURE__ */ jsxs2(Table2.Root, { variant: "outline", children: [
|
|
1071
|
+
/* @__PURE__ */ jsx2(Table2.Header, { children: /* @__PURE__ */ jsxs2(Table2.Row, { children: [
|
|
1072
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpLanguageManagement::Actions") || "Actions" }),
|
|
1073
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpLanguageManagement::Key") || "Key" }),
|
|
1074
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpLanguageManagement::BaseValue") || "Base Value" }),
|
|
1075
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpLanguageManagement::TargetValue") || "Target Value" }),
|
|
1076
|
+
/* @__PURE__ */ jsx2(Table2.ColumnHeader, { children: t("AbpLanguageManagement::Resource") || "Resource" })
|
|
1077
|
+
] }) }),
|
|
1078
|
+
/* @__PURE__ */ jsx2(Table2.Body, { children: languageTexts.map((text, index) => /* @__PURE__ */ jsxs2(Table2.Row, { children: [
|
|
1079
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsxs2(Menu2.Root, { children: [
|
|
1080
|
+
/* @__PURE__ */ jsx2(Menu2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx2(Button2, { size: "sm", colorPalette: "blue", children: t("AbpLanguageManagement::Actions") || "Actions" }) }),
|
|
1081
|
+
/* @__PURE__ */ jsx2(Menu2.Positioner, { children: /* @__PURE__ */ jsxs2(Menu2.Content, { children: [
|
|
1082
|
+
/* @__PURE__ */ jsx2(Menu2.Item, { value: "edit", onClick: () => handleEdit(text), children: t("AbpLanguageManagement::Edit") || "Edit" }),
|
|
1083
|
+
text.value !== text.baseValue && /* @__PURE__ */ jsx2(
|
|
1084
|
+
Menu2.Item,
|
|
1085
|
+
{
|
|
1086
|
+
value: "restore",
|
|
1087
|
+
color: "orange.500",
|
|
1088
|
+
onClick: () => handleRestore(text),
|
|
1089
|
+
children: t("AbpLanguageManagement::RestoreToDefault") || "Restore to Default"
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
] }) })
|
|
1093
|
+
] }) }),
|
|
1094
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsx2(Text2, { fontSize: "sm", fontFamily: "mono", children: text.name }) }),
|
|
1095
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsx2(Text2, { fontSize: "sm", color: "gray.600", children: text.baseValue }) }),
|
|
1096
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsx2(
|
|
1097
|
+
Text2,
|
|
1098
|
+
{
|
|
1099
|
+
fontSize: "sm",
|
|
1100
|
+
color: text.value ? "inherit" : "red.500",
|
|
1101
|
+
fontStyle: text.value ? "normal" : "italic",
|
|
1102
|
+
children: text.value || t("AbpLanguageManagement::NotTranslated") || "(Not translated)"
|
|
1103
|
+
}
|
|
1104
|
+
) }),
|
|
1105
|
+
/* @__PURE__ */ jsx2(Table2.Cell, { children: /* @__PURE__ */ jsx2(Text2, { fontSize: "sm", color: "gray.500", children: text.resourceName }) })
|
|
1106
|
+
] }, `${text.resourceName}-${text.name}-${index}`)) })
|
|
1107
|
+
] }),
|
|
1108
|
+
totalPages > 1 && /* @__PURE__ */ jsxs2(Flex2, { justify: "space-between", align: "center", mt: 4, children: [
|
|
1109
|
+
/* @__PURE__ */ jsx2(Text2, { fontSize: "sm", color: "gray.500", children: t("AbpLanguageManagement::ShowingXofY", (currentPage * pageSize + 1).toString(), Math.min((currentPage + 1) * pageSize, totalCount).toString(), totalCount.toString()) || `Showing ${currentPage * pageSize + 1}-${Math.min((currentPage + 1) * pageSize, totalCount)} of ${totalCount}` }),
|
|
1110
|
+
/* @__PURE__ */ jsxs2(HStack, { gap: 2, children: [
|
|
1111
|
+
/* @__PURE__ */ jsx2(
|
|
1112
|
+
Button2,
|
|
1113
|
+
{
|
|
1114
|
+
size: "sm",
|
|
1115
|
+
variant: "outline",
|
|
1116
|
+
onClick: () => handlePageChange(currentPage - 1),
|
|
1117
|
+
disabled: currentPage === 0,
|
|
1118
|
+
children: t("AbpLanguageManagement::Previous") || "Previous"
|
|
1119
|
+
}
|
|
1120
|
+
),
|
|
1121
|
+
/* @__PURE__ */ jsxs2(Text2, { fontSize: "sm", children: [
|
|
1122
|
+
currentPage + 1,
|
|
1123
|
+
" / ",
|
|
1124
|
+
totalPages
|
|
1125
|
+
] }),
|
|
1126
|
+
/* @__PURE__ */ jsx2(
|
|
1127
|
+
Button2,
|
|
1128
|
+
{
|
|
1129
|
+
size: "sm",
|
|
1130
|
+
variant: "outline",
|
|
1131
|
+
onClick: () => handlePageChange(currentPage + 1),
|
|
1132
|
+
disabled: currentPage >= totalPages - 1,
|
|
1133
|
+
children: t("AbpLanguageManagement::Next") || "Next"
|
|
1134
|
+
}
|
|
1135
|
+
)
|
|
1136
|
+
] })
|
|
1137
|
+
] })
|
|
1138
|
+
] }),
|
|
1139
|
+
!isLoading && languageTexts.length === 0 && filterState.baseCultureName && filterState.targetCultureName && /* @__PURE__ */ jsx2(Text2, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpLanguageManagement::NoLanguageTextsFound") || "No language texts found" }),
|
|
1140
|
+
!filterState.baseCultureName || !filterState.targetCultureName ? /* @__PURE__ */ jsx2(Text2, { textAlign: "center", color: "gray.500", py: 8, children: t("AbpLanguageManagement::SelectCulturesToViewTexts") || "Select base and target cultures to view language texts" }) : null,
|
|
1141
|
+
/* @__PURE__ */ jsx2(
|
|
1142
|
+
Modal2,
|
|
1143
|
+
{
|
|
1144
|
+
visible: isModalOpen,
|
|
1145
|
+
onVisibleChange: setIsModalOpen,
|
|
1146
|
+
header: t("AbpLanguageManagement::EditLanguageText") || "Edit Language Text",
|
|
1147
|
+
footer: /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1148
|
+
/* @__PURE__ */ jsx2(Button2, { variant: "outline", onClick: handleModalClose, disabled: isSubmitting, children: t("AbpLanguageManagement::Cancel") || "Cancel" }),
|
|
1149
|
+
/* @__PURE__ */ jsx2(Button2, { colorPalette: "blue", onClick: handleSubmit, loading: isSubmitting, children: t("AbpLanguageManagement::Save") || "Save" })
|
|
1150
|
+
] }),
|
|
1151
|
+
children: /* @__PURE__ */ jsx2(VStack2, { gap: 4, align: "stretch", children: selectedLanguageText && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
1152
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::Key") || "Key", children: /* @__PURE__ */ jsx2(Text2, { fontFamily: "mono", p: 2, bg: "gray.100", borderRadius: "md", children: selectedLanguageText.name }) }),
|
|
1153
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::BaseValue") || "Base Value", children: /* @__PURE__ */ jsx2(Text2, { p: 2, bg: "gray.100", borderRadius: "md", color: "gray.600", children: selectedLanguageText.baseValue }) }),
|
|
1154
|
+
/* @__PURE__ */ jsx2(FormField2, { label: t("AbpLanguageManagement::TargetValue") || "Target Value", children: /* @__PURE__ */ jsx2(
|
|
1155
|
+
Textarea,
|
|
1156
|
+
{
|
|
1157
|
+
value: editValue,
|
|
1158
|
+
onChange: (e) => setEditValue(e.target.value),
|
|
1159
|
+
placeholder: t("AbpLanguageManagement::EnterTranslation") || "Enter translation...",
|
|
1160
|
+
rows: 4
|
|
1161
|
+
}
|
|
1162
|
+
) })
|
|
1163
|
+
] }) })
|
|
1164
|
+
}
|
|
1165
|
+
)
|
|
1166
|
+
] });
|
|
1167
|
+
}
|
|
1168
|
+
export {
|
|
1169
|
+
LANGUAGE_MANAGEMENT_ROUTES,
|
|
1170
|
+
LanguageManagementService,
|
|
1171
|
+
LanguageTextsComponent,
|
|
1172
|
+
LanguagesComponent,
|
|
1173
|
+
useLanguageTexts,
|
|
1174
|
+
useLanguages
|
|
1175
|
+
};
|