From 5c9268c4317c37426f87fe62dd80a79551ce5d87 Mon Sep 17 00:00:00 2001 From: n0ctal <4c866w5fn9@privaterelay.appleid.com> Date: Tue, 18 Aug 2026 14:43:59 +0500 Subject: [PATCH] feat(i18n): translate the log levels, access events and calendar labels (#6226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(i18n): translate the log levels, access events and calendar labels The log-level selector, the access-log event tags, the Sub Formats sidebar entry and the calendar choices were hardcoded English, so a fully translated locale still showed them in English on core screens. Add eleven keys across the 13 locales and reference them. Russian and Ukrainian are translated; the remaining locales carry the English string, the same convention the existing files already use for untranslated entries. Two module-level constants had to move: the calendar list and the access-event map were built outside the component, where t is not in scope. The event map now stores keys and resolves them at render. * fix(i18n): keep the log export language-independent and fit the translations Three follow-ups from review. The downloaded x-ui.log had started carrying the translated event text, so its contents depended on the panel language and the Russian value for PROXY contains a space in a field format whose other values are single tokens. The export keeps DIRECT/BLOCKED/PROXY; only the on-screen tag is translated. The log-level select had a fixed 95px width sized for "Warning", which clips "Предупреждение"; it now grows with its content. The three access filters stayed English while the tags they filter became translated, so they use the same keys. --------- Co-authored-by: n0ctal --- frontend/public/mockServiceWorker.js | 30 +++++++++++++++------- frontend/src/layouts/AppSidebar.tsx | 2 +- frontend/src/pages/index/IndexPage.tsx | 2 +- frontend/src/pages/index/LogModal.tsx | 12 ++++----- frontend/src/pages/index/XrayLogModal.tsx | 24 +++++++++++++---- frontend/src/pages/settings/GeneralTab.tsx | 9 +++---- internal/web/translation/ar-EG.json | 17 +++++++++--- internal/web/translation/en-US.json | 17 +++++++++--- internal/web/translation/es-ES.json | 17 +++++++++--- internal/web/translation/fa-IR.json | 17 +++++++++--- internal/web/translation/id-ID.json | 17 +++++++++--- internal/web/translation/ja-JP.json | 17 +++++++++--- internal/web/translation/pt-BR.json | 17 +++++++++--- internal/web/translation/ru-RU.json | 17 +++++++++--- internal/web/translation/tr-TR.json | 17 +++++++++--- internal/web/translation/uk-UA.json | 17 +++++++++--- internal/web/translation/vi-VN.json | 17 +++++++++--- internal/web/translation/zh-CN.json | 17 +++++++++--- internal/web/translation/zh-TW.json | 17 +++++++++--- 19 files changed, 234 insertions(+), 66 deletions(-) diff --git a/frontend/public/mockServiceWorker.js b/frontend/public/mockServiceWorker.js index dc58f3d9e..0c970efc9 100644 --- a/frontend/public/mockServiceWorker.js +++ b/frontend/public/mockServiceWorker.js @@ -7,8 +7,8 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.14.7' -const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' +const PACKAGE_VERSION = '2.15.0' +const INTEGRITY_CHECKSUM = '03cb67ac84128e63d7cd722a6e5b7f1e' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -137,8 +137,18 @@ async function handleRequest(event, requestId, requestInterceptedAt) { if (client && activeClientIds.has(client.id)) { const serializedRequest = await serializeRequest(requestCloneForEvents) + // Omit the body of server-sent event stream responses. + // Cloning such responses would prevent client-side stream cancelations + // from reaching the original stream (a teed stream only cancels its + // source once both of its branches cancel) and would buffer the + // entire stream into the unconsumed clone indefinitely. + const isEventStreamResponse = response.headers + .get('content-type') + ?.toLowerCase() + .startsWith('text/event-stream') + // Clone the response so both the client and the library could consume it. - const responseClone = response.clone() + const responseClone = isEventStreamResponse ? null : response.clone() sendToClient( client, @@ -151,15 +161,17 @@ async function handleRequest(event, requestId, requestInterceptedAt) { ...serializedRequest, }, response: { - type: responseClone.type, - status: responseClone.status, - statusText: responseClone.statusText, - headers: Object.fromEntries(responseClone.headers.entries()), - body: responseClone.body, + type: response.type, + status: response.status, + statusText: response.statusText, + headers: Object.fromEntries(response.headers.entries()), + body: responseClone ? responseClone.body : null, }, }, }, - responseClone.body ? [serializedRequest.body, responseClone.body] : [], + responseClone && responseClone.body + ? [serializedRequest.body, responseClone.body] + : [], ) } diff --git a/frontend/src/layouts/AppSidebar.tsx b/frontend/src/layouts/AppSidebar.tsx index c464fc329..647d67db5 100644 --- a/frontend/src/layouts/AppSidebar.tsx +++ b/frontend/src/layouts/AppSidebar.tsx @@ -219,7 +219,7 @@ export default function AppSidebar() { { key: '/settings#subscription', icon: , label: t('pages.settings.subSettings') }, ]; if (showSubFormats) { - children.push({ key: '/settings#subscription-formats', icon: , label: 'Sub Formats' }); + children.push({ key: '/settings#subscription-formats', icon: , label: t('menu.subFormats') }); } return children; }, [t, showSubFormats]); diff --git a/frontend/src/pages/index/IndexPage.tsx b/frontend/src/pages/index/IndexPage.tsx index 87441e91f..75acbd05d 100644 --- a/frontend/src/pages/index/IndexPage.tsx +++ b/frontend/src/pages/index/IndexPage.tsx @@ -127,7 +127,7 @@ export default function IndexPage() { async function copyConfig() { const ok = await ClipboardManager.copyText(configText || ''); - if (ok) messageApi.success('Copied'); + if (ok) messageApi.success(t('copied')); } function downloadConfig() { diff --git a/frontend/src/pages/index/LogModal.tsx b/frontend/src/pages/index/LogModal.tsx index eccf2b3d3..bbceab2bb 100644 --- a/frontend/src/pages/index/LogModal.tsx +++ b/frontend/src/pages/index/LogModal.tsx @@ -105,14 +105,14 @@ export default function LogModal({ open, onClose }: LogModalProps) {