@djangocfg/i18n 2.1.111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +235 -0
- package/package.json +70 -0
- package/src/context.tsx +293 -0
- package/src/index.ts +28 -0
- package/src/locales/en.ts +491 -0
- package/src/locales/index.ts +3 -0
- package/src/locales/ko.ts +491 -0
- package/src/locales/ru.ts +491 -0
- package/src/types.ts +656 -0
- package/src/utils/get-value.ts +30 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/interpolate.ts +23 -0
- package/src/utils/merge.ts +88 -0
- package/src/utils/path-keys.ts +85 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
import type { PathKeys, TranslationFn } from './utils/path-keys'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* All valid translation keys for base I18nTranslations
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import type { I18nKeys } from '@djangocfg/i18n'
|
|
9
|
+
*
|
|
10
|
+
* const key: I18nKeys = 'ui.form.save' // OK
|
|
11
|
+
* const bad: I18nKeys = 'ui.form.typo' // Error
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export type I18nKeys = PathKeys<I18nTranslations>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Type-safe translation function for base translations
|
|
18
|
+
*/
|
|
19
|
+
export type I18nTranslationFn = TranslationFn<I18nTranslations>
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Core translation structure for @djangocfg packages
|
|
23
|
+
*
|
|
24
|
+
* This type defines all translatable strings used across the component library.
|
|
25
|
+
* Each package section contains its own namespace to avoid conflicts.
|
|
26
|
+
*/
|
|
27
|
+
export interface I18nTranslations {
|
|
28
|
+
/**
|
|
29
|
+
* UI Components (ui-core, ui-nextjs)
|
|
30
|
+
*/
|
|
31
|
+
ui: {
|
|
32
|
+
/** Select/Combobox/MultiSelect components */
|
|
33
|
+
select: {
|
|
34
|
+
placeholder: string
|
|
35
|
+
search: string
|
|
36
|
+
noResults: string
|
|
37
|
+
selectAll: string
|
|
38
|
+
clearAll: string
|
|
39
|
+
/** Template: "+{count} more" */
|
|
40
|
+
moreItems: string
|
|
41
|
+
loading: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Pagination components */
|
|
45
|
+
pagination: {
|
|
46
|
+
previous: string
|
|
47
|
+
next: string
|
|
48
|
+
first: string
|
|
49
|
+
last: string
|
|
50
|
+
/** Template: "Page {page}" */
|
|
51
|
+
page: string
|
|
52
|
+
/** Template: "of {total}" */
|
|
53
|
+
of: string
|
|
54
|
+
/** Template: "{from}-{to} of {total}" */
|
|
55
|
+
showing: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Dialog/Modal components */
|
|
59
|
+
dialog: {
|
|
60
|
+
close: string
|
|
61
|
+
confirm: string
|
|
62
|
+
cancel: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Form components and validation */
|
|
66
|
+
form: {
|
|
67
|
+
submit: string
|
|
68
|
+
cancel: string
|
|
69
|
+
save: string
|
|
70
|
+
delete: string
|
|
71
|
+
edit: string
|
|
72
|
+
create: string
|
|
73
|
+
update: string
|
|
74
|
+
reset: string
|
|
75
|
+
clear: string
|
|
76
|
+
loading: string
|
|
77
|
+
saving: string
|
|
78
|
+
deleting: string
|
|
79
|
+
required: string
|
|
80
|
+
optional: string
|
|
81
|
+
/** Template: "{min} characters minimum" */
|
|
82
|
+
minLength: string
|
|
83
|
+
/** Template: "{max} characters maximum" */
|
|
84
|
+
maxLength: string
|
|
85
|
+
invalidEmail: string
|
|
86
|
+
invalidUrl: string
|
|
87
|
+
invalidPhone: string
|
|
88
|
+
passwordMismatch: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Date/Time components */
|
|
92
|
+
datetime: {
|
|
93
|
+
today: string
|
|
94
|
+
yesterday: string
|
|
95
|
+
tomorrow: string
|
|
96
|
+
now: string
|
|
97
|
+
/** Template: "{count} seconds ago" */
|
|
98
|
+
secondsAgo: string
|
|
99
|
+
/** Template: "{count} minutes ago" */
|
|
100
|
+
minutesAgo: string
|
|
101
|
+
/** Template: "{count} hours ago" */
|
|
102
|
+
hoursAgo: string
|
|
103
|
+
/** Template: "{count} days ago" */
|
|
104
|
+
daysAgo: string
|
|
105
|
+
pickDate: string
|
|
106
|
+
pickTime: string
|
|
107
|
+
pickDateTime: string
|
|
108
|
+
pickDateRange: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** File upload components */
|
|
112
|
+
file: {
|
|
113
|
+
upload: string
|
|
114
|
+
uploading: string
|
|
115
|
+
dragDrop: string
|
|
116
|
+
browse: string
|
|
117
|
+
remove: string
|
|
118
|
+
/** Template: "Max size: {size}" */
|
|
119
|
+
maxSize: string
|
|
120
|
+
invalidType: string
|
|
121
|
+
tooLarge: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Table components */
|
|
125
|
+
table: {
|
|
126
|
+
noData: string
|
|
127
|
+
loading: string
|
|
128
|
+
/** Template: "Showing {from}-{to} of {total}" */
|
|
129
|
+
showing: string
|
|
130
|
+
rowsPerPage: string
|
|
131
|
+
sortAsc: string
|
|
132
|
+
sortDesc: string
|
|
133
|
+
filter: string
|
|
134
|
+
clearFilters: string
|
|
135
|
+
selectAll: string
|
|
136
|
+
deselectAll: string
|
|
137
|
+
/** Template: "{count} selected" */
|
|
138
|
+
selected: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Common actions */
|
|
142
|
+
actions: {
|
|
143
|
+
view: string
|
|
144
|
+
copy: string
|
|
145
|
+
copied: string
|
|
146
|
+
copyToClipboard: string
|
|
147
|
+
download: string
|
|
148
|
+
share: string
|
|
149
|
+
refresh: string
|
|
150
|
+
retry: string
|
|
151
|
+
expand: string
|
|
152
|
+
collapse: string
|
|
153
|
+
showMore: string
|
|
154
|
+
showLess: string
|
|
155
|
+
seeAll: string
|
|
156
|
+
goBack: string
|
|
157
|
+
remove: string
|
|
158
|
+
previousSlide: string
|
|
159
|
+
nextSlide: string
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** Phone input */
|
|
163
|
+
phone: {
|
|
164
|
+
searchCountries: string
|
|
165
|
+
noCountries: string
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** Navigation (for tabs, mobile sheets, etc.) */
|
|
169
|
+
navigation: {
|
|
170
|
+
/** Title for navigation sheet/modal */
|
|
171
|
+
title: string
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Common states */
|
|
175
|
+
states: {
|
|
176
|
+
loading: string
|
|
177
|
+
empty: string
|
|
178
|
+
error: string
|
|
179
|
+
success: string
|
|
180
|
+
warning: string
|
|
181
|
+
info: string
|
|
182
|
+
pending: string
|
|
183
|
+
active: string
|
|
184
|
+
inactive: string
|
|
185
|
+
enabled: string
|
|
186
|
+
disabled: string
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Error messages */
|
|
190
|
+
errors: {
|
|
191
|
+
generic: string
|
|
192
|
+
network: string
|
|
193
|
+
timeout: string
|
|
194
|
+
notFound: string
|
|
195
|
+
unauthorized: string
|
|
196
|
+
forbidden: string
|
|
197
|
+
serverError: string
|
|
198
|
+
validation: string
|
|
199
|
+
unknown: string
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Layout components (@djangocfg/layouts)
|
|
205
|
+
*/
|
|
206
|
+
layouts: {
|
|
207
|
+
/** Sidebar component */
|
|
208
|
+
sidebar: {
|
|
209
|
+
toggle: string
|
|
210
|
+
collapse: string
|
|
211
|
+
expand: string
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Navigation */
|
|
215
|
+
navigation: {
|
|
216
|
+
menu: string
|
|
217
|
+
home: string
|
|
218
|
+
back: string
|
|
219
|
+
forward: string
|
|
220
|
+
toggleMobile: string
|
|
221
|
+
breadcrumb: string
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Profile/User section */
|
|
225
|
+
profile: {
|
|
226
|
+
settings: string
|
|
227
|
+
account: string
|
|
228
|
+
logout: string
|
|
229
|
+
login: string
|
|
230
|
+
signUp: string
|
|
231
|
+
signOut: string
|
|
232
|
+
userMenu: string
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Theme */
|
|
236
|
+
theme: {
|
|
237
|
+
toggle: string
|
|
238
|
+
light: string
|
|
239
|
+
dark: string
|
|
240
|
+
system: string
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Search */
|
|
244
|
+
search: {
|
|
245
|
+
placeholder: string
|
|
246
|
+
noResults: string
|
|
247
|
+
recentSearches: string
|
|
248
|
+
clearHistory: string
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Mobile drawer */
|
|
252
|
+
mobile: {
|
|
253
|
+
closeMenu: string
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Error pages */
|
|
257
|
+
errors: {
|
|
258
|
+
somethingWentWrong: string
|
|
259
|
+
tryRefreshing: string
|
|
260
|
+
refreshPage: string
|
|
261
|
+
goBack: string
|
|
262
|
+
goHome: string
|
|
263
|
+
needHelp: string
|
|
264
|
+
contactSupport: string
|
|
265
|
+
/** Template: "If the problem persists, please contact {email}" */
|
|
266
|
+
persistsContact: string
|
|
267
|
+
/** Error titles */
|
|
268
|
+
error: string
|
|
269
|
+
badRequest: string
|
|
270
|
+
authRequired: string
|
|
271
|
+
accessDenied: string
|
|
272
|
+
pageNotFound: string
|
|
273
|
+
requestTimeout: string
|
|
274
|
+
serverError: string
|
|
275
|
+
badGateway: string
|
|
276
|
+
serviceUnavailable: string
|
|
277
|
+
gatewayTimeout: string
|
|
278
|
+
/** Error descriptions */
|
|
279
|
+
badRequestDesc: string
|
|
280
|
+
authRequiredDesc: string
|
|
281
|
+
accessDeniedDesc: string
|
|
282
|
+
pageNotFoundDesc: string
|
|
283
|
+
requestTimeoutDesc: string
|
|
284
|
+
serverErrorDesc: string
|
|
285
|
+
badGatewayDesc: string
|
|
286
|
+
serviceUnavailableDesc: string
|
|
287
|
+
gatewayTimeoutDesc: string
|
|
288
|
+
unknownErrorDesc: string
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Push notifications */
|
|
292
|
+
push: {
|
|
293
|
+
enableNotifications: string
|
|
294
|
+
stayUpdated: string
|
|
295
|
+
enable: string
|
|
296
|
+
notNow: string
|
|
297
|
+
dismiss: string
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/** Auth dialog */
|
|
301
|
+
auth: {
|
|
302
|
+
authRequired: string
|
|
303
|
+
pleaseSignIn: string
|
|
304
|
+
goToSignIn: string
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** MCP Chat */
|
|
308
|
+
chat: {
|
|
309
|
+
aiAssistant: string
|
|
310
|
+
defaultTitle: string
|
|
311
|
+
newChat: string
|
|
312
|
+
closeChat: string
|
|
313
|
+
switchToFloating: string
|
|
314
|
+
switchToSidebar: string
|
|
315
|
+
dragToResize: string
|
|
316
|
+
howCanIHelp: string
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** PWA Install */
|
|
320
|
+
pwa: {
|
|
321
|
+
/** A2HS Hint */
|
|
322
|
+
addToHomeScreen: string
|
|
323
|
+
installApp: string
|
|
324
|
+
tapToLearnHow: string
|
|
325
|
+
clickToSeeGuide: string
|
|
326
|
+
tapToInstall: string
|
|
327
|
+
installing: string
|
|
328
|
+
dismiss: string
|
|
329
|
+
appLogo: string
|
|
330
|
+
/** iOS Guide */
|
|
331
|
+
iosTitle: string
|
|
332
|
+
iosDescription: string
|
|
333
|
+
iosStep1Title: string
|
|
334
|
+
iosStep1Desc: string
|
|
335
|
+
iosStep2Title: string
|
|
336
|
+
iosStep2Desc: string
|
|
337
|
+
iosStep3Title: string
|
|
338
|
+
iosStep3Desc: string
|
|
339
|
+
gotIt: string
|
|
340
|
+
/** Desktop Guide */
|
|
341
|
+
desktopTitle: string
|
|
342
|
+
desktopDescription: string
|
|
343
|
+
desktopDescSafari: string
|
|
344
|
+
desktopTip: string
|
|
345
|
+
desktopFirefoxNote: string
|
|
346
|
+
/** Desktop steps - Chromium */
|
|
347
|
+
chromiumStep1Title: string
|
|
348
|
+
chromiumStep1Desc: string
|
|
349
|
+
chromiumStep2Title: string
|
|
350
|
+
chromiumStep2Desc: string
|
|
351
|
+
chromiumStep3Title: string
|
|
352
|
+
chromiumStep3Desc: string
|
|
353
|
+
/** Desktop steps - Firefox */
|
|
354
|
+
firefoxStep1Title: string
|
|
355
|
+
firefoxStep1Desc: string
|
|
356
|
+
firefoxStep2Title: string
|
|
357
|
+
firefoxStep2Desc: string
|
|
358
|
+
firefoxStep3Title: string
|
|
359
|
+
firefoxStep3Desc: string
|
|
360
|
+
/** Desktop steps - Safari */
|
|
361
|
+
safariStep1Title: string
|
|
362
|
+
safariStep1Desc: string
|
|
363
|
+
safariStep2Title: string
|
|
364
|
+
safariStep2Desc: string
|
|
365
|
+
/** Desktop steps - Unknown */
|
|
366
|
+
unknownStep1Title: string
|
|
367
|
+
unknownStep1Desc: string
|
|
368
|
+
unknownStep2Title: string
|
|
369
|
+
unknownStep2Desc: string
|
|
370
|
+
unknownStep3Title: string
|
|
371
|
+
unknownStep3Desc: string
|
|
372
|
+
close: string
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Profile page */
|
|
376
|
+
profilePage: {
|
|
377
|
+
/** Page title */
|
|
378
|
+
title: string
|
|
379
|
+
/** Sections */
|
|
380
|
+
account: string
|
|
381
|
+
personalInfo: string
|
|
382
|
+
work: string
|
|
383
|
+
security: string
|
|
384
|
+
actions: string
|
|
385
|
+
/** Fields */
|
|
386
|
+
email: string
|
|
387
|
+
firstName: string
|
|
388
|
+
lastName: string
|
|
389
|
+
company: string
|
|
390
|
+
position: string
|
|
391
|
+
phone: string
|
|
392
|
+
/** Values */
|
|
393
|
+
notSet: string
|
|
394
|
+
on: string
|
|
395
|
+
off: string
|
|
396
|
+
/** Actions */
|
|
397
|
+
save: string
|
|
398
|
+
saving: string
|
|
399
|
+
cancel: string
|
|
400
|
+
signOut: string
|
|
401
|
+
deleteAccount: string
|
|
402
|
+
deleting: string
|
|
403
|
+
/** 2FA */
|
|
404
|
+
twoFactorAuth: string
|
|
405
|
+
/** Avatar */
|
|
406
|
+
avatar: string
|
|
407
|
+
changeAvatar: string
|
|
408
|
+
/** Membership */
|
|
409
|
+
memberSince: string
|
|
410
|
+
/** Placeholders */
|
|
411
|
+
enterField: string
|
|
412
|
+
/** Messages */
|
|
413
|
+
profileUpdated: string
|
|
414
|
+
avatarUpdated: string
|
|
415
|
+
failedToUpdate: string
|
|
416
|
+
failedToUploadAvatar: string
|
|
417
|
+
selectImageFile: string
|
|
418
|
+
fileTooLarge: string
|
|
419
|
+
/** Not authenticated */
|
|
420
|
+
notAuthenticated: string
|
|
421
|
+
pleaseLogIn: string
|
|
422
|
+
/** Delete account dialog */
|
|
423
|
+
deleteAccountTitle: string
|
|
424
|
+
deleteAccountDesc: string
|
|
425
|
+
typeToConfirm: string
|
|
426
|
+
confirmationWord: string
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* API/Network related messages (@djangocfg/api)
|
|
432
|
+
*/
|
|
433
|
+
api: {
|
|
434
|
+
errors: {
|
|
435
|
+
networkError: string
|
|
436
|
+
connectionFailed: string
|
|
437
|
+
requestTimeout: string
|
|
438
|
+
serverUnavailable: string
|
|
439
|
+
invalidResponse: string
|
|
440
|
+
rateLimited: string
|
|
441
|
+
}
|
|
442
|
+
status: {
|
|
443
|
+
connecting: string
|
|
444
|
+
connected: string
|
|
445
|
+
disconnected: string
|
|
446
|
+
reconnecting: string
|
|
447
|
+
}
|
|
448
|
+
/** Logout dialog */
|
|
449
|
+
logout: {
|
|
450
|
+
title: string
|
|
451
|
+
message: string
|
|
452
|
+
confirm: string
|
|
453
|
+
cancel: string
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Centrifugo WebSocket (@djangocfg/centrifugo)
|
|
459
|
+
*/
|
|
460
|
+
centrifugo: {
|
|
461
|
+
/** Monitor component */
|
|
462
|
+
monitor: {
|
|
463
|
+
title: string
|
|
464
|
+
description: string
|
|
465
|
+
openMonitor: string
|
|
466
|
+
openDebugPanel: string
|
|
467
|
+
widgetTitle: string
|
|
468
|
+
}
|
|
469
|
+
/** Tabs */
|
|
470
|
+
tabs: {
|
|
471
|
+
connection: string
|
|
472
|
+
messages: string
|
|
473
|
+
subscriptions: string
|
|
474
|
+
}
|
|
475
|
+
/** Subscriptions list */
|
|
476
|
+
subscriptionsList: {
|
|
477
|
+
title: string
|
|
478
|
+
notConnected: string
|
|
479
|
+
noActiveSubscriptions: string
|
|
480
|
+
}
|
|
481
|
+
/** Status */
|
|
482
|
+
status: {
|
|
483
|
+
connected: string
|
|
484
|
+
disconnected: string
|
|
485
|
+
connecting: string
|
|
486
|
+
connect: string
|
|
487
|
+
uptime: string
|
|
488
|
+
subscriptions: string
|
|
489
|
+
realtimeUnavailable: string
|
|
490
|
+
}
|
|
491
|
+
/** Messages feed */
|
|
492
|
+
feed: {
|
|
493
|
+
title: string
|
|
494
|
+
noMessages: string
|
|
495
|
+
pausedClickToResume: string
|
|
496
|
+
autoScrollOn: string
|
|
497
|
+
autoScrollOff: string
|
|
498
|
+
viewData: string
|
|
499
|
+
}
|
|
500
|
+
/** Filters */
|
|
501
|
+
filters: {
|
|
502
|
+
title: string
|
|
503
|
+
active: string
|
|
504
|
+
clear: string
|
|
505
|
+
searchMessages: string
|
|
506
|
+
level: string
|
|
507
|
+
type: string
|
|
508
|
+
source: string
|
|
509
|
+
autoScrollToLatest: string
|
|
510
|
+
}
|
|
511
|
+
/** Debug panel */
|
|
512
|
+
debug: {
|
|
513
|
+
title: string
|
|
514
|
+
description: string
|
|
515
|
+
openDebugPanel: string
|
|
516
|
+
tabConnection: string
|
|
517
|
+
tabLogs: string
|
|
518
|
+
tabSubscriptions: string
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Heavy tools (@djangocfg/ui-tools)
|
|
524
|
+
*/
|
|
525
|
+
tools: {
|
|
526
|
+
/** Code viewer/editor */
|
|
527
|
+
code: {
|
|
528
|
+
copyCode: string
|
|
529
|
+
noContent: string
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/** Diagram/Mermaid */
|
|
533
|
+
diagram: {
|
|
534
|
+
title: string
|
|
535
|
+
clickToView: string
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** Image viewer */
|
|
539
|
+
image: {
|
|
540
|
+
noImage: string
|
|
541
|
+
failedToLoad: string
|
|
542
|
+
zoomIn: string
|
|
543
|
+
zoomOut: string
|
|
544
|
+
fitToView: string
|
|
545
|
+
flipHorizontal: string
|
|
546
|
+
flipVertical: string
|
|
547
|
+
rotate: string
|
|
548
|
+
fullscreen: string
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Gallery/Lightbox */
|
|
552
|
+
gallery: {
|
|
553
|
+
noImages: string
|
|
554
|
+
lightbox: string
|
|
555
|
+
previous: string
|
|
556
|
+
next: string
|
|
557
|
+
close: string
|
|
558
|
+
download: string
|
|
559
|
+
share: string
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/** Video player */
|
|
563
|
+
video: {
|
|
564
|
+
play: string
|
|
565
|
+
fullscreen: string
|
|
566
|
+
unavailable: string
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Audio player */
|
|
570
|
+
audio: {
|
|
571
|
+
restart: string
|
|
572
|
+
back: string
|
|
573
|
+
forward: string
|
|
574
|
+
volume: string
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/** Color picker */
|
|
578
|
+
color: {
|
|
579
|
+
pick: string
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/** OpenAPI viewer */
|
|
583
|
+
openapi: {
|
|
584
|
+
response: string
|
|
585
|
+
noResponse: string
|
|
586
|
+
required: string
|
|
587
|
+
optional: string
|
|
588
|
+
searchEndpoints: string
|
|
589
|
+
all: string
|
|
590
|
+
methods: string
|
|
591
|
+
path: string
|
|
592
|
+
description: string
|
|
593
|
+
navigation: string
|
|
594
|
+
previous: string
|
|
595
|
+
next: string
|
|
596
|
+
bearerToken: string
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/** JSON form */
|
|
600
|
+
form: {
|
|
601
|
+
title: string
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Deeply partial type for translation overrides
|
|
608
|
+
*/
|
|
609
|
+
export type PartialTranslations = DeepPartial<I18nTranslations>
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Helper type for deep partial
|
|
613
|
+
*/
|
|
614
|
+
export type DeepPartial<T> = T extends object
|
|
615
|
+
? { [P in keyof T]?: DeepPartial<T[P]> }
|
|
616
|
+
: T
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Supported locale codes
|
|
620
|
+
*/
|
|
621
|
+
export type LocaleCode = 'en' | 'ru' | 'ko' | string
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* I18n context value
|
|
625
|
+
*/
|
|
626
|
+
export interface I18nContextValue {
|
|
627
|
+
/** Current locale code */
|
|
628
|
+
locale: LocaleCode
|
|
629
|
+
/** Current translations */
|
|
630
|
+
translations: I18nTranslations
|
|
631
|
+
/**
|
|
632
|
+
* Get translated string by key path
|
|
633
|
+
* @param key - Dot-notation key path (e.g., "ui.select.placeholder")
|
|
634
|
+
* @param params - Optional interpolation parameters
|
|
635
|
+
*/
|
|
636
|
+
t: (key: string, params?: Record<string, string | number>) => string
|
|
637
|
+
/**
|
|
638
|
+
* Change current locale
|
|
639
|
+
*/
|
|
640
|
+
setLocale: (locale: LocaleCode) => void
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* I18n provider props
|
|
645
|
+
*/
|
|
646
|
+
export interface I18nProviderProps {
|
|
647
|
+
children: React.ReactNode
|
|
648
|
+
/** Initial locale */
|
|
649
|
+
locale?: LocaleCode
|
|
650
|
+
/** Translations for the current locale */
|
|
651
|
+
translations?: I18nTranslations | PartialTranslations
|
|
652
|
+
/** All available translations by locale */
|
|
653
|
+
allTranslations?: Record<LocaleCode, I18nTranslations | PartialTranslations>
|
|
654
|
+
/** Callback when locale changes */
|
|
655
|
+
onLocaleChange?: (locale: LocaleCode) => void
|
|
656
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get a nested value from an object using dot notation
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* getNestedValue({ ui: { select: { placeholder: 'Select...' } } }, 'ui.select.placeholder')
|
|
6
|
+
* // => 'Select...'
|
|
7
|
+
*/
|
|
8
|
+
export function getNestedValue(
|
|
9
|
+
obj: Record<string, unknown>,
|
|
10
|
+
path: string
|
|
11
|
+
): string | undefined {
|
|
12
|
+
const keys = path.split('.')
|
|
13
|
+
let current: unknown = obj
|
|
14
|
+
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
if (current === null || current === undefined) {
|
|
17
|
+
return undefined
|
|
18
|
+
}
|
|
19
|
+
if (typeof current !== 'object') {
|
|
20
|
+
return undefined
|
|
21
|
+
}
|
|
22
|
+
current = (current as Record<string, unknown>)[key]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (typeof current === 'string') {
|
|
26
|
+
return current
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interpolate variables in a translation string
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* interpolate("Hello, {name}!", { name: "World" })
|
|
6
|
+
* // => "Hello, World!"
|
|
7
|
+
*
|
|
8
|
+
* interpolate("+{count} more", { count: 5 })
|
|
9
|
+
* // => "+5 more"
|
|
10
|
+
*/
|
|
11
|
+
export function interpolate(
|
|
12
|
+
template: string,
|
|
13
|
+
params?: Record<string, string | number>
|
|
14
|
+
): string {
|
|
15
|
+
if (!params) return template
|
|
16
|
+
|
|
17
|
+
return template.replace(/\{(\w+)\}/g, (match, key) => {
|
|
18
|
+
if (key in params) {
|
|
19
|
+
return String(params[key])
|
|
20
|
+
}
|
|
21
|
+
return match
|
|
22
|
+
})
|
|
23
|
+
}
|