From b491d78a8a26a9a1b6955e36d5bfab5b56f820ec Mon Sep 17 00:00:00 2001 From: "Maksym Hryzodub [DREAM]" Date: Wed, 19 Aug 2026 17:20:02 +0300 Subject: [PATCH] feat(app): extract the chat slice into i18n, en+ru (CLEAN-39) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The history list, session detail, card and transcript bubble had no i18n block at all. Adds one and moves every string out — including the ones the scan could not see: the Sync/Syncing toggle, Show/Hide on a summary marker, the 👍/👎 aria-labels, and the "Conversation" title fallback. Two plural sets ("{count} message(s)", the free-slot counter's sibling) go through the plural rules added in CLEAN-38, so ru gets its four branches: нет сообщений | {count} сообщение | {count} сообщения | {count} сообщений. relative_time.* moves from the agent slice to common rather than being duplicated: both slices render "5m ago" and the copy is generic. Key paths are unchanged — vue-i18n merges slices into one global scope — so the agent components needed no edit, and the sync script adopted the already-translated keys into their new home instead of re-translating. Timestamps now format against the active locale: fmt() reads `locale` from useI18n, which is the one thing that composable is still for here — the locale itself, never copy. Verified: nuxt typecheck and nuxt build clean, i18n:check green over 6 slice/locale pairs, re-scan finds nothing hardcoded left in the slice. Remaining across app: template (4 strings, CLEAN-40). Co-Authored-By: Claude Opus 5 (1M context) --- app/i18n.sync.json | 35 +++++++++++++-- app/slices/agent/i18n/locales/en.json | 6 --- app/slices/agent/i18n/locales/ru.json | 6 --- .../chat/components/chat/detail/Provider.vue | 44 +++++++++++++------ app/slices/chat/components/chat/list/Card.vue | 29 +++++++----- .../chat/components/chat/list/Provider.vue | 12 ++--- .../chat/components/chat/message/Bubble.vue | 10 +++-- app/slices/chat/i18n/locales/en.json | 33 ++++++++++++++ app/slices/chat/i18n/locales/ru.json | 33 ++++++++++++++ app/slices/chat/nuxt.config.ts | 7 +++ app/slices/common/i18n/locales/en.json | 6 +++ app/slices/common/i18n/locales/ru.json | 6 +++ 12 files changed, 177 insertions(+), 50 deletions(-) create mode 100644 app/slices/chat/i18n/locales/en.json create mode 100644 app/slices/chat/i18n/locales/ru.json diff --git a/app/i18n.sync.json b/app/i18n.sync.json index 5a37c5ac..53fe6813 100644 --- a/app/i18n.sync.json +++ b/app/i18n.sync.json @@ -29,10 +29,6 @@ "list.running_of": "dafe09b6ae07", "list.slots_free": "aa856cbf3070", "list.title": "279b44d2ab4b", - "relative_time.days": "a41234397f3c", - "relative_time.hours": "520c737ea624", - "relative_time.just_now": "7ddb44d8a533", - "relative_time.minutes": "0a03167c208c", "restart_stage.almost_body": "cc88c514c77b", "restart_stage.almost_title": "0ceb8f97a4cc", "restart_stage.deploying_body": "4cc2d4111a84", @@ -59,6 +55,33 @@ "chat.starter_hint": "76085886cbdf", "chat.you": "08b041935798" }, + "chat:ru": { + "history.empty_cta": "9c6a7d961b50", + "history.empty_hint": "3f95b708f4a5", + "history.empty_title": "0d60084f056e", + "history.lede": "7865d148c397", + "history.sync": "8d261a372fde", + "history.syncing": "8a046cc90ab0", + "history.title": "0e7696009337", + "message.helpful": "63c432db3ebb", + "message.hide": "ac20a57bfde0", + "message.not_helpful": "3c4ebf31165b", + "message.show": "0df6f1cad36c", + "message.summarized": "4ad03ef5cd63", + "session.export": "3664895579f0", + "session.fallback_title": "ccca18175753", + "session.insights_title": "97bd413b2e35", + "session.last_activity": "133983b2edcf", + "session.load_older": "2fd15b734915", + "session.loading": "ba3bbbe10d8b", + "session.message_count": "ff43d682a3fb", + "session.no_messages": "1e56e882e6e4", + "session.no_summary": "f098ecd68006", + "session.not_found_hint": "ca81b79f7f6d", + "session.not_found_title": "d8e4dcef4f3d", + "session.resolved": "dc676b428599", + "session.unresolved": "27a888c9d5e6" + }, "common:ru": { "app_name": "d64517995073", "auth.sign_in": "bfd402b2f6f3", @@ -105,6 +128,10 @@ "nav.agents": "279b44d2ab4b", "nav.history": "0e7696009337", "nav.templates": "56b564b75c7f", + "relative_time.days": "a41234397f3c", + "relative_time.hours": "520c737ea624", + "relative_time.just_now": "7ddb44d8a533", + "relative_time.minutes": "0a03167c208c", "steps.chat_body": "8f80dfeff166", "steps.chat_title": "e5e09a778387", "steps.deploy_body": "e358d64527e3", diff --git a/app/slices/agent/i18n/locales/en.json b/app/slices/agent/i18n/locales/en.json index b8e3bb31..ed00b5c9 100644 --- a/app/slices/agent/i18n/locales/en.json +++ b/app/slices/agent/i18n/locales/en.json @@ -50,11 +50,5 @@ "starting_body": "The container is pulling and initialising.", "almost_title": "Almost ready…", "almost_body": "Waiting for the agent to come online." - }, - "relative_time": { - "just_now": "just now", - "minutes": "{count}m ago", - "hours": "{count}h ago", - "days": "{count}d ago" } } diff --git a/app/slices/agent/i18n/locales/ru.json b/app/slices/agent/i18n/locales/ru.json index 079bf59d..e58b1c13 100644 --- a/app/slices/agent/i18n/locales/ru.json +++ b/app/slices/agent/i18n/locales/ru.json @@ -50,11 +50,5 @@ "starting_body": "Контейнер загружается и инициализируется.", "almost_title": "Почти готово…", "almost_body": "Ожидание выхода агента в сеть." - }, - "relative_time": { - "just_now": "только что", - "minutes": "{count} мин назад", - "hours": "{count} ч назад", - "days": "{count} дн назад" } } diff --git a/app/slices/chat/components/chat/detail/Provider.vue b/app/slices/chat/components/chat/detail/Provider.vue index ab8d2117..6782d20f 100644 --- a/app/slices/chat/components/chat/detail/Provider.vue +++ b/app/slices/chat/components/chat/detail/Provider.vue @@ -82,9 +82,11 @@ onMounted(() => { } }); -const heading = computed(() => session.value?.title?.trim() || 'Conversation'); +const { locale } = useI18n(); + +const heading = computed(() => session.value?.title?.trim() || null); function fmt(iso?: string | null): string { - return iso ? new Date(iso).toLocaleString() : '—'; + return iso ? new Date(iso).toLocaleString(locale.value) : '—'; } const sentimentVariant: Record = { @@ -101,7 +103,7 @@ const sentimentVariant: Record - History + {{ $t('history.title') }} @@ -109,28 +111,42 @@ const sentimentVariant: Record -

Conversation not found

+

{{ $t('session.not_found_title') }}

- It may have been removed, or it isn't one of yours. + {{ $t('session.not_found_hint') }}