From 1aeb4db9f266f8c2131f5e3a44e2f606c36b0988 Mon Sep 17 00:00:00 2001 From: "Maksym Hryzodub [DREAM]" Date: Wed, 19 Aug 2026 17:13:54 +0300 Subject: [PATCH] feat(app): extract the agent slice into i18n, en+ru (CLEAN-38) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moves all copy out of the agent list, card, detail item and chat screen — 28 strings the scan found plus the ones it could not see: status labels and relative timestamps built in script. Keys, not text, wherever script decides the wording: status meta returns `status.running` (with the raw value kept for a status the runtime invented and we have no wording for), the restart overlay returns titleKey/bodyKey per stage, and the relative timestamp returns a bucket plus its number so "5m ago" can be reordered by the translation. agentChat drops its hardcoded 'Restart failed' the same way the auth providers did — a failure flag plus the server's own message. Two infrastructure bits this slice forced: - Russian plural rules in the i18n config. The free-slots counter is a real plural, and Russian needs three forms where English has two, so vue-i18n's default rule would pick the wrong branch for most numbers. The translator prompt now states the branch order, and ru came back with the correct four ("нет свободных слотов | {count} слот свободен | {count} слота свободно | {count} слотов свободно"). - Narrowed yesterday's message guard. It rejected a bare `|` as well as `@`, but `|` *is* the plural separator — a legitimate feature, not a mistake. It now flags only `@` outside the `@:key` linked form. Verified: nuxt typecheck and nuxt build clean, ru strings in the client chunks, i18n:check green over 5 slice/locale pairs, and a re-scan finds nothing hardcoded left in the slice. Co-Authored-By: Claude Opus 5 (1M context) --- .cursor/rules/project.mdc | 7 +- CLAUDE.md | 2 +- app/i18n.sync.json | 50 +++++++++++++-- app/slices/agent/components/agent/Item.vue | 13 +++- .../agent/components/agent/Provider.vue | 4 +- .../agent/components/agentChat/Provider.vue | 62 +++++++++--------- .../agent/components/agentList/Card.vue | 41 ++++++++---- .../agent/components/agentList/Provider.vue | 43 ++++++++----- app/slices/agent/i18n/locales/en.json | 64 +++++++++++++++++-- app/slices/agent/i18n/locales/ru.json | 64 +++++++++++++++++-- app/slices/agent/pages/agents/create.vue | 2 +- app/slices/setup/i18n/i18n/i18n.config.ts | 15 +++++ scripts/i18n-sync.ts | 22 ++++--- 13 files changed, 297 insertions(+), 92 deletions(-) diff --git a/.cursor/rules/project.mdc b/.cursor/rules/project.mdc index 781ae2b4..6c532044 100644 --- a/.cursor/rules/project.mdc +++ b/.cursor/rules/project.mdc @@ -33,9 +33,10 @@ API keys live in **`.env.project`** (gitignored). Typical keys: `JIRA_API_TOKEN` If the user describes work and does **not** give a `CLEAN-` id, that description *is* the ticket. Do not start code, SpecKit, Brainstorm, or a git branch first. 1. Create a Jira issue in CLEAN from their description (title + short summary). Use `.env.project`. -2. Reply with the issue key and URL. -3. Move it to In Progress. -4. Then the usual flow: branch → work → comments → PR. +2. Mark surface: title prefix `[ADMIN]` / `[APP]` / `[ADMIN][APP]`, plus Jira labels `admin` / `app`. Infer from `admin/` vs `app/`; if unclear, ask. API-only → `[API]`. +3. Reply with the issue key and URL. +4. Move it to In Progress. +5. Then the usual flow: branch → work → comments → PR. ## OpenAPI diff --git a/CLAUDE.md b/CLAUDE.md index 406524b9..645b49d3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,7 @@ At the start of every task, read `.cursor/rules/project.mdc` (project card) and - Git identity: folder `E:/code/dream/` → Maksym Hryzodub [DREAM] / `github-dream` - Keys: `JIRA_API_TOKEN`, `JIRA_DOMAIN`, `JIRA_EMAIL`, `GITHUB_TOKEN`, and any other tokens in `.env.project` only -**No `CLEAN-` in the request:** the user's description *is* the ticket. Create the Jira issue first (keys in `.env.project`), send back the key/URL, move to In Progress — then branch/code. Do not start SpecKit or implementation without that id. +**No `CLEAN-` in the request:** the user's description *is* the ticket. Create the Jira issue first (keys in `.env.project`), mark `[ADMIN]` / `[APP]` in the title and labels, send back the key/URL, move to In Progress — then branch/code. Do not start SpecKit or implementation without that id. **OpenAPI:** if SDK/types or `api/swagger-spec.json` are missing, regenerate first (`cd api && bun run generate:swagger` or `bun run build`, then `cd admin && bun run build:api` / `cd app && bun run build:api`). Ask where the schema is only after that fails. diff --git a/app/i18n.sync.json b/app/i18n.sync.json index 50e804a0..5a37c5ac 100644 --- a/app/i18n.sync.json +++ b/app/i18n.sync.json @@ -2,12 +2,50 @@ "version": 1, "hashes": { "agent:ru": { - "agent_name": "28145084c725", - "agent_resources": "e89b30aa1dc3", - "agent_status": "920e413c7d41", - "agent_template": "0575f29df888", - "agents": "279b44d2ab4b", - "create_agent": "5a614e73e098" + "card.open_chat": "0600175af842", + "card.updated": "f0a6d28abcbc", + "chat.back_to_agents": "7da2164b2679", + "chat.elapsed": "e7a16571c3e4", + "chat.loading": "ba3bbbe10d8b", + "chat.not_found": "a50ba166a23a", + "chat.restart": "6b983a81e5e8", + "chat.restart_failed": "b8864cf013b4", + "chat.restarting": "75d0f1469d16", + "chat.unavailable_hint": "b14ea709f7e0", + "chat.unavailable_title": "d6bf283bee98", + "item.load_error": "af04f385814b", + "item.loading": "7e1e624a3210", + "item.resources": "e89b30aa1dc3", + "item.resources_value": "d4c134c14b82", + "item.template": "0575f29df888", + "list.cluster_full": "129b2952a7dd", + "list.cluster_no_nodes": "4b5656d4657f", + "list.create": "5a614e73e098", + "list.empty_cta": "88dcddea044f", + "list.empty_hint": "3b00ddd1d6b2", + "list.empty_no_permission": "11c1123faf1d", + "list.empty_title": "971b61f8cb4d", + "list.lede": "1a2a5c6eb9e9", + "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", + "restart_stage.deploying_title": "dfdc8e60ff35", + "restart_stage.starting_body": "f048e1dcc8ca", + "restart_stage.starting_title": "a1661573d16c", + "restart_stage.stopping_body": "4d3eb76d014c", + "restart_stage.stopping_title": "93f2bb08afc2", + "status.deploying": "4338bdb0808b", + "status.failed": "031a8f0f659d", + "status.pending": "331551b0de41", + "status.running": "f4ccae29e1bb", + "status.stopped": "1a4f630ac1b6" }, "bridle:ru": { "chat.agent": "11b39c93777e", diff --git a/app/slices/agent/components/agent/Item.vue b/app/slices/agent/components/agent/Item.vue index 34292e40..401ae09c 100644 --- a/app/slices/agent/components/agent/Item.vue +++ b/app/slices/agent/components/agent/Item.vue @@ -11,12 +11,19 @@
-

Template

+

{{ $t('item.template') }}

{{ agent.templateId }}

-

Resources

-

CPU: {{ agent.resources.cpu }} / Memory: {{ agent.resources.memory }}

+

{{ $t('item.resources') }}

+

+ {{ + $t('item.resources_value', { + cpu: agent.resources.cpu, + memory: agent.resources.memory, + }) + }} +

diff --git a/app/slices/agent/components/agent/Provider.vue b/app/slices/agent/components/agent/Provider.vue index 6abac03d..771bb236 100644 --- a/app/slices/agent/components/agent/Provider.vue +++ b/app/slices/agent/components/agent/Provider.vue @@ -1,6 +1,6 @@