feat(a11y): screen-reader & keyboard accessibility across the panel (#5486) (#5652)

* feat(a11y): label list, toolbar & dashboard actions for screen readers

Phase 1 of #5486 (Android TalkBack support). Icon-only controls across
the management surfaces previously announced only their untranslated
icon name (e.g. "edit", "ellipsis") or nothing at all.

- Add aria-label to icon-only row-action and toolbar buttons across
  inbounds, clients, groups, hosts, nodes and xray
  (outbounds/routing/dns/balancers) lists, plus the dashboard cards.
- Make clickable bare icons and AntD Card actions keyboard-operable via
  role/tabIndex + Enter/Space (new activateOnKey helper); convert mobile
  dropdown triggers to buttons so they open from the keyboard.
- Fix the sidebar hamburger's mislabeled aria-label (was the dashboard
  label) and translate previously-hardcoded outbound menu labels.

New i18n keys in all 13 locales: sort, menu.openMenu,
pages.xray.outbound.moveToTop.

* feat(a11y): label modal, QR and copy/download controls for screen readers

Phase 2 of #5486. Modal and overlay controls relied on tooltips (not a
reliable accessible name) or were bare clickable icons with no keyboard
or screen-reader support.

- Add aria-label to copy/QR/download/info icon buttons in the inbound and
  client info modals, sub-links modal, QR panel, backup/log modals, and
  to the bare search/select inputs of the attach/detach client modals.
- Make click-to-copy QR codes and the IP-log refresh/clear, geofile
  reload and log refresh icons keyboard-operable (role/tabIndex +
  Enter/Space) with translated labels.
- Label the 2FA code input; drop the QrPanel download-image string
  fallback now that the key exists.

New i18n key in all 13 locales: downloadImage.

* feat(a11y): label form fields and shared form components for screen readers

Phase 3 of #5486. Form controls and shared form widgets were largely
unlabelled, and several remove controls were not keyboard-operable.

- SettingListItem now ties its title to the control via aria-labelledby,
  giving accessible names to the ~90 settings-tab inputs at once.
- InputAddon gains button semantics (role/tabIndex/Enter+Space) and an
  ariaLabel prop when used as an interactive remove control.
- Sparkline charts expose a role="img" summary of their latest values.
- Add aria-label to add/remove/regenerate icon buttons and bare
  inputs/selects across inbound, client and xray (dns/routing/balancer/
  outbound) forms; make clickable remove icons keyboard-operable; mark
  decorative help/target icons aria-hidden; label the JSON editor,
  date-time clear button, header-map remove, notification select-all and
  remark token chips.

New i18n keys in all 13 locales: regenerate, jsonEditor,
pages.xray.balancer.{costMatch,costValue,costRegexp}.

* chore(a11y): add eslint-plugin-jsx-a11y harness and fix flagged interactions

Phase 4 of #5486. Adds eslint-plugin-jsx-a11y (recommended ruleset,
scoped to .tsx) so screen-reader/keyboard regressions fail lint.

- Make the mobile node-card header a proper keyboard disclosure
  (role=button, aria-expanded, Enter/Space activation that ignores
  clicks on the nested action buttons) and drop the now-redundant
  stop-propagation click handlers the linter flagged on card-action
  wrappers in the node, client and inbound mobile cards.
- Disable jsx-a11y/no-autofocus: the autofocus on the login field and
  modal primary inputs is intentional focus management that helps
  screen-reader and keyboard users land on the right control.

make lint passes with the a11y ruleset enforced.

* feat(a11y): cover remaining deferred spots (settings tabs, sockopt, API docs)

Completes the panel sweep for #5486 by labelling the spots previously
left out of phases 1-4:

- NotifyTimeField (Telegram notifications): the mode, interval, unit and
  custom-cron inputs now carry aria-labels.
- The Sockopt toggle in transport options.
- Settings category tabs in icons-only (mobile) mode now expose the tab
  name as the icon's aria-label instead of the raw icon name.
- The Swagger API-docs view is wrapped in a labelled region landmark.

New i18n keys in all 13 locales: pages.settings.notifyTime.{interval,unit}.

