@djangocfg/i18n 2.1.541 → 2.1.543
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 +0 -1
- package/dist/cli/index.mjs +61 -63
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -65
- package/dist/index.mjs +1 -165
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/cli/commands/add.ts +9 -101
- package/src/cli/utils/locales.ts +115 -11
- package/src/context.tsx +7 -4
- package/src/locales/ar.ts +0 -55
- package/src/locales/da.ts +0 -55
- package/src/locales/de.ts +0 -55
- package/src/locales/en.ts +0 -55
- package/src/locales/es.ts +0 -55
- package/src/locales/fr.ts +0 -55
- package/src/locales/it.ts +0 -55
- package/src/locales/ja.ts +0 -55
- package/src/locales/ko.ts +0 -55
- package/src/locales/nl.ts +0 -55
- package/src/locales/no.ts +0 -55
- package/src/locales/pl.ts +0 -55
- package/src/locales/pt-BR.ts +0 -55
- package/src/locales/ru.ts +0 -55
- package/src/locales/sv.ts +0 -55
- package/src/locales/tr.ts +0 -55
- package/src/locales/zh.ts +0 -55
- package/src/types.ts +0 -65
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/i18n",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.543",
|
|
4
4
|
"description": "Lightweight i18n library for @djangocfg packages with built-in translations for English, Russian, and Korean",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"i18n",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"i18n:add": "tsx src/cli/index.ts add"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"react": "^19.
|
|
70
|
+
"react": "^19.0.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
73
|
"citty": "^0.1.6",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"jiti": "^2.7.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
78
|
+
"@djangocfg/typescript-config": "^2.1.543",
|
|
79
79
|
"@types/node": "^25.9.5",
|
|
80
80
|
"@types/react": "19.2.15",
|
|
81
81
|
"eslint": "^9.39.5",
|
package/src/cli/commands/add.ts
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
readLocaleFile,
|
|
12
12
|
writeLocaleFile,
|
|
13
13
|
getValueAtPath,
|
|
14
|
+
setValueAtPath,
|
|
15
|
+
renderTsLocale,
|
|
14
16
|
loadLocale,
|
|
15
17
|
} from '../utils';
|
|
16
18
|
|
|
@@ -65,7 +67,6 @@ export const addCommand = defineCommand({
|
|
|
65
67
|
consola.info(`Directory: ${localesDir}`);
|
|
66
68
|
consola.log('');
|
|
67
69
|
|
|
68
|
-
const keyParts = keyPath.split('.');
|
|
69
70
|
let updated = 0;
|
|
70
71
|
let skipped = 0;
|
|
71
72
|
|
|
@@ -92,14 +93,16 @@ export const addCommand = defineCommand({
|
|
|
92
93
|
const { content, exportName } = readLocaleFile(config, locale);
|
|
93
94
|
|
|
94
95
|
if (config.fileExtension === '.json') {
|
|
95
|
-
// JSON file
|
|
96
96
|
const json = JSON.parse(content);
|
|
97
|
-
|
|
97
|
+
setValueAtPath(json, keyPath, translation);
|
|
98
98
|
writeLocaleFile(config, locale, JSON.stringify(json, null, 2));
|
|
99
99
|
} else {
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
100
|
+
// `existing` is the same file, already parsed by `loadLocale` above
|
|
101
|
+
// for the key-exists check. Editing that object and re-serialising is
|
|
102
|
+
// what makes nested keys work: the old text-splicing path inserted a
|
|
103
|
+
// duplicate parent block and lost its siblings.
|
|
104
|
+
setValueAtPath(existing, keyPath, translation);
|
|
105
|
+
writeLocaleFile(config, locale, renderTsLocale(content, exportName, existing));
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
consola.success(` ${locale}: Added "${translation}"`);
|
|
@@ -116,98 +119,3 @@ export const addCommand = defineCommand({
|
|
|
116
119
|
}
|
|
117
120
|
},
|
|
118
121
|
});
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Set nested value in object
|
|
122
|
-
*/
|
|
123
|
-
function setNestedValue(obj: Record<string, unknown>, keys: string[], value: string): void {
|
|
124
|
-
let current = obj;
|
|
125
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
126
|
-
const key = keys[i];
|
|
127
|
-
if (!(key in current) || typeof current[key] !== 'object') {
|
|
128
|
-
current[key] = {};
|
|
129
|
-
}
|
|
130
|
-
current = current[key] as Record<string, unknown>;
|
|
131
|
-
}
|
|
132
|
-
current[keys[keys.length - 1]] = value;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Insert key into TypeScript locale file
|
|
137
|
-
*/
|
|
138
|
-
function insertKeyIntoTS(
|
|
139
|
-
content: string,
|
|
140
|
-
exportName: string,
|
|
141
|
-
keyParts: string[],
|
|
142
|
-
value: string
|
|
143
|
-
): string {
|
|
144
|
-
// Find the object for the first key part
|
|
145
|
-
const firstKey = keyParts[0];
|
|
146
|
-
const restKeys = keyParts.slice(1);
|
|
147
|
-
|
|
148
|
-
// Check if top-level key exists
|
|
149
|
-
const topLevelRegex = new RegExp(`(${firstKey}:\\s*\\{)`, 'g');
|
|
150
|
-
const hasTopLevel = topLevelRegex.test(content);
|
|
151
|
-
|
|
152
|
-
if (!hasTopLevel) {
|
|
153
|
-
// Add new top-level key before closing brace
|
|
154
|
-
const closingBrace = content.lastIndexOf('}');
|
|
155
|
-
const indent = ' ';
|
|
156
|
-
const newEntry = buildNestedEntry(keyParts, value, indent);
|
|
157
|
-
return (
|
|
158
|
-
content.slice(0, closingBrace) + '\n' + newEntry + '\n' + content.slice(closingBrace)
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Navigate to the right nesting level and insert
|
|
163
|
-
// This is a simplified approach - for complex cases, consider AST parsing
|
|
164
|
-
let insertPoint = content.indexOf(`${firstKey}:`);
|
|
165
|
-
if (insertPoint === -1) return content;
|
|
166
|
-
|
|
167
|
-
// Find the opening brace for this section
|
|
168
|
-
let braceCount = 0;
|
|
169
|
-
let foundStart = false;
|
|
170
|
-
let insertIndex = insertPoint;
|
|
171
|
-
|
|
172
|
-
for (let i = insertPoint; i < content.length; i++) {
|
|
173
|
-
if (content[i] === '{') {
|
|
174
|
-
braceCount++;
|
|
175
|
-
foundStart = true;
|
|
176
|
-
} else if (content[i] === '}') {
|
|
177
|
-
braceCount--;
|
|
178
|
-
if (foundStart && braceCount === 0) {
|
|
179
|
-
// Insert before this closing brace
|
|
180
|
-
insertIndex = i;
|
|
181
|
-
break;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Build the entry
|
|
187
|
-
const indent = ' '; // 4 spaces for nested
|
|
188
|
-
const entry = restKeys.length === 0
|
|
189
|
-
? `${indent}${keyParts[keyParts.length - 1]}: '${escapeQuotes(value)}',`
|
|
190
|
-
: buildNestedEntry(restKeys, value, indent);
|
|
191
|
-
|
|
192
|
-
return content.slice(0, insertIndex) + '\n' + entry + '\n ' + content.slice(insertIndex);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Build nested entry string
|
|
197
|
-
*/
|
|
198
|
-
function buildNestedEntry(keys: string[], value: string, baseIndent: string): string {
|
|
199
|
-
if (keys.length === 1) {
|
|
200
|
-
return `${baseIndent}${keys[0]}: '${escapeQuotes(value)}',`;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const [first, ...rest] = keys;
|
|
204
|
-
const nestedContent = buildNestedEntry(rest, value, baseIndent + ' ');
|
|
205
|
-
return `${baseIndent}${first}: {\n${nestedContent}\n${baseIndent}},`;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Escape single quotes in value
|
|
210
|
-
*/
|
|
211
|
-
function escapeQuotes(value: string): string {
|
|
212
|
-
return value.replace(/'/g, "\\'");
|
|
213
|
-
}
|
package/src/cli/utils/locales.ts
CHANGED
|
@@ -123,12 +123,15 @@ export function readLocaleFile(
|
|
|
123
123
|
return { content, exportName: '' };
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
// Destructured rather than indexed: `\w+` cannot match empty, so a match
|
|
127
|
+
// always carries group 1 — but only the binding proves that to the compiler,
|
|
128
|
+
// and the same `throw` covers both halves instead of asserting one of them.
|
|
129
|
+
const [, exportName] = content.match(/export const (\w+)/) ?? [];
|
|
130
|
+
if (!exportName) {
|
|
128
131
|
throw new Error(`Could not find export in ${locale}${config.fileExtension}`);
|
|
129
132
|
}
|
|
130
133
|
|
|
131
|
-
return { content, exportName
|
|
134
|
+
return { content, exportName };
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
/**
|
|
@@ -183,23 +186,124 @@ export function getValueAtPath(obj: Record<string, unknown>, keyPath: string): u
|
|
|
183
186
|
}
|
|
184
187
|
|
|
185
188
|
/**
|
|
186
|
-
* Set value at nested path
|
|
189
|
+
* Set value at nested path.
|
|
190
|
+
*
|
|
191
|
+
* `isPlainRecord` rather than `typeof x === 'object'`: that test is true for
|
|
192
|
+
* `null` and for arrays. A `null` on the path crashed with "Cannot set
|
|
193
|
+
* properties of null", and an array swallowed the write silently — the value
|
|
194
|
+
* went nowhere and the CLI reported success.
|
|
195
|
+
*
|
|
196
|
+
* An empty `keyPath` writes nothing. `''.split('.')` yields `['']`, and the
|
|
197
|
+
* previous code indexed `keys[-1]`, producing a literal `"undefined"` key in
|
|
198
|
+
* the locale file.
|
|
187
199
|
*/
|
|
188
200
|
export function setValueAtPath(
|
|
189
201
|
obj: Record<string, unknown>,
|
|
190
202
|
keyPath: string,
|
|
191
203
|
value: unknown
|
|
192
204
|
): void {
|
|
193
|
-
const keys = keyPath.split('.');
|
|
205
|
+
const keys = keyPath.split('.').filter(Boolean);
|
|
206
|
+
const leaf = keys.pop();
|
|
207
|
+
if (leaf === undefined) return;
|
|
208
|
+
|
|
194
209
|
let current = obj;
|
|
210
|
+
for (const key of keys) {
|
|
211
|
+
const next = current[key];
|
|
212
|
+
current = isPlainRecord(next) ? next : (current[key] = {});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
current[leaf] = value;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** A value that can carry nested keys: an object, but not `null` and not an array. */
|
|
219
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
220
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Object keys that need no quoting in a TS/JS object literal. */
|
|
224
|
+
const BARE_KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Serialise a translations object back to a TypeScript object literal.
|
|
228
|
+
*
|
|
229
|
+
* Locale leaves are always strings and branches always plain objects, so this
|
|
230
|
+
* needs no general-purpose value support — anything else is a bug upstream and
|
|
231
|
+
* `JSON.stringify` is the honest fallback rather than a silent `[object]`.
|
|
232
|
+
*/
|
|
233
|
+
function toObjectLiteral(value: unknown, indent: string): string {
|
|
234
|
+
if (!isPlainRecord(value)) return JSON.stringify(value ?? null);
|
|
235
|
+
|
|
236
|
+
const inner = indent + ' ';
|
|
237
|
+
const body = Object.entries(value)
|
|
238
|
+
.map(([key, child]) => {
|
|
239
|
+
const name = BARE_KEY.test(key) ? key : JSON.stringify(key);
|
|
240
|
+
return `${inner}${name}: ${toObjectLiteral(child, inner)},`;
|
|
241
|
+
})
|
|
242
|
+
.join('\n');
|
|
243
|
+
|
|
244
|
+
return body ? `{\n${body}\n${indent}}` : '{}';
|
|
245
|
+
}
|
|
195
246
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
247
|
+
/**
|
|
248
|
+
* Replace the exported object literal in a TS locale file, keeping everything
|
|
249
|
+
* around it — the type import, the doc comment, and the `: I18nTranslations`
|
|
250
|
+
* annotation — untouched.
|
|
251
|
+
*
|
|
252
|
+
* The previous approach edited the text with `indexOf` and brace counting, and
|
|
253
|
+
* inserted a whole nested chain at the outermost level: adding `ui.form.cancel`
|
|
254
|
+
* to a file that already had `ui.form.save` produced a SECOND `form:` block
|
|
255
|
+
* inside `ui`. In a TS object literal the later key wins, so the existing
|
|
256
|
+
* translation was silently dropped — a data-loss bug, not a formatting one.
|
|
257
|
+
* The file's own comment said "for complex cases, consider AST parsing".
|
|
258
|
+
* Serialising the object `loadLocale` already parsed removes the need for both.
|
|
259
|
+
*/
|
|
260
|
+
export function renderTsLocale(
|
|
261
|
+
originalContent: string,
|
|
262
|
+
exportName: string,
|
|
263
|
+
translations: Record<string, unknown>
|
|
264
|
+
): string {
|
|
265
|
+
const declaration = new RegExp(`(export\\s+const\\s+${exportName}\\b[^=]*=\\s*)`);
|
|
266
|
+
const match = originalContent.match(declaration);
|
|
267
|
+
if (!match || match.index === undefined) {
|
|
268
|
+
throw new Error(`Could not find "export const ${exportName}" to update`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const bodyStart = match.index + match[0].length;
|
|
272
|
+
if (originalContent[bodyStart] !== '{') {
|
|
273
|
+
throw new Error(`Expected an object literal after "export const ${exportName}"`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const bodyEnd = matchBrace(originalContent, bodyStart);
|
|
277
|
+
return (
|
|
278
|
+
originalContent.slice(0, bodyStart) +
|
|
279
|
+
toObjectLiteral(translations, '') +
|
|
280
|
+
originalContent.slice(bodyEnd + 1)
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Index of the `}` closing the `{` at `start`.
|
|
286
|
+
*
|
|
287
|
+
* String-aware: a brace inside a translation (`"{count} items"`) would
|
|
288
|
+
* otherwise unbalance the count and truncate the file.
|
|
289
|
+
*/
|
|
290
|
+
function matchBrace(source: string, start: number): number {
|
|
291
|
+
let depth = 0;
|
|
292
|
+
let quote: string | null = null;
|
|
293
|
+
|
|
294
|
+
for (let i = start; i < source.length; i++) {
|
|
295
|
+
const char = source[i];
|
|
296
|
+
|
|
297
|
+
if (quote) {
|
|
298
|
+
if (char === '\\') i++;
|
|
299
|
+
else if (char === quote) quote = null;
|
|
300
|
+
continue;
|
|
200
301
|
}
|
|
201
|
-
|
|
302
|
+
|
|
303
|
+
if (char === '"' || char === "'" || char === '`') quote = char;
|
|
304
|
+
else if (char === '{') depth++;
|
|
305
|
+
else if (char === '}' && --depth === 0) return i;
|
|
202
306
|
}
|
|
203
307
|
|
|
204
|
-
|
|
308
|
+
throw new Error('Unbalanced braces in locale file');
|
|
205
309
|
}
|
package/src/context.tsx
CHANGED
|
@@ -117,11 +117,14 @@ export function I18nProvider({
|
|
|
117
117
|
[onLocaleChange]
|
|
118
118
|
)
|
|
119
119
|
|
|
120
|
-
// Sync with external locale changes
|
|
120
|
+
// Sync with external locale changes.
|
|
121
|
+
//
|
|
122
|
+
// The comparison moved inside the updater rather than `locale` joining the
|
|
123
|
+
// deps: this effect must run when the PROP changes, not when local state
|
|
124
|
+
// does. Depending on `locale` would re-run it after every `setLocale` call
|
|
125
|
+
// and reset the user's choice back to `initialLocale`.
|
|
121
126
|
React.useEffect(() => {
|
|
122
|
-
|
|
123
|
-
setLocaleState(initialLocale)
|
|
124
|
-
}
|
|
127
|
+
setLocaleState((current) => (current === initialLocale ? current : initialLocale))
|
|
125
128
|
}, [initialLocale])
|
|
126
129
|
|
|
127
130
|
const value = React.useMemo<I18nContextValue>(
|
package/src/locales/ar.ts
CHANGED
|
@@ -470,61 +470,6 @@ export const ar: I18nTranslations = {
|
|
|
470
470
|
},
|
|
471
471
|
},
|
|
472
472
|
|
|
473
|
-
centrifugo: {
|
|
474
|
-
monitor: {
|
|
475
|
-
title: 'مراقب Centrifugo',
|
|
476
|
-
description: 'مراقبة وتصحيح WebSocket في الوقت الفعلي',
|
|
477
|
-
openMonitor: 'فتح مراقب Centrifugo',
|
|
478
|
-
openDebugPanel: 'فتح لوحة تصحيح Centrifugo',
|
|
479
|
-
widgetTitle: 'مراقب WebSocket',
|
|
480
|
-
},
|
|
481
|
-
tabs: {
|
|
482
|
-
connection: 'الاتصال',
|
|
483
|
-
messages: 'الرسائل',
|
|
484
|
-
subscriptions: 'الاشتراكات',
|
|
485
|
-
},
|
|
486
|
-
subscriptionsList: {
|
|
487
|
-
title: 'الاشتراكات النشطة',
|
|
488
|
-
notConnected: 'غير متصل بـ Centrifugo',
|
|
489
|
-
noActiveSubscriptions: 'لا توجد اشتراكات نشطة',
|
|
490
|
-
},
|
|
491
|
-
status: {
|
|
492
|
-
connected: 'متصل',
|
|
493
|
-
disconnected: 'غير متصل',
|
|
494
|
-
connecting: 'جارٍ الاتصال...',
|
|
495
|
-
connect: 'اتصال',
|
|
496
|
-
uptime: 'وقت التشغيل:',
|
|
497
|
-
subscriptions: 'الاشتراكات:',
|
|
498
|
-
realtimeUnavailable: 'ميزات الوقت الفعلي غير متاحة',
|
|
499
|
-
},
|
|
500
|
-
feed: {
|
|
501
|
-
title: 'تغذية الرسائل',
|
|
502
|
-
noMessages: 'لا توجد رسائل بعد',
|
|
503
|
-
pausedClickToResume: 'متوقف - انقر على تشغيل للاستئناف',
|
|
504
|
-
autoScrollOn: 'التمرير التلقائي: مفعّل',
|
|
505
|
-
autoScrollOff: 'التمرير التلقائي: معطّل',
|
|
506
|
-
viewData: 'عرض البيانات',
|
|
507
|
-
},
|
|
508
|
-
filters: {
|
|
509
|
-
title: 'الفلاتر',
|
|
510
|
-
active: 'نشط',
|
|
511
|
-
clear: 'مسح',
|
|
512
|
-
searchMessages: 'البحث في الرسائل...',
|
|
513
|
-
level: 'المستوى:',
|
|
514
|
-
type: 'النوع:',
|
|
515
|
-
source: 'المصدر',
|
|
516
|
-
autoScrollToLatest: 'التمرير التلقائي للأحدث',
|
|
517
|
-
},
|
|
518
|
-
debug: {
|
|
519
|
-
title: 'تصحيح Centrifugo',
|
|
520
|
-
description: 'حالة اتصال WebSocket والسجلات والاشتراكات',
|
|
521
|
-
openDebugPanel: 'فتح لوحة تصحيح Centrifugo',
|
|
522
|
-
tabConnection: 'الاتصال',
|
|
523
|
-
tabLogs: 'السجلات',
|
|
524
|
-
tabSubscriptions: 'الاشتراكات',
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
|
-
|
|
528
473
|
tools: {
|
|
529
474
|
code: {
|
|
530
475
|
copyCode: 'نسخ الكود',
|
package/src/locales/da.ts
CHANGED
|
@@ -470,61 +470,6 @@ export const da: I18nTranslations = {
|
|
|
470
470
|
},
|
|
471
471
|
},
|
|
472
472
|
|
|
473
|
-
centrifugo: {
|
|
474
|
-
monitor: {
|
|
475
|
-
title: 'Centrifugo-monitor',
|
|
476
|
-
description: 'Realtids WebSocket-overvågning og fejlfinding',
|
|
477
|
-
openMonitor: 'Åbn Centrifugo-monitor',
|
|
478
|
-
openDebugPanel: 'Åbn Centrifugo-fejlfindingspanel',
|
|
479
|
-
widgetTitle: 'WebSocket-monitor',
|
|
480
|
-
},
|
|
481
|
-
tabs: {
|
|
482
|
-
connection: 'Forbindelse',
|
|
483
|
-
messages: 'Beskeder',
|
|
484
|
-
subscriptions: 'Abonnementer',
|
|
485
|
-
},
|
|
486
|
-
subscriptionsList: {
|
|
487
|
-
title: 'Aktive abonnementer',
|
|
488
|
-
notConnected: 'Ikke forbundet til Centrifugo',
|
|
489
|
-
noActiveSubscriptions: 'Ingen aktive abonnementer',
|
|
490
|
-
},
|
|
491
|
-
status: {
|
|
492
|
-
connected: 'Forbundet',
|
|
493
|
-
disconnected: 'Afbrudt',
|
|
494
|
-
connecting: 'Forbinder...',
|
|
495
|
-
connect: 'Forbind',
|
|
496
|
-
uptime: 'Oppetid:',
|
|
497
|
-
subscriptions: 'Abonnementer:',
|
|
498
|
-
realtimeUnavailable: 'Realtidsfunktioner utilgængelige',
|
|
499
|
-
},
|
|
500
|
-
feed: {
|
|
501
|
-
title: 'Beskedstrøm',
|
|
502
|
-
noMessages: 'Ingen beskeder endnu',
|
|
503
|
-
pausedClickToResume: 'Sat på pause - Klik på afspil for at fortsætte',
|
|
504
|
-
autoScrollOn: 'Automatisk scroll: TIL',
|
|
505
|
-
autoScrollOff: 'Automatisk scroll: FRA',
|
|
506
|
-
viewData: 'Vis data',
|
|
507
|
-
},
|
|
508
|
-
filters: {
|
|
509
|
-
title: 'Filtre',
|
|
510
|
-
active: 'Aktiv',
|
|
511
|
-
clear: 'Ryd',
|
|
512
|
-
searchMessages: 'Søg i beskeder...',
|
|
513
|
-
level: 'Niveau:',
|
|
514
|
-
type: 'Type:',
|
|
515
|
-
source: 'Kilde',
|
|
516
|
-
autoScrollToLatest: 'Automatisk scroll til nyeste',
|
|
517
|
-
},
|
|
518
|
-
debug: {
|
|
519
|
-
title: 'Centrifugo-fejlfinding',
|
|
520
|
-
description: 'WebSocket-forbindelsesstatus, logs og abonnementer',
|
|
521
|
-
openDebugPanel: 'Åbn Centrifugo-fejlfindingspanel',
|
|
522
|
-
tabConnection: 'Forbindelse',
|
|
523
|
-
tabLogs: 'Logs',
|
|
524
|
-
tabSubscriptions: 'Abonnementer',
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
|
-
|
|
528
473
|
tools: {
|
|
529
474
|
code: {
|
|
530
475
|
copyCode: 'Kopier kode',
|
package/src/locales/de.ts
CHANGED
|
@@ -470,61 +470,6 @@ export const de: I18nTranslations = {
|
|
|
470
470
|
},
|
|
471
471
|
},
|
|
472
472
|
|
|
473
|
-
centrifugo: {
|
|
474
|
-
monitor: {
|
|
475
|
-
title: 'Centrifugo Monitor',
|
|
476
|
-
description: 'Echtzeit-WebSocket-Überwachung und Debugging',
|
|
477
|
-
openMonitor: 'Centrifugo Monitor öffnen',
|
|
478
|
-
openDebugPanel: 'Centrifugo Debug-Panel öffnen',
|
|
479
|
-
widgetTitle: 'WebSocket Monitor',
|
|
480
|
-
},
|
|
481
|
-
tabs: {
|
|
482
|
-
connection: 'Verbindung',
|
|
483
|
-
messages: 'Nachrichten',
|
|
484
|
-
subscriptions: 'Abonnements',
|
|
485
|
-
},
|
|
486
|
-
subscriptionsList: {
|
|
487
|
-
title: 'Aktive Abonnements',
|
|
488
|
-
notConnected: 'Nicht mit Centrifugo verbunden',
|
|
489
|
-
noActiveSubscriptions: 'Keine aktiven Abonnements',
|
|
490
|
-
},
|
|
491
|
-
status: {
|
|
492
|
-
connected: 'Verbunden',
|
|
493
|
-
disconnected: 'Getrennt',
|
|
494
|
-
connecting: 'Verbinden...',
|
|
495
|
-
connect: 'Verbinden',
|
|
496
|
-
uptime: 'Betriebszeit:',
|
|
497
|
-
subscriptions: 'Abonnements:',
|
|
498
|
-
realtimeUnavailable: 'Echtzeit-Funktionen nicht verfügbar',
|
|
499
|
-
},
|
|
500
|
-
feed: {
|
|
501
|
-
title: 'Nachrichten-Feed',
|
|
502
|
-
noMessages: 'Noch keine Nachrichten',
|
|
503
|
-
pausedClickToResume: 'Pausiert - Klicken Sie auf Wiedergabe zum Fortsetzen',
|
|
504
|
-
autoScrollOn: 'Auto-Scroll: AN',
|
|
505
|
-
autoScrollOff: 'Auto-Scroll: AUS',
|
|
506
|
-
viewData: 'Daten anzeigen',
|
|
507
|
-
},
|
|
508
|
-
filters: {
|
|
509
|
-
title: 'Filter',
|
|
510
|
-
active: 'Aktiv',
|
|
511
|
-
clear: 'Löschen',
|
|
512
|
-
searchMessages: 'Nachrichten suchen...',
|
|
513
|
-
level: 'Stufe:',
|
|
514
|
-
type: 'Typ:',
|
|
515
|
-
source: 'Quelle',
|
|
516
|
-
autoScrollToLatest: 'Auto-Scroll zum Neuesten',
|
|
517
|
-
},
|
|
518
|
-
debug: {
|
|
519
|
-
title: 'Centrifugo Debug',
|
|
520
|
-
description: 'WebSocket-Verbindungsstatus, Protokolle und Abonnements',
|
|
521
|
-
openDebugPanel: 'Centrifugo Debug-Panel öffnen',
|
|
522
|
-
tabConnection: 'Verbindung',
|
|
523
|
-
tabLogs: 'Protokolle',
|
|
524
|
-
tabSubscriptions: 'Abonnements',
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
|
-
|
|
528
473
|
tools: {
|
|
529
474
|
code: {
|
|
530
475
|
copyCode: 'Code kopieren',
|
package/src/locales/en.ts
CHANGED
|
@@ -479,61 +479,6 @@ export const en: I18nTranslations = {
|
|
|
479
479
|
},
|
|
480
480
|
},
|
|
481
481
|
|
|
482
|
-
centrifugo: {
|
|
483
|
-
monitor: {
|
|
484
|
-
title: 'Centrifugo Monitor',
|
|
485
|
-
description: 'Real-time WebSocket monitoring and debugging',
|
|
486
|
-
openMonitor: 'Open Centrifugo Monitor',
|
|
487
|
-
openDebugPanel: 'Open Centrifugo Debug Panel',
|
|
488
|
-
widgetTitle: 'WebSocket Monitor',
|
|
489
|
-
},
|
|
490
|
-
tabs: {
|
|
491
|
-
connection: 'Connection',
|
|
492
|
-
messages: 'Messages',
|
|
493
|
-
subscriptions: 'Subscriptions',
|
|
494
|
-
},
|
|
495
|
-
subscriptionsList: {
|
|
496
|
-
title: 'Active Subscriptions',
|
|
497
|
-
notConnected: 'Not connected to Centrifugo',
|
|
498
|
-
noActiveSubscriptions: 'No active subscriptions',
|
|
499
|
-
},
|
|
500
|
-
status: {
|
|
501
|
-
connected: 'Connected',
|
|
502
|
-
disconnected: 'Disconnected',
|
|
503
|
-
connecting: 'Connecting...',
|
|
504
|
-
connect: 'Connect',
|
|
505
|
-
uptime: 'Uptime:',
|
|
506
|
-
subscriptions: 'Subscriptions:',
|
|
507
|
-
realtimeUnavailable: 'Real-time features unavailable',
|
|
508
|
-
},
|
|
509
|
-
feed: {
|
|
510
|
-
title: 'Messages Feed',
|
|
511
|
-
noMessages: 'No messages yet',
|
|
512
|
-
pausedClickToResume: 'Paused - Click play to resume',
|
|
513
|
-
autoScrollOn: 'Auto-scroll: ON',
|
|
514
|
-
autoScrollOff: 'Auto-scroll: OFF',
|
|
515
|
-
viewData: 'View data',
|
|
516
|
-
},
|
|
517
|
-
filters: {
|
|
518
|
-
title: 'Filters',
|
|
519
|
-
active: 'Active',
|
|
520
|
-
clear: 'Clear',
|
|
521
|
-
searchMessages: 'Search messages...',
|
|
522
|
-
level: 'Level:',
|
|
523
|
-
type: 'Type:',
|
|
524
|
-
source: 'Source',
|
|
525
|
-
autoScrollToLatest: 'Auto-scroll to latest',
|
|
526
|
-
},
|
|
527
|
-
debug: {
|
|
528
|
-
title: 'Centrifugo Debug',
|
|
529
|
-
description: 'WebSocket connection status, logs, and subscriptions',
|
|
530
|
-
openDebugPanel: 'Open Centrifugo Debug Panel',
|
|
531
|
-
tabConnection: 'Connection',
|
|
532
|
-
tabLogs: 'Logs',
|
|
533
|
-
tabSubscriptions: 'Subscriptions',
|
|
534
|
-
},
|
|
535
|
-
},
|
|
536
|
-
|
|
537
482
|
tools: {
|
|
538
483
|
code: {
|
|
539
484
|
copyCode: 'Copy code',
|
package/src/locales/es.ts
CHANGED
|
@@ -470,61 +470,6 @@ export const es: I18nTranslations = {
|
|
|
470
470
|
},
|
|
471
471
|
},
|
|
472
472
|
|
|
473
|
-
centrifugo: {
|
|
474
|
-
monitor: {
|
|
475
|
-
title: 'Monitor Centrifugo',
|
|
476
|
-
description: 'Monitoreo y depuración de WebSocket en tiempo real',
|
|
477
|
-
openMonitor: 'Abrir Monitor Centrifugo',
|
|
478
|
-
openDebugPanel: 'Abrir Panel de Depuración Centrifugo',
|
|
479
|
-
widgetTitle: 'Monitor WebSocket',
|
|
480
|
-
},
|
|
481
|
-
tabs: {
|
|
482
|
-
connection: 'Conexión',
|
|
483
|
-
messages: 'Mensajes',
|
|
484
|
-
subscriptions: 'Suscripciones',
|
|
485
|
-
},
|
|
486
|
-
subscriptionsList: {
|
|
487
|
-
title: 'Suscripciones activas',
|
|
488
|
-
notConnected: 'No conectado a Centrifugo',
|
|
489
|
-
noActiveSubscriptions: 'No hay suscripciones activas',
|
|
490
|
-
},
|
|
491
|
-
status: {
|
|
492
|
-
connected: 'Conectado',
|
|
493
|
-
disconnected: 'Desconectado',
|
|
494
|
-
connecting: 'Conectando...',
|
|
495
|
-
connect: 'Conectar',
|
|
496
|
-
uptime: 'Tiempo activo:',
|
|
497
|
-
subscriptions: 'Suscripciones:',
|
|
498
|
-
realtimeUnavailable: 'Funciones en tiempo real no disponibles',
|
|
499
|
-
},
|
|
500
|
-
feed: {
|
|
501
|
-
title: 'Feed de mensajes',
|
|
502
|
-
noMessages: 'No hay mensajes aún',
|
|
503
|
-
pausedClickToResume: 'Pausado - Haz clic en reproducir para continuar',
|
|
504
|
-
autoScrollOn: 'Auto-scroll: ACTIVADO',
|
|
505
|
-
autoScrollOff: 'Auto-scroll: DESACTIVADO',
|
|
506
|
-
viewData: 'Ver datos',
|
|
507
|
-
},
|
|
508
|
-
filters: {
|
|
509
|
-
title: 'Filtros',
|
|
510
|
-
active: 'Activo',
|
|
511
|
-
clear: 'Limpiar',
|
|
512
|
-
searchMessages: 'Buscar mensajes...',
|
|
513
|
-
level: 'Nivel:',
|
|
514
|
-
type: 'Tipo:',
|
|
515
|
-
source: 'Fuente',
|
|
516
|
-
autoScrollToLatest: 'Auto-scroll a lo más reciente',
|
|
517
|
-
},
|
|
518
|
-
debug: {
|
|
519
|
-
title: 'Depuración Centrifugo',
|
|
520
|
-
description: 'Estado de conexión WebSocket, logs y suscripciones',
|
|
521
|
-
openDebugPanel: 'Abrir Panel de Depuración Centrifugo',
|
|
522
|
-
tabConnection: 'Conexión',
|
|
523
|
-
tabLogs: 'Logs',
|
|
524
|
-
tabSubscriptions: 'Suscripciones',
|
|
525
|
-
},
|
|
526
|
-
},
|
|
527
|
-
|
|
528
473
|
tools: {
|
|
529
474
|
code: {
|
|
530
475
|
copyCode: 'Copiar código',
|