-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathen.ts
More file actions
619 lines (599 loc) · 24.5 KB
/
Copy pathen.ts
File metadata and controls
619 lines (599 loc) · 24.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
const en = {
common: {
create: 'Create',
edit: 'Edit',
delete: 'Delete',
save: 'Save',
cancel: 'Cancel',
confirm: 'Confirm',
close: 'Close',
refresh: 'Refresh',
copy: 'Copy',
copied: 'Copied',
loading: 'Loading...',
submitting: 'Submitting...',
saving: 'Saving...',
success: 'Success',
error: 'Error',
name: 'Name',
url: 'URL',
actions: 'Actions',
createdAt: 'Created At',
search: 'Search',
noData: 'No data',
required: 'Required',
optional: 'Optional',
yes: 'Yes',
no: 'No',
enabled: 'Enabled',
disabled: 'Disabled',
back: 'Back',
selectAll: 'Select All',
deselectAll: 'Deselect All',
detail: 'Detail',
status: 'Status',
type: 'Type',
value: 'Value',
mode: 'Mode',
prev: 'Previous',
next: 'Next',
page: 'Page {{page}}',
add: 'Add',
remove: 'Remove',
update: 'Update',
description: 'Description',
showPassword: 'Show password',
hidePassword: 'Hide password',
},
nav: {
brandName: 'Clash Config Store',
dashboard: 'Dashboard',
providers: 'Providers',
userAgents: 'UA Library',
customConfigs: 'Custom Configs',
subscriptions: 'Subscriptions',
configTemplates: 'Config Templates',
ruleProviders: 'Rule Set Library',
hostedRuleSets: 'Hosted Rule Sets',
settings: 'Settings',
logout: 'Logout',
profile: 'Profile',
},
layout: {
collapseSidebar: 'Collapse sidebar',
expandSidebar: 'Expand sidebar',
},
auth: {
login: 'Login',
register: 'Register',
loginTitle: 'Welcome Back',
loginSubtitle: 'Sign in to Clash Config Store',
registerTitle: 'Create Account',
registerSubtitle: 'Register for Clash Config Store',
email: 'Email',
password: 'Password',
confirmPassword: 'Confirm Password',
username: 'Username',
loginButton: 'Sign In',
registerButton: 'Register',
noAccount: "Don't have an account?",
hasAccount: 'Already have an account?',
goRegister: 'Register',
goLogin: 'Sign In',
loginSuccess: 'Login successful',
registerSuccess: 'Registration successful',
logoutSuccess: 'Logged out',
invalidCredentials: 'Invalid email or password',
emailPlaceholder: 'Enter your email',
passwordPlaceholder: 'Enter your password',
usernamePlaceholder: 'Enter your username',
confirmPasswordPlaceholder: 'Confirm your password',
passwordMismatch: 'Passwords do not match',
emailRequired: 'Email is required',
passwordRequired: 'Password is required',
passwordMinLength: 'Password must be at least {{min}} characters',
nameRequired: 'Username is required',
emailInvalid: 'Invalid email format',
},
hostedRuleSets: {
title: 'Hosted Rule Sets',
add: 'Add Hosted Rule Set',
edit: 'Edit Hosted Rule Set',
delete: 'Delete Hosted Rule Set',
deleteConfirm: 'Delete this hosted rule set? This action cannot be undone.',
url: 'URL',
content: 'Content',
resetAllTokens: 'Reset All Hosted Rule Set Tokens',
resetAllTokensConfirm: 'This will reset tokens for all hosted rule sets in the current account. All old URLs will stop working immediately and clients must update their links.',
nameHint: 'The name is used directly in the URL and only allows letters, numbers, underscores, and hyphens.',
nameInvalid: 'Only letters, numbers, underscores, and hyphens are allowed.',
customSection: 'Hosted Rule Sets',
},
contextSaveBar: {
unsaved: 'Unsaved changes',
discard: 'Discard',
leaveTitle: 'Leave this page?',
leaveDescription: 'You have unsaved changes. If you leave now, they will be lost.',
stay: 'Stay',
leave: 'Leave',
viewDiff: 'Diff',
diffTitle: 'Change preview',
diffDescription: 'Renders both snapshots as YAML, then shows an inline word-level diff (green = added, red strikethrough = removed). Opens scrolled to the first change.',
diffNoChanges: 'No differences from the last saved version.',
},
onboarding: {
dashboardTitle: 'Create your first subscription in three steps',
dashboardDescription: 'A workflow you can revisit any time: add an upstream provider, prepare a custom config, then create a subscription URL for your client.',
done: 'Done',
progress: '{{done}} / {{total}} steps done',
expand: 'Show steps',
collapse: 'Hide steps',
stepProviderTitle: 'Add a provider',
stepProviderDescription: 'Paste an existing upstream subscription URL so the app can cache and parse its nodes.',
stepConfigTitle: 'Prepare a custom config',
stepConfigDescription: 'Start from the sample config, then adjust proxy groups, rules, and rule-set references.',
stepSubscriptionTitle: 'Create a subscription',
stepSubscriptionDescription: 'Bind providers and config, then copy the generated URL into Mihomo or Clash.',
},
dashboard: {
title: 'Dashboard',
totalProviders: 'Providers',
totalSubscriptions: 'Subscriptions',
totalCustomConfigs: 'Custom Configs',
totalConfigTemplates: 'Config Templates',
totalRuleProviders: 'Rule Sets',
recentLogs: 'Recent Access Logs',
recentLogsDescription: 'The latest 10 subscription URL visits for checking sources and blocked requests.',
recentActivity: 'Recent Activity',
recentActivitySummary: 'Allowed {{allowed}} / Denied {{denied}}',
allowedCount: 'Allowed {{count}}',
deniedCount: 'Denied {{count}}',
allowedCountTooltip: 'Allowed requests in the latest 10 access logs',
deniedCountTooltip: 'Denied requests in the latest 10 access logs',
noRecentLogsTitle: 'No access yet',
noRecentLogsDescription: 'Recent activity will appear here after clients access subscription URLs.',
ip: 'IP Address',
country: 'Country',
allowed: 'Status',
denyReason: 'Deny Reason',
time: 'Time',
subscription: 'Subscription',
providerStatus: 'Provider Status',
providerStatusDescription: 'Watch cache freshness, upstream fetch errors, and sources needing action.',
subscriptionHealth: 'Subscription Health',
subscriptionHealthDescription: 'Check token validity and config/template bindings.',
needAttention: '{{count}} to review',
allClear: 'All clear',
refreshAll: 'Refresh All Providers',
refreshAllSuccess: 'All provider refreshes triggered',
cacheStale: 'Cache Stale',
cacheOk: 'Cache OK',
lastFetched: 'Last Fetched',
neverFetched: 'Never fetched',
tokenExpired: 'Token Expired',
tokenNeverExpires: 'Never expires',
daysLeft: '{{days}} days left',
copyLink: 'Copy subscription URL',
noCustomConfig: 'No config',
noConfigTemplate: 'No template',
hasCustomConfig: 'Has config',
hasConfigTemplate: 'Has template',
fetchError: 'Fetch error',
unknownLocation: 'Unknown location',
relativeJustNow: 'just now',
relativeMinutesAgo: '{{count}} minutes ago',
relativeHoursAgo: '{{count}} hours ago',
},
providers: {
title: 'Provider Management',
addProvider: 'Add Provider',
editProvider: 'Edit Provider',
deleteProvider: 'Delete Provider',
deleteConfirm: 'Are you sure you want to delete this provider?',
providerName: 'Provider Name',
providerUrl: 'Subscription URL',
userAgent: 'User-Agent',
cacheTTL: 'Cache TTL (seconds)',
lastFetched: 'Last Fetched',
fetchError: 'Fetch Error',
refreshing: 'Refreshing...',
refreshSuccess: 'Refresh successful',
refreshFailed: 'Refresh failed',
neverFetched: 'Never fetched',
selectUA: 'Select UA (optional)',
noUA: 'No UA',
namePlaceholder: 'Enter provider name',
urlPlaceholder: 'Enter subscription URL',
cacheTTLPlaceholder: 'Cache TTL in seconds, 0 = no cache',
emptyTitle: 'Add your first upstream provider',
emptyDescription: 'Providers supply the real nodes. Later, subscriptions can enable these sources and merge them into the final config.',
},
userAgents: {
title: 'User-Agent Library',
addUA: 'Add UA',
editUA: 'Edit UA',
deleteUA: 'Delete UA',
deleteConfirm: 'Are you sure you want to delete this UA?',
uaName: 'UA Name',
uaValue: 'UA Value',
namePlaceholder: 'Enter UA name (e.g., Clash)',
valuePlaceholder: 'Enter User-Agent string',
presets: 'Presets',
},
customConfigs: {
title: 'Custom Configs',
updatedAt: 'Updated At',
statsSummary: 'Proxies {{proxies}} / Groups {{groups}} / Rules {{rules}} / Rule Sets {{ruleSets}}',
relativeJustNow: 'just now',
relativeMinutesAgo: '{{count}} minutes ago',
relativeHoursAgo: '{{count}} hours ago',
relativeDaysAgo: '{{count}} days ago',
addConfig: 'New Config',
cloneConfig: 'Clone Config',
cloneSuccess: 'Config duplicated',
importConfig: 'Import Config',
importSuccess: 'Config imported',
importUploadFile: 'Upload JSON File',
importChooseFile: 'Choose File',
importPasteJson: 'Or Paste JSON',
importInvalidJson: 'Failed to parse JSON',
importInvalidFormat: 'Imported content is missing required fields or has invalid types',
exportConfig: 'Export Config',
exportSuccess: 'Config exported',
editConfig: 'Edit Config',
deleteConfig: 'Delete Config',
deleteConfirm: 'Are you sure you want to delete this config?',
configName: 'Config Name',
namePlaceholder: 'Enter config name',
saveSuccess: 'Config saved',
detail: 'Custom Config Detail',
clickToEditTitle: 'Click to edit config name',
tabProxies: 'Proxies',
tabProxyGroups: 'Proxy Groups',
tabRules: 'Rules',
tabRuleSets: 'Rule Sets',
addProxy: 'Add Proxy',
editProxy: 'Edit Proxy',
deleteProxy: 'Delete Proxy',
duplicateProxy: 'Duplicate Proxy',
proxyCopySuffix: 'Copy',
proxyDuplicated: 'Proxy duplicate added',
proxyName: 'Proxy Name',
proxyType: 'Protocol',
proxyServer: 'Server',
proxyPort: 'Port',
rawYaml: 'Raw YAML',
switchToForm: 'Switch to Form',
switchToYaml: 'Switch to YAML',
addProxyGroup: 'Add Group',
editProxyGroup: 'Edit Group',
deleteProxyGroup: 'Delete Group',
groupName: 'Group Name',
groupType: 'Type',
groupProxies: 'Members',
groupProxiesSelected: 'Selected (drag to reorder)',
groupProxiesAvailable: 'Available to add',
groupProxiesEmptyHint: 'Check items below to add. Order is written to the generated config.',
groupProxiesNothingToAdd: 'Nothing to add (all selected or no candidates).',
groupUse: 'Use Providers',
groupUseHint: 'Dynamically inject nodes from providers at generation time',
groupUrl: 'Health Check URL',
groupInterval: 'Interval (s)',
groupTolerance: 'Tolerance (ms)',
groupStrategy: 'Strategy',
addRule: 'Add Rule',
ruleType: 'Rule Type',
rulePayload: 'Payload',
ruleTarget: 'Target',
ruleNoResolve: 'no-resolve',
ruleNoResolveHint:
'For GEOIP / IP-CIDR-style destination-IP rules. Appends ,no-resolve so Mihomo skips DNS resolution when checking whether a domain hits this rule. If an earlier rule already resolved DNS, this rule may still match.',
ruleNoResolveHintRuleSet:
'RULE-SET rules may take no-resolve. When checked, appends ,no-resolve; Mihomo applies it per the rule engine (different from IP-only rules; see docs).',
ruleAnalysis: {
emptyRule: 'Empty rules will not be saved',
missingType: 'Missing rule type',
unsupportedType: 'Unsupported rule type: {{type}}',
missingPayload: 'Missing match content',
matchMissingTarget: 'MATCH rule must specify a target policy',
missingTarget: 'Missing target policy',
ruleSetNotFound: 'Rule set "{{name}}" does not exist',
ruleSetNotSelected: 'Rule set "{{name}}" is not selected in rule set references',
targetNotFound: 'Target policy "{{name}}" does not exist in built-ins, proxy groups, or nodes',
matchShouldBeLast: 'MATCH should be kept at the end of the rule list',
noResolveUnsupported: 'no-resolve is typically only for GEOIP / IP-CIDR destination-IP rules; it may not work as expected for this type',
duplicateRules: '{{count}} identical rules found',
fixCheckRuleSets: 'Check rule sets',
fixGoSelectRuleSets: 'Go select rule sets',
fixCheckGroups: 'Check proxy groups',
fixCheckProxies: 'Check proxy nodes',
fixMoveToBottom: 'Move to bottom',
},
ruleTypeHint: {
exactDomain: 'Exact domain match',
suffixDomain: 'Match domain suffix',
keywordDomain: 'Match domain keyword',
regexDomain: 'Supports commas, uses regular expressions',
wildcardDomain: 'Match wildcard domains',
geoSite: 'GeoSite category name',
geoIp: 'Country/region code',
srcGeoIp: 'Source country/region code',
ipCidr: 'IPv4 CIDR',
ipCidr6: 'IPv6 CIDR',
ipAsn: 'ASN number',
ipSuffix: 'IP suffix match',
ruleSet: 'Name from rule set library',
processName: 'Process name match',
processPath: 'Process path match',
port: 'Port number',
network: 'Network type (tcp / udp)',
dscp: 'DSCP value',
uid: 'User ID',
match: 'Fallback rule, usually placed last',
default: 'Rule match condition',
},
ruleTargetHint: 'Choose from built-ins, proxy groups, or proxy nodes',
rawRulesMode: 'Raw Text Mode',
structuredRulesMode: 'Structured Mode',
tableRulesMode: 'Table Mode',
selectRuleSets: 'Select Rule Sets',
ruleSetSelected: '{{count}} rule sets selected',
ruleSetHint: 'Selected rule sets will be injected as rule-providers in the generated config',
ruleSetSelectionHint: 'RULE-SET must reference an existing selected rule set name',
ruleSetDuplicateName: 'A rule set with the same name is already selected. Rename it before selecting both.',
ruleSetMissing: 'Missing',
ruleSearchPlaceholder: 'Search rule type, payload, or target',
ruleQuickFilter: 'Quick Filter',
ruleFilterAll: 'All',
ruleFilterDomain: 'DOMAIN family',
ruleFilterRuleSet: 'RULE-SET',
ruleFilterGeoIp: 'GEOIP',
ruleFilterMatch: 'MATCH',
onlyShowIssues: 'Issues Only',
clearFilters: 'Clear Filters',
visibleRules: 'Showing {{count}} / {{total}}',
quickInsert: 'Quick Insert',
rulesWorkspaceTitle: 'Rules Workspace',
rulesWorkspaceStructuredHint: 'Structured mode is optimized for drag-sort, quick edits, and reference fixes',
rulesWorkspaceTextHint: 'Text mode supports bulk paste, advanced rules, and line-based diagnostics',
normalizeMatch: 'Move MATCH to Bottom',
matchShouldBeLast: 'MATCH is not at the bottom and may short-circuit later rules.',
ruleStatTotal: 'Total Rules',
ruleStatRuleSets: 'RULE-SET Count',
ruleStatWarnings: 'Warnings',
ruleStatErrors: 'Errors',
ruleStatusValid: 'Valid',
ruleStatusWarning: 'Warning',
ruleStatusError: 'Error',
rulePayloadNotRequired: 'No payload needed',
matchRuleCompactHint: 'No input needed',
matchRuleHint: 'MATCH only needs a target strategy',
matchRuleUnique: 'Only one MATCH rule is allowed',
ruleDiagnostics: 'Text Diagnostics',
ruleDiagnosticsHint: 'Analyze the current text line by line to locate issues quickly',
noMatchingRules: 'No rules match the current filter',
noMatchingRulesHint: 'Try clearing search terms, changing filters, or adding a new rule',
ruleContextTitle: 'Rule Context',
ruleContextHint: 'Shows the rule sets and targets currently referenced by this rule list',
ruleContextRuleSets: 'Referenced Rule Sets',
ruleContextRuleSetsHint: 'Missing or unselected rule sets are highlighted',
ruleContextTargets: 'Referenced Targets',
ruleContextTargetsHint: 'Use this to confirm targets are still valid',
ruleChecklistTitle: 'Before Saving',
ruleChecklistRuleSets: 'Make sure RULE-SET entries are selected in the Rule Sets tab.',
ruleChecklistTargets: 'Make sure targets still point to valid built-ins, groups, or nodes.',
ruleChecklistMatch: 'Keep MATCH at the bottom so it does not short-circuit later rules.',
currentRuleCard: 'Current Rule Status',
noActiveRule: 'Select a rule to see detailed diagnostics and quick fixes here.',
targetBuiltin: 'Built-ins',
targetProxyGroups: 'Proxy Groups',
targetProxies: 'Proxy Nodes',
ruleTargetMissing: 'Missing',
previewYaml: 'YAML Preview',
previewLoading: 'Generating preview...',
refreshPreview: 'Refresh Preview',
copyPreview: 'Copy YAML',
previewRulesCount: 'Rules {{count}}',
previewGroupsCount: 'Groups {{count}}',
previewRuleSetsCount: 'Rule Sets {{count}}',
unsavedChanges: 'Unsaved changes',
validationErrorsBadge: '{{count}} errors to fix',
validationWarningsBadge: '{{count}} warnings to review',
validationReady: 'Rules look good',
lastCheckError: 'Last check found errors',
lastCheckWarning: 'Last check found warnings',
lastCheckValid: 'Last check passed',
ruleTextFixErrorsFirst: 'Fix text mode errors before switching back to structured mode',
saveBlockedByErrors: 'Rule errors still exist, save was blocked',
renameConflict: 'This name is already used by another proxy or proxy group',
renameRefsSynced: 'Updated {{count}} reference(s) automatically',
emptyTitle: 'Start with a custom config',
emptyDescription: 'Custom configs organize proxy groups and rules. Beginners can import the sample first, then adjust it around their own providers.',
importSample: 'Import Sample Config',
sampleName: 'Starter Sample Config',
detailGuideTitle: 'A config has three main parts',
detailGuideDescription: 'Proxies are optional hand-written nodes, proxy groups combine nodes or providers into strategies, and rules decide which strategy traffic uses. Beginners usually start with groups and rules.',
},
configTemplates: {
title: 'Config Templates',
addTemplate: 'New Template',
editTemplate: 'Edit Template',
deleteTemplate: 'Delete Template',
deleteConfirm: 'Are you sure you want to delete this template?',
templateName: 'Template Name',
templateDescription: 'Description',
templateContent: 'Content (YAML)',
namePlaceholder: 'Enter template name',
descriptionPlaceholder: 'Optional description',
contentPlaceholder: '# Top-level mihomo config\n# e.g. mixed-port, dns, tun\nmixed-port: 7890\nmode: rule\n',
saveSuccess: 'Template saved',
detail: 'Config Template Detail',
contentHint: 'This config is the top-level base. proxies/proxy-groups/rules come from Custom Configs and do not need to be defined here.',
},
ruleProviders: {
title: 'Rule Set Library',
addProvider: 'Add Rule Set',
editProvider: 'Edit Rule Set',
deleteProvider: 'Delete Rule Set',
deleteConfirm: 'Are you sure you want to delete this rule set?',
providerName: 'Rule Set Name',
providerType: 'Type',
providerSource: 'Source',
providerUrl: 'URL',
providerBehavior: 'Behavior',
providerFormat: 'Format',
providerInterval: 'Interval (s)',
isPreset: 'Built-in Preset',
presetTag: 'Preset Tag',
namePlaceholder: 'e.g. my-rules (used in RULE-SET references)',
urlPlaceholder: 'Rule file URL',
behaviorDomain: 'Domain',
behaviorIpcidr: 'IP-CIDR',
behaviorClassical: 'Classical',
formatYaml: 'YAML',
formatText: 'Text',
formatMrs: 'MRS',
typeHttp: 'HTTP',
typeFile: 'File',
presetBadge: 'Built-in',
cannotDelete: 'Built-in presets cannot be deleted',
cannotEdit: 'Built-in presets cannot be modified',
loyalsoldierSection: 'Loyalsoldier Built-in Presets',
customSection: 'External Rule Sets',
addSuccess: 'Rule set added',
updateSuccess: 'Rule set updated',
deleteSuccess: 'Rule set deleted',
},
subscriptions: {
title: 'Subscription Management',
addSubscription: 'Create Subscription',
editSubscription: 'Edit Subscription',
deleteSubscription: 'Delete Subscription',
deleteConfirm: 'Are you sure you want to delete this subscription?',
subscriptionName: 'Subscription Name',
token: 'Token',
tokenExpiredAt: 'Token Expiry',
regenerateToken: 'Regenerate Token',
regenerateConfirm: 'Regenerating the token will invalidate the old one. Continue?',
subscriptionUrl: 'Subscription URL',
providers: 'Providers',
enabledProviders: 'Enabled Providers',
noProviders: 'No providers available, please add one first',
customConfig: 'Custom Config',
selectCustomConfig: 'Select Custom Config (optional)',
noCustomConfig: 'No custom config',
configTemplate: 'Config Template',
selectConfigTemplate: 'Select Config Template (optional)',
noConfigTemplate: 'No config template',
ruleInsertMode: 'Rule Insert Mode',
prepend: 'Prepend (custom rules first)',
append: 'Append (custom rules last)',
replace: 'Replace (custom rules only)',
proxyPrefixEnabled: 'Enable Proxy Prefix',
proxyPrefixDesc: 'Add provider name as prefix to proxy names to avoid conflicts',
accessRestrictions: 'Access Restrictions',
addRestriction: 'Add Restriction',
restrictionType: 'Restriction Type',
restrictionValue: 'Restriction Value',
restrictionMode: 'Restriction Mode',
allow: 'Allow',
deny: 'Deny',
typeIP: 'IP Address',
typeCIDR: 'CIDR Range',
typeCountry: 'Country',
accessLogs: 'Access Logs',
viewLogs: 'View Logs',
accessLogCount: 'Access count',
copySubscriptionUrl: 'Copy subscription URL',
shareSubscriptionUrl: 'Share QR Code',
shareDialogTitle: 'Share Subscription: {{name}}',
shareDialogDescription: 'Use the QR code to quickly share the subscription URL for import.',
urlConfirmation: 'URL confirmation',
tabProviders: 'Providers',
tabConfig: 'Custom Config',
tabTemplate: 'Config Template',
tabRestrictions: 'Restrictions',
tokenNeverExpires: 'Never expires',
tokenExpired: 'Expired',
tokenExpiresSoon: 'Active',
namePlaceholder: 'Enter subscription name',
createHint: 'After creation, you can configure providers, rule sets, and more in the detail page.',
copySuccess: 'Subscription URL copied',
saveSuccess: 'Subscription saved',
regenerateSuccess: 'Token regenerated',
detail: 'Subscription Detail',
noExpiry: 'No expiry',
noExpiryDescription: 'No expiration time set',
setExpiry: 'Set expiry',
subscriptionInfo: 'Subscription Info',
configSummary: 'Config Summary',
accessOverview: 'Access Overview',
activeProviderCount: '{{count}} providers enabled',
hasCustomConfig: 'Custom config linked',
hasConfigTemplate: 'Config template linked',
proxyPrefixStatus: 'Proxy prefix',
proxyPrefixOn: 'Enabled',
proxyPrefixOff: 'Disabled',
emptyTitle: 'Create a distributable subscription',
emptyDescription: 'A subscription combines providers, custom config, and template into the final YAML, then gives you a URL or QR code to import.',
noProvidersTitle: 'No providers to enable yet',
noProvidersDescription: 'Add an upstream provider first, then return here to choose which node sources participate in generation.',
noCustomConfigsTitle: 'No custom configs yet',
noCustomConfigsDescription: 'Custom configs manage proxy groups and rules. Start with the sample config, then return here to bind it.',
},
accessLogs: {
title: 'Access Logs',
ip: 'IP Address',
country: 'Country',
city: 'City',
allowed: 'Status',
denyReason: 'Deny Reason',
time: 'Time',
allowedBadge: 'Allowed',
deniedBadge: 'Denied',
noLogs: 'No access logs',
},
settings: {
title: 'Settings',
basicInfo: 'Basic Info',
changePassword: 'Change Password',
username: 'Username',
email: 'Email',
oldPassword: 'Current Password',
newPassword: 'New Password',
confirmNewPassword: 'Confirm New Password',
saveProfile: 'Save Info',
changePasswordBtn: 'Change Password',
profileUpdated: 'Profile updated',
passwordChanged: 'Password changed',
passwordMismatch: 'Passwords do not match',
oldPasswordRequired: 'Current password is required',
newPasswordRequired: 'New password is required',
},
theme: {
light: 'Light',
dark: 'Dark',
system: 'System',
toggle: 'Toggle theme',
},
language: {
zh: '中文',
en: 'English',
toggle: 'Toggle language',
},
footer: {
github: 'GitHub',
repoLinkA11y: 'Open this project on GitHub',
buildLabelTitle: 'Build version',
},
// Generic errors (used in axios interceptor and non-React contexts)
errors: {
invalidCredentials: 'Invalid email or password',
operationFailed: 'Operation failed',
unauthorized: 'Unauthorized, please log in again',
networkError: 'Network error, please try again later',
encryptFailed: 'Password encryption failed, please refresh and try again',
publicKeyFailed: 'Failed to fetch security key, please refresh and try again',
},
}
export default en