* feat(a11y): label shared xray form components and remark field

Code review surfaced frontend/src/lib/xray/forms/ — shared form components
used by the host and inbound JSON forms — which the initial audit missed.

- FinalMaskForm (TCP/UDP final-mask editor): label the icon-only add and
  regenerate buttons and make all six remove icons keyboard-operable
  (role/tabIndex/Enter+Space); adds useTranslation to its sub-components.
- CustomSockoptList: the remove icon is now keyboard-operable.
- SniffingFields: aria-label on the otherwise label-less destOverride select.
- RemarkTemplateField: aria-label on the remark-variable picker button.

New i18n key in all 13 locales: pages.inbounds.sniffingDestOverride.

* feat(a11y): label client info modal and WireGuard config block

After rebasing onto the WireGuard client-config feature, re-apply the
ClientInfoModal copy/QR/IP-log aria-labels (the modal was restructured
upstream, so the original labels did not carry over) and label the new
ConfigBlock component's copy/download/QR actions. ConfigBlock's action
wrapper keeps its stop-propagation handler (a non-interactive guard for
the Collapse header) under a scoped jsx-a11y exception.

* fix(frontend): let npm install jsx-a11y under ESLint 10

eslint-plugin-jsx-a11y@6.10.2 declares a peer range that stops at ESLint 9,
but the panel is on ESLint 10, so `npm ci` aborts with ERESOLVE even though
the plugin runs fine on ESLint 10 with flat config. Add an npm override so
jsx-a11y accepts the project's ESLint version. This keeps normal peer
resolution (recharts' react-is peer still auto-installs) — no global
legacy-peer-deps and no manual react-is pin needed.

* fix(a11y): size mobile row triggers and move node expand role to chevron

Address automated review on #5652:
- add size="small" to the inbound/client/node mobile-card "more" dropdown
  triggers so they match the adjacent small Switch and the established
  desktop RowActions pattern.
- move the node card-head disclosure semantics (role/tabIndex/aria-expanded/
  keyboard) onto the chevron affordance so the expand control is no longer a
  role="button" wrapping the Switch, info button and dropdown. Mouse
  click-anywhere-to-expand is preserved on the header div.
This commit is contained in:
nima1024m
2026-06-29 12:51:29 +02:00
committed by GitHub
parent 6c71b725da
commit 71aca2018a
82 changed files with 2072 additions and 258 deletions
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "اتنسخ",
"more": "المزيد",
"download": "تحميل",
"regenerate": "إعادة التوليد",
"jsonEditor": "محرر JSON",
"downloadImage": "تنزيل الصورة",
"sort": "ترتيب",
"remark": "ملاحظة",
"enable": "مفعل",
"protocol": "بروتوكول",
@@ -118,7 +122,8 @@
"link": "إدارة",
"donate": "تبرع",
"hosts": "المضيفات",
"docs": "التوثيق"
"docs": "التوثيق",
"openMenu": "فتح القائمة"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "رأس الطلب",
"responseHeader": "رأس الرد"
}
}
},
"sniffingDestOverride": "تجاوز الوجهة"
},
"clients": {
"tabBasics": "أساسي",
@@ -1142,7 +1148,9 @@
"custom": "مخصص (crontab)",
"seconds": "ثوانٍ",
"minutes": "دقائق",
"hours": "ساعات"
"hours": "ساعات",
"interval": "الفاصل الزمني",
"unit": "الوحدة"
},
"tgNotifyBackup": "نسخة احتياطية لقاعدة البيانات",
"tgNotifyBackupDesc": "ابعت ملف النسخة الاحتياطية لقاعدة البيانات مع التقرير.",
@@ -1618,7 +1626,8 @@
"city": "المدينة",
"allCities": "كل المدن",
"privateKey": "المفتاح الخاص",
"load": "الحمل"
"load": "الحمل",
"moveToTop": "نقل إلى الأعلى"
},
"outboundSub": {
"manage": "الاشتراكات",
@@ -1717,7 +1726,10 @@
"tolerance": "التحمل",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "ماينفعش تستخدم balancerTag و outboundTag مع بعض. لو اتستخدموا مع بعض، outboundTag هو اللي هيشتغل."
"balancerDesc": "ماينفعش تستخدم balancerTag و outboundTag مع بعض. لو اتستخدموا مع بعض، outboundTag هو اللي هيشتغل.",
"costMatch": "نمط الوسم",
"costValue": "الوزن",
"costRegexp": "مطابقة تعبير نمطي"
},
"wireguard": {
"secretKey": "المفتاح السري",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Copied",
"more": "more",
"download": "Download",
"regenerate": "Regenerate",
"jsonEditor": "JSON editor",
"downloadImage": "Download Image",
"sort": "Sort",
"remark": "Remark",
"enable": "Enabled",
"protocol": "Protocol",
@@ -118,7 +122,8 @@
"logout": "Log Out",
"link": "Manage",
"donate": "Donate",
"docs": "Documentation"
"docs": "Documentation",
"openMenu": "Open menu"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Request Header",
"responseHeader": "Response Header"
}
}
},
"sniffingDestOverride": "Destination override"
},
"clients": {
"tabBasics": "Basics",
@@ -1260,7 +1266,9 @@
"custom": "Custom (crontab)",
"seconds": "Seconds",
"minutes": "Minutes",
"hours": "Hours"
"hours": "Hours",
"interval": "Interval",
"unit": "Unit"
},
"tgNotifyBackup": "Database Backup",
"tgNotifyBackupDesc": "Send a database backup file with a report.",
@@ -1734,7 +1742,8 @@
"city": "City",
"allCities": "All Cities",
"privateKey": "Private Key",
"load": "Load"
"load": "Load",
"moveToTop": "Move to top"
},
"outboundSub": {
"manage": "Subscriptions",
@@ -1833,7 +1842,10 @@
"tolerance": "Tolerance",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "It is not possible to use balancerTag and outboundTag at the same time. If used at the same time, only outboundTag will work."
"balancerDesc": "It is not possible to use balancerTag and outboundTag at the same time. If used at the same time, only outboundTag will work.",
"costMatch": "Tag pattern",
"costValue": "Weight",
"costRegexp": "Regular expression match"
},
"wireguard": {
"secretKey": "Secret Key",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Copiado",
"more": "más",
"download": "Descargar",
"regenerate": "Regenerar",
"jsonEditor": "Editor JSON",
"downloadImage": "Descargar imagen",
"sort": "Ordenar",
"remark": "Notas",
"enable": "Habilitar",
"protocol": "Protocolo",
@@ -118,7 +122,8 @@
"link": "Gestionar",
"donate": "Donar",
"hosts": "Hosts",
"docs": "Documentación"
"docs": "Documentación",
"openMenu": "Abrir menú"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Encabezado de solicitud",
"responseHeader": "Encabezado de respuesta"
}
}
},
"sniffingDestOverride": "Anulación de destino"
},
"clients": {
"tabBasics": "Básico",
@@ -1142,7 +1148,9 @@
"custom": "Personalizado (crontab)",
"seconds": "Segundos",
"minutes": "Minutos",
"hours": "Horas"
"hours": "Horas",
"interval": "Intervalo",
"unit": "Unidad"
},
"tgNotifyBackup": "Respaldo de Base de Datos",
"tgNotifyBackupDesc": "Incluir archivo de respaldo de base de datos con notificación de informe.",
@@ -1618,7 +1626,8 @@
"city": "Ciudad",
"allCities": "Todas las ciudades",
"privateKey": "Clave privada",
"load": "Carga"
"load": "Carga",
"moveToTop": "Mover al principio"
},
"outboundSub": {
"manage": "Suscripciones",
@@ -1717,7 +1726,10 @@
"tolerance": "Tolerancia",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "No es posible utilizar balancerTag y outboundTag al mismo tiempo. Si se utilizan al mismo tiempo, sólo funcionará outboundTag."
"balancerDesc": "No es posible utilizar balancerTag y outboundTag al mismo tiempo. Si se utilizan al mismo tiempo, sólo funcionará outboundTag.",
"costMatch": "Patrón de etiqueta",
"costValue": "Peso",
"costRegexp": "Coincidencia por expresión regular"
},
"wireguard": {
"secretKey": "Llave secreta",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "کپی شد",
"more": "بیشتر",
"download": "دانلود",
"regenerate": "تولید مجدد",
"jsonEditor": "ویرایشگر JSON",
"downloadImage": "دانلود تصویر",
"sort": "مرتب‌سازی",
"remark": "نام",
"enable": "فعال",
"protocol": "پروتکل",
@@ -118,7 +122,8 @@
"link": "مدیریت",
"donate": "حمایت مالی",
"hosts": "میزبان‌ها",
"docs": "مستندات"
"docs": "مستندات",
"openMenu": "باز کردن منو"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "سربرگ درخواست",
"responseHeader": "سربرگ پاسخ"
}
}
},
"sniffingDestOverride": "بازنویسی مقصد"
},
"clients": {
"tabBasics": "پایه",
@@ -1144,7 +1150,9 @@
"custom": "سفارشی (crontab)",
"seconds": "ثانیه",
"minutes": "دقیقه",
"hours": "ساعت"
"hours": "ساعت",
"interval": "بازه زمانی",
"unit": "واحد"
},
"tgNotifyBackup": "پشتیبان‌گیری از دیتابیس",
"tgNotifyBackupDesc": "فایل پشتیبان‌دیتابیس را به‌همراه گزارش ارسال می‌کند",
@@ -1618,7 +1626,8 @@
"city": "شهر",
"allCities": "همه شهرها",
"privateKey": "کلید خصوصی",
"load": "فشار سرور"
"load": "فشار سرور",
"moveToTop": "انتقال به بالا"
},
"outboundSub": {
"manage": "سابسکریپشن‌ها",
@@ -1717,7 +1726,10 @@
"tolerance": "تحمل",
"baselines": "خطوط پایه",
"costs": "هزینه‌ها",
"balancerDesc": "امکان استفاده همزمان balancerTag و outboundTag باهم وجود ندارد. درصورت استفاده همزمان فقط outboundTag عمل خواهد کرد."
"balancerDesc": "امکان استفاده همزمان balancerTag و outboundTag باهم وجود ندارد. درصورت استفاده همزمان فقط outboundTag عمل خواهد کرد.",
"costMatch": "الگوی برچسب",
"costValue": "وزن",
"costRegexp": "تطبیق با عبارت باقاعده"
},
"wireguard": {
"secretKey": "کلید شخصی",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Tersalin",
"more": "lainnya",
"download": "Unduh",
"regenerate": "Buat Ulang",
"jsonEditor": "Editor JSON",
"downloadImage": "Unduh Gambar",
"sort": "Urutkan",
"remark": "Catatan",
"enable": "Aktifkan",
"protocol": "Protokol",
@@ -118,7 +122,8 @@
"link": "Kelola",
"donate": "Donasi",
"hosts": "Host",
"docs": "Dokumentasi"
"docs": "Dokumentasi",
"openMenu": "Buka menu"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Header Permintaan",
"responseHeader": "Header Respons"
}
}
},
"sniffingDestOverride": "Penggantian tujuan"
},
"clients": {
"tabBasics": "Dasar",
@@ -1142,7 +1148,9 @@
"custom": "Kustom (crontab)",
"seconds": "Detik",
"minutes": "Menit",
"hours": "Jam"
"hours": "Jam",
"interval": "Interval",
"unit": "Satuan"
},
"tgNotifyBackup": "Cadangan Database",
"tgNotifyBackupDesc": "Kirim berkas cadangan database dengan laporan.",
@@ -1618,7 +1626,8 @@
"city": "Kota",
"allCities": "Semua Kota",
"privateKey": "Kunci Privat",
"load": "Beban"
"load": "Beban",
"moveToTop": "Pindahkan ke atas"
},
"outboundSub": {
"manage": "Langganan",
@@ -1717,7 +1726,10 @@
"tolerance": "Toleransi",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "BalancerTag dan outboundTag tidak dapat digunakan secara bersamaan. Jika digunakan secara bersamaan, hanya outboundTag yang akan berfungsi."
"balancerDesc": "BalancerTag dan outboundTag tidak dapat digunakan secara bersamaan. Jika digunakan secara bersamaan, hanya outboundTag yang akan berfungsi.",
"costMatch": "Pola tag",
"costValue": "Bobot",
"costRegexp": "Pencocokan ekspresi reguler"
},
"wireguard": {
"secretKey": "Kunci Rahasia",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "コピー済み",
"more": "もっと",
"download": "ダウンロード",
"regenerate": "再生成",
"jsonEditor": "JSON エディター",
"downloadImage": "画像をダウンロード",
"sort": "並べ替え",
"remark": "備考",
"enable": "有効化",
"protocol": "プロトコル",
@@ -118,7 +122,8 @@
"link": "リンク管理",
"donate": "寄付",
"hosts": "ホスト",
"docs": "ドキュメント"
"docs": "ドキュメント",
"openMenu": "メニューを開く"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "リクエストヘッダー",
"responseHeader": "レスポンスヘッダー"
}
}
},
"sniffingDestOverride": "宛先のオーバーライド"
},
"clients": {
"tabBasics": "基本",
@@ -1142,7 +1148,9 @@
"custom": "カスタム (crontab)",
"seconds": "秒",
"minutes": "分",
"hours": "時間"
"hours": "時間",
"interval": "間隔",
"unit": "単位"
},
"tgNotifyBackup": "データベースバックアップ",
"tgNotifyBackupDesc": "レポート付きのデータベースバックアップファイルを送信",
@@ -1618,7 +1626,8 @@
"city": "都市",
"allCities": "すべての都市",
"privateKey": "秘密鍵",
"load": "負荷"
"load": "負荷",
"moveToTop": "先頭に移動"
},
"outboundSub": {
"manage": "サブスクリプション",
@@ -1717,7 +1726,10 @@
"tolerance": "許容範囲",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "balancerTagとoutboundTagは同時に使用できません。同時に使用された場合、outboundTagのみが有効になります。"
"balancerDesc": "balancerTagとoutboundTagは同時に使用できません。同時に使用された場合、outboundTagのみが有効になります。",
"costMatch": "タグパターン",
"costValue": "重み",
"costRegexp": "正規表現で一致"
},
"wireguard": {
"secretKey": "シークレットキー",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Copiado",
"more": "mais",
"download": "Baixar",
"regenerate": "Regenerar",
"jsonEditor": "Editor JSON",
"downloadImage": "Baixar imagem",
"sort": "Ordenar",
"remark": "Observação",
"enable": "Ativado",
"protocol": "Protocolo",
@@ -118,7 +122,8 @@
"link": "Gerenciar",
"donate": "Doar",
"hosts": "Hosts",
"docs": "Documentação"
"docs": "Documentação",
"openMenu": "Abrir menu"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Cabeçalho da Requisição",
"responseHeader": "Cabeçalho da Resposta"
}
}
},
"sniffingDestOverride": "Substituição de destino"
},
"clients": {
"tabBasics": "Básico",
@@ -1142,7 +1148,9 @@
"custom": "Personalizado (crontab)",
"seconds": "Segundos",
"minutes": "Minutos",
"hours": "Horas"
"hours": "Horas",
"interval": "Intervalo",
"unit": "Unidade"
},
"tgNotifyBackup": "Backup do Banco de Dados",
"tgNotifyBackupDesc": "Enviar arquivo de backup do banco de dados junto com o relatório.",
@@ -1618,7 +1626,8 @@
"city": "Cidade",
"allCities": "Todas as Cidades",
"privateKey": "Chave Privada",
"load": "Carga"
"load": "Carga",
"moveToTop": "Mover para o topo"
},
"outboundSub": {
"manage": "Assinaturas",
@@ -1717,7 +1726,10 @@
"tolerance": "Tolerância",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "Não é possível usar balancerTag e outboundTag ao mesmo tempo. Se usados simultaneamente, apenas outboundTag funcionará."
"balancerDesc": "Não é possível usar balancerTag e outboundTag ao mesmo tempo. Se usados simultaneamente, apenas outboundTag funcionará.",
"costMatch": "Padrão de tag",
"costValue": "Peso",
"costRegexp": "Correspondência por expressão regular"
},
"wireguard": {
"secretKey": "Chave Secreta",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Скопировано",
"more": "ещё",
"download": "Скачать",
"regenerate": "Сгенерировать заново",
"jsonEditor": "Редактор JSON",
"downloadImage": "Скачать изображение",
"sort": "Сортировка",
"remark": "Примечание",
"enable": "Включить",
"protocol": "Протокол",
@@ -118,7 +122,8 @@
"link": "Управление",
"donate": "Поддержать",
"hosts": "Хосты",
"docs": "Документация"
"docs": "Документация",
"openMenu": "Открыть меню"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Заголовок запроса",
"responseHeader": "Заголовок ответа"
}
}
},
"sniffingDestOverride": "Переопределение назначения"
},
"clients": {
"tabBasics": "Основные",
@@ -1142,7 +1148,9 @@
"custom": "Произвольный (crontab)",
"seconds": "Секунды",
"minutes": "Минуты",
"hours": "Часы"
"hours": "Часы",
"interval": "Интервал",
"unit": "Единица"
},
"tgNotifyBackup": "Резервное копирование базы данных",
"tgNotifyBackupDesc": "Отправлять уведомление с файлом резервной копии базы данных",
@@ -1618,7 +1626,8 @@
"city": "Город",
"allCities": "Все города",
"privateKey": "Приватный ключ",
"load": "Нагрузка"
"load": "Нагрузка",
"moveToTop": "Переместить наверх"
},
"outboundSub": {
"manage": "Подписки",
@@ -1717,7 +1726,10 @@
"tolerance": "Допуск",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag."
"balancerDesc": "Невозможно одновременно использовать balancerTag и outboundTag. При одновременном использовании будет работать только outboundTag.",
"costMatch": "Шаблон тега",
"costValue": "Вес",
"costRegexp": "Совпадение по регулярному выражению"
},
"wireguard": {
"secretKey": "Секретный ключ",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Kopyalandı",
"more": "Diğer",
"download": "İndir",
"regenerate": "Yeniden Oluştur",
"jsonEditor": "JSON Düzenleyici",
"downloadImage": "Resmi İndir",
"sort": "Sırala",
"remark": "Açıklama",
"enable": "Etkin",
"protocol": "Protokol",
@@ -118,7 +122,8 @@
"link": "Yönet",
"donate": "Bağış Yap",
"hosts": "Host'lar",
"docs": "Belgeler"
"docs": "Belgeler",
"openMenu": "Menüyü aç"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "İstek Başlığı",
"responseHeader": "Yanıt Başlığı"
}
}
},
"sniffingDestOverride": "Hedef geçersiz kılma"
},
"clients": {
"tabBasics": "Temel",
@@ -1142,7 +1148,9 @@
"custom": "Özel (crontab)",
"seconds": "Saniye",
"minutes": "Dakika",
"hours": "Saat"
"hours": "Saat",
"interval": "Aralık",
"unit": "Birim"
},
"tgNotifyBackup": "Veritabanı Yedeği",
"tgNotifyBackupDesc": "Bir rapor ile birlikte veritabanı yedek dosyasını gönderir.",
@@ -1618,7 +1626,8 @@
"city": "Şehir",
"allCities": "Tüm Şehirler",
"privateKey": "Özel Anahtar",
"load": "Yükle"
"load": "Yükle",
"moveToTop": "En üste taşı"
},
"outboundSub": {
"manage": "Abonelikler",
@@ -1717,7 +1726,10 @@
"tolerance": "Tolerans",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "Dengeleyici Etiketi (balancerTag) ve Giden Bağlantı Etiketi (outboundTag) aynı anda kullanılamaz. Aynı anda kullanıldığında yalnızca giden bağlantı etiketi geçerli olur."
"balancerDesc": "Dengeleyici Etiketi (balancerTag) ve Giden Bağlantı Etiketi (outboundTag) aynı anda kullanılamaz. Aynı anda kullanıldığında yalnızca giden bağlantı etiketi geçerli olur.",
"costMatch": "Etiket deseni",
"costValue": "Ağırlık",
"costRegexp": "Düzenli ifade eşleşmesi"
},
"wireguard": {
"secretKey": "Gizli Anahtar",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Скопійовано",
"more": "більше",
"download": "Завантажити",
"regenerate": "Згенерувати заново",
"jsonEditor": "Редактор JSON",
"downloadImage": "Завантажити зображення",
"sort": "Сортування",
"remark": "Примітка",
"enable": "Увімкнути",
"protocol": "Протокол",
@@ -118,7 +122,8 @@
"link": "Керувати",
"donate": "Підтримати",
"hosts": "Хости",
"docs": "Документація"
"docs": "Документація",
"openMenu": "Відкрити меню"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Заголовок запиту",
"responseHeader": "Заголовок відповіді"
}
}
},
"sniffingDestOverride": "Перевизначення призначення"
},
"clients": {
"tabBasics": "Основні",
@@ -1142,7 +1148,9 @@
"custom": "Власний (crontab)",
"seconds": "Секунди",
"minutes": "Хвилини",
"hours": "Години"
"hours": "Години",
"interval": "Інтервал",
"unit": "Одиниця"
},
"tgNotifyBackup": "Резервне копіювання бази даних",
"tgNotifyBackupDesc": "Надіслати файл резервної копії бази даних зі звітом.",
@@ -1618,7 +1626,8 @@
"city": "Місто",
"allCities": "Усі міста",
"privateKey": "Приватний ключ",
"load": "Навантаження"
"load": "Навантаження",
"moveToTop": "Перемістити вгору"
},
"outboundSub": {
"manage": "Підписки",
@@ -1717,7 +1726,10 @@
"tolerance": "Допуск",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "Неможливо використовувати balancerTag і outboundTag одночасно. Якщо використовувати одночасно, працюватиме лише outboundTag."
"balancerDesc": "Неможливо використовувати balancerTag і outboundTag одночасно. Якщо використовувати одночасно, працюватиме лише outboundTag.",
"costMatch": "Шаблон тегу",
"costValue": "Вага",
"costRegexp": "Збіг за регулярним виразом"
},
"wireguard": {
"secretKey": "Приватний ключ",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "Đã sao chép",
"more": "thêm",
"download": "Tải xuống",
"regenerate": "Tạo lại",
"jsonEditor": "Trình chỉnh sửa JSON",
"downloadImage": "Tải hình ảnh",
"sort": "Sắp xếp",
"remark": "Ghi chú",
"enable": "Kích hoạt",
"protocol": "Giao thức",
@@ -118,7 +122,8 @@
"link": "Quản lý",
"donate": "Quyên góp",
"hosts": "Hosts",
"docs": "Tài liệu"
"docs": "Tài liệu",
"openMenu": "Mở menu"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "Header yêu cầu",
"responseHeader": "Header phản hồi"
}
}
},
"sniffingDestOverride": "Ghi đè đích"
},
"clients": {
"tabBasics": "Cơ bản",
@@ -1142,7 +1148,9 @@
"custom": "Tùy chỉnh (crontab)",
"seconds": "Giây",
"minutes": "Phút",
"hours": "Giờ"
"hours": "Giờ",
"interval": "Khoảng thời gian",
"unit": "Đơn vị"
},
"tgNotifyBackup": "Sao lưu Cơ sở dữ liệu",
"tgNotifyBackupDesc": "Bao gồm tệp sao lưu cơ sở dữ liệu với thông báo báo cáo.",
@@ -1618,7 +1626,8 @@
"city": "Thành phố",
"allCities": "Tất cả thành phố",
"privateKey": "Khóa riêng",
"load": "Tải"
"load": "Tải",
"moveToTop": "Chuyển lên đầu"
},
"outboundSub": {
"manage": "Đăng ký",
@@ -1717,7 +1726,10 @@
"tolerance": "Dung sai",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "Không thể sử dụng balancerTag và outboundTag cùng một lúc. Nếu sử dụng cùng lúc thì chỉ outboundTag mới hoạt động."
"balancerDesc": "Không thể sử dụng balancerTag và outboundTag cùng một lúc. Nếu sử dụng cùng lúc thì chỉ outboundTag mới hoạt động.",
"costMatch": "Mẫu thẻ",
"costValue": "Trọng số",
"costRegexp": "Khớp biểu thức chính quy"
},
"wireguard": {
"secretKey": "Khoá bí mật",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "已复制",
"more": "更多",
"download": "下载",
"regenerate": "重新生成",
"jsonEditor": "JSON 编辑器",
"downloadImage": "下载图片",
"sort": "排序",
"remark": "备注",
"enable": "启用",
"protocol": "协议",
@@ -118,7 +122,8 @@
"link": "管理",
"donate": "捐赠",
"hosts": "主机",
"docs": "文档"
"docs": "文档",
"openMenu": "打开菜单"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "请求头",
"responseHeader": "响应头"
}
}
},
"sniffingDestOverride": "目标覆盖"
},
"clients": {
"tabBasics": "基本",
@@ -1142,7 +1148,9 @@
"custom": "自定义 (crontab)",
"seconds": "秒",
"minutes": "分钟",
"hours": "小时"
"hours": "小时",
"interval": "间隔",
"unit": "单位"
},
"tgNotifyBackup": "数据库备份",
"tgNotifyBackupDesc": "发送带有报告的数据库备份文件",
@@ -1618,7 +1626,8 @@
"city": "城市",
"allCities": "所有城市",
"privateKey": "私钥",
"load": "负载"
"load": "负载",
"moveToTop": "移到顶部"
},
"outboundSub": {
"manage": "订阅",
@@ -1717,7 +1726,10 @@
"tolerance": "容差",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "无法同时使用 balancerTag 和 outboundTag。如果同时使用,则只有 outboundTag 会生效。"
"balancerDesc": "无法同时使用 balancerTag 和 outboundTag。如果同时使用,则只有 outboundTag 会生效。",
"costMatch": "标签匹配模式",
"costValue": "权重",
"costRegexp": "正则表达式匹配"
},
"wireguard": {
"secretKey": "密钥",
+17 -5
View File
@@ -15,6 +15,10 @@
"copied": "已複製",
"more": "更多",
"download": "下載",
"regenerate": "重新產生",
"jsonEditor": "JSON 編輯器",
"downloadImage": "下載圖片",
"sort": "排序",
"remark": "備註",
"enable": "啟用",
"protocol": "協議",
@@ -118,7 +122,8 @@
"link": "管理",
"donate": "捐贈",
"hosts": "Hosts",
"docs": "文件"
"docs": "文件",
"openMenu": "開啟選單"
},
"pages": {
"login": {
@@ -712,7 +717,8 @@
"requestHeader": "請求頭",
"responseHeader": "響應頭"
}
}
},
"sniffingDestOverride": "目標覆寫"
},
"clients": {
"tabBasics": "基本",
@@ -1142,7 +1148,9 @@
"custom": "自訂 (crontab)",
"seconds": "秒",
"minutes": "分鐘",
"hours": "小時"
"hours": "小時",
"interval": "間隔",
"unit": "單位"
},
"tgNotifyBackup": "資料庫備份",
"tgNotifyBackupDesc": "傳送帶有報告的資料庫備份檔案",
@@ -1618,7 +1626,8 @@
"city": "城市",
"allCities": "所有城市",
"privateKey": "私密金鑰",
"load": "負載"
"load": "負載",
"moveToTop": "移到頂部"
},
"outboundSub": {
"manage": "訂閱",
@@ -1717,7 +1726,10 @@
"tolerance": "容差",
"baselines": "Baselines",
"costs": "Costs",
"balancerDesc": "無法同時使用 balancerTag 和 outboundTag。如果同時使用,則只有 outboundTag 會生效。"
"balancerDesc": "無法同時使用 balancerTag 和 outboundTag。如果同時使用,則只有 outboundTag 會生效。",
"costMatch": "標籤比對模式",
"costValue": "權重",
"costRegexp": "正規表示式比對"
},
"wireguard": {
"secretKey": "金鑰",