Skip to content

feat(i18n): add English and Chinese localization - #44

Merged
LRainner merged 2 commits into
masterfrom
codex/add-i18n-support
Aug 7, 2026
Merged

feat(i18n): add English and Chinese localization#44
LRainner merged 2 commits into
masterfrom
codex/add-i18n-support

Conversation

@LRainner

@LRainner LRainner commented Aug 6, 2026

Copy link
Copy Markdown
Owner

背景

Agent Cat 目前的用户界面文案主要直接写在 HTML、TypeScript 和 Rust 原生菜单中,无法根据用户语言切换。这个 PR 引入一套轻量的 i18n 基础设施,首期支持英文和简体中文,并保持现有配置和多窗口行为兼容。

主要改动

  • 在 src/i18n 小模块中新增单一 messages.json 文案源,使用英文语句作为 Key,每条记录包含 en 和 cn 两种文案。
  • 新增类型安全的 t() 翻译函数、命名参数插值、系统语言解析、缺省回退和静态 DOM 文案/属性翻译。
  • 在 AppConfig 中增加 system / en / cn 语言偏好;旧配置通过 serde 默认值自动使用 system,无需升级配置版本。
  • 在“通用”页面底部增加独立的语言设置卡片,保持原有四个显示滑杆连续排列,并为下拉框补充与现有界面一致的样式。
  • “简体中文”和“English”在下拉框中始终使用各自固定名称;只有“跟随系统”随当前界面语言变化。
  • 迁移设置页、状态气泡、宠物窗口、动画测试器、更新流程和 Hook 连接状态等用户可见文案。
  • 语言变更会同步更新设置窗口、状态窗口、动画测试器标题以及 Rust 托盘菜单。
  • 状态气泡在切换语言时会重新生成现有会话的状态文案,同时保留计时器、折叠状态和会话顺序。
  • 平台返回的宠物目录示例路径和真实路径不会参与静态翻译;切换语言后仍保持 Windows/macOS 对应的原生路径。

校验与兼容性

  • i18n 单元测试检查每条文案都包含非空的 en 和 cn,并覆盖系统语言解析和参数插值。
  • Rust 测试直接读取原始 messages.json,通过 serde Map Visitor 检查顶层翻译 Key 是否重复,避免 JSON 解析时静默覆盖。
  • 增加 E2E 回归测试,覆盖中英文实时切换、固定语言名称和平台路径保持。
  • 测试环境和 README 截图配置显式使用中文,避免 CI 系统语言影响既有断言与截图。

验证

  • npm test:76 passed
  • npm run test:e2e:12 passed
  • cargo test:66 passed
  • npm run build:通过
  • git diff --check:通过

Summary by CodeRabbit

  • 新功能

    • 新增“跟随系统”、简体中文和 English 三种语言选项。
    • 设置、状态、调试页面及托盘菜单支持中英文切换。
    • 页面标题、提示文本、无障碍标签和错误消息支持本地化。
    • 切换语言后,界面内容、原生窗口标题及更新信息会同步更新。
    • 优化软件更新状态展示,切换语言后仍可继续查看和安装更新。
  • 测试

    • 新增语言切换、翻译完整性及页面显示行为测试。

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

新增系统语言、English 和简体中文支持。前端页面、实时状态、设置流程、调试页面及 Tauri 托盘和窗口标题均接入运行时国际化。更新界面改为状态模型驱动。

Changes

运行时国际化

Layer / File(s) Summary
语言配置与翻译基础
src-tauri/src/config.rs, src/types.ts, src/i18n/*, tsconfig.json
新增语言偏好配置、双语消息表、翻译函数、文档属性翻译和原生消息生成。
原生界面消息同步
src-tauri/src/lib.rs
新增 sync_native_i18n 命令,更新托盘菜单及设置、状态、调试窗口标题。
前端页面与状态本地化
src/settings.*, src/status.*, src/live-status.ts, src/pet-debug.*, src/main.ts, src/styles.css
将页面文本、无障碍文本、更新流程、连接状态和事件提示改为可翻译消息。语言变化后刷新文档、目录和状态。
集成配置与端到端验证
e2e/*.ts
为 E2E 配置设置简体中文,并验证英文与简体中文切换、目录路径显示及更新状态保留。

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AppConfig
  participant SettingsPage
  participant I18n
  participant LiveStatusController
  participant sync_native_i18n
  participant Tauri
  AppConfig->>SettingsPage: 提供 language 配置
  SettingsPage->>I18n: 调用 setLanguage()
  I18n->>SettingsPage: 翻译页面和更新状态
  SettingsPage->>LiveStatusController: 调用 refreshLanguage()
  SettingsPage->>sync_native_i18n: 发送 nativeMessages()
  sync_native_i18n->>Tauri: 更新托盘菜单和窗口标题
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次变更的主要内容,即新增英文和简体中文国际化支持。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/i18n/index.ts`:
- Around line 5-6: 更新 MessageParameters 及 t 的类型定义,使其根据 MessageKey
对应消息中的占位符名称推导必需参数,并拒绝缺少参数或错误参数名;不含占位符的消息应允许无参数调用。对 data-i18n
等动态键,仅允许无占位符键,或提供独立的动态翻译 API;补充覆盖缺少参数和错误参数名的 `@ts-expect-error` 编译期测试。

In `@src/i18n/messages.json`:
- Line 95: Update the Simplified Chinese value for the “No events received since
launch” message in the messages localization object from the incomplete text to
“本次启动后尚未收到事件”, leaving the English translation unchanged.

In `@src/pet-debug.ts`:
- Around line 22-26: 在 src/pet-debug.ts 的 initialize 函数中补充
agent-cat-config-changed 配置变更监听;当收到语言配置变化时,重新调用 setLanguage() 并执行
translateDocument(),保持初始化时的现有语言设置与原生消息同步逻辑不变。

In `@src/settings.ts`:
- Around line 199-204: Update applyLanguage so that after translateDocument(),
it restores `#current-version` from the actual current-version value and
re-renders the update card using its existing state. Preserve all download,
installation, and error statuses while refreshing only the localized runtime
text.
- Around line 331-338: 在更新完成处理逻辑中,使用翻译函数 t 将 installButton 的文本设置为 t("Install and
Restart"),并确保该消息键已加入语言消息定义;将此赋值放在 installButton.hidden = false 之前,以便按钮显示时使用当前语言。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca7b9062-3650-4a22-8af3-a2f6d0fc6058

📥 Commits

Reviewing files that changed from the base of the PR and between 5c91d5e and c286b71.

📒 Files selected for processing (19)
  • e2e/readme-screenshots.screenshot.ts
  • e2e/settings.e2e.ts
  • e2e/status.e2e.ts
  • src-tauri/src/config.rs
  • src-tauri/src/lib.rs
  • src/i18n/index.test.ts
  • src/i18n/index.ts
  • src/i18n/messages.json
  • src/live-status.ts
  • src/main.ts
  • src/pet-debug.html
  • src/pet-debug.ts
  • src/settings.html
  • src/settings.ts
  • src/status.html
  • src/status.ts
  • src/styles.css
  • src/types.ts
  • tsconfig.json

Comment thread src/i18n/index.ts
Comment on lines +5 to +6
export type MessageKey = keyof typeof messages;
export type MessageParameters = Record<string, string | number>;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 查找含命名占位符但未传第二个参数的直接调用。
rg -nP --glob '*.ts' '\bt\(\s*["'\''][^"'\'']*\{[A-Za-z][A-Za-z0-9]*\}[^"'\'']*["'\'']\s*\)' src e2e

# 检查翻译 API 和全部调用点,以便更新动态键调用。
ast-grep outline src/i18n/index.ts --items all
rg -n -C 2 --glob '*.ts' '\bt\s*\(' src e2e

Repository: LRainner/AgentCat

Length of output: 155


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- tracked i18n files ---'
git ls-files | rg '(^|/)(i18n|.*translation|.*locale|.*messages).*|src/i18n/index\.ts$' || true

printf '%s\n' '--- src/i18n/index.ts ---'
cat -n src/i18n/index.ts

printf '%s\n' '--- translation API definitions and calls ---'
rg -n -C 3 --glob '*.{ts,tsx}' '(^|[^[:alnum:]_])t\s*[:=]|\bt\s*\(|MessageKey|MessageParameters|data-i18n' src e2e || true

printf '%s\n' '--- i18n outline ---'
ast-grep outline src/i18n/index.ts --items all || true

Repository: LRainner/AgentCat

Length of output: 41545


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- message keys and placeholders ---'
python3 - <<'PY'
import json, re
from pathlib import Path

messages = json.loads(Path("src/i18n/messages.json").read_text())
pattern = re.compile(r"\{([A-Za-z][A-Za-z0-9]*)\}")
for key, value in messages.items():
    texts = value if isinstance(value, dict) else {"value": value}
    names = sorted(set(n for text in texts.values() for n in pattern.findall(text)))
    if names:
        print(f"{key!r}: {names}")
PY

printf '%s\n' '--- i18n tests ---'
cat -n src/i18n/index.test.ts

printf '%s\n' '--- project TypeScript configuration ---'
git ls-files | rg '(^|/)(tsconfig[^/]*|package\.json|vite\.config[^/]*)$' | xargs -r -n1 sh -c 'echo "--- $0"; cat -n "$0"'

printf '%s\n' '--- data-i18n attributes in tracked files ---'
rg -n --glob '!src/i18n/messages.json' 'data-(i18n|i18n-title|i18n-aria-label|i18n-placeholder)=' . || true

printf '%s\n' '--- all literal t calls containing placeholders without a second argument ---'
python3 - <<'PY'
import re
from pathlib import Path

call = re.compile(r'\bt\(\s*(["\'])(.*?)\1\s*(?:,|\))', re.S)
for path in [Path(p) for p in __import__("subprocess").check_output(["git","ls-files","src","e2e"], text=True).splitlines()]:
    if path.suffix != ".ts":
        continue
    text = path.read_text()
    for m in call.finditer(text):
        if "{" in m.group(2) and m.group(0).rstrip().endswith(")"):
            print(f"{path}:{text.count(chr(10), 0, m.start())+1}: {m.group(0).replace(chr(10),' ')}")
PY

Repository: LRainner/AgentCat

Length of output: 20380


将命名参数绑定到 MessageKey

MessageParameters 当前接受任意键,t 在缺少参数时会保留 {name}。请从 MessageKey 提取占位符名称,并要求包含占位符的键提供对应参数。对 data-i18n 等动态键,仅允许不含占位符的键,或提供单独的动态翻译 API。添加 @ts-expect-error 编译期测试,覆盖缺少参数和错误参数名。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/i18n/index.ts` around lines 5 - 6, 更新 MessageParameters 及 t 的类型定义,使其根据
MessageKey 对应消息中的占位符名称推导必需参数,并拒绝缺少参数或错误参数名;不含占位符的消息应允许无参数调用。对 data-i18n
等动态键,仅允许无占位符键,或提供独立的动态翻译 API;补充覆盖缺少参数和错误参数名的 `@ts-expect-error` 编译期测试。

Comment thread src/i18n/messages.json Outdated
Comment thread src/pet-debug.ts
Comment thread src/settings.ts
Comment thread src/settings.ts Outdated
Comment on lines 331 to 338
pendingUpdate = update;
card.dataset.state = "ready";
icon.textContent = "\u2713";
title.textContent = `v${update.version} 已准备好`;
detail.textContent = "更新包已下载并通过签名验证,可以安全安装。";
title.textContent = t("v{version} is ready", { version: update.version });
detail.textContent = t("The update package was downloaded and passed signature verification. It is safe to install.");
progressBar.style.width = "100%";
button.hidden = true;
installButton.hidden = false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

显示安装按钮前设置当前语言文本。

下载完成后,代码只显示 #install-update。该按钮的初始 HTML 文本是中文,因此英语会话会显示“安装并重启”。

在设置 installButton.hidden = false 前,使用 t("Install and Restart") 写入按钮文本,并确保该消息键存在。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/settings.ts` around lines 331 - 338, 在更新完成处理逻辑中,使用翻译函数 t 将 installButton
的文本设置为 t("Install and Restart"),并确保该消息键已加入语言消息定义;将此赋值放在 installButton.hidden =
false 之前,以便按钮显示时使用当前语言。

@monkeyscan

monkeyscan Bot commented Aug 6, 2026

Copy link
Copy Markdown

PR Title: feat(i18n): add English and Chinese localization

Commit: a708eba

本次 PR(fix(i18n): preserve runtime state on language changes)将设置页更新卡片渲染重构为基于 updatePresentation 判别联合状态机的集中式 renderUpdatePresentation(),并在 applyLanguage() 中于 translateDocument() 之后重渲染更新卡片与 #current-version,从而在切换语言时既保留下载/安装等运行时状态、又完成新语言的翻译。逐一核对各状态(idle/available/checking/current/downloading/ready/check-error/installing/install-error)的按钮显隐/禁用、进度条宽度、progress 显隐与 card.data-state,均与旧行为一致;translateDocument() 先于 renderUpdatePresentation() 执行,避免更新卡片上 data-i18n 默认文案覆盖运行时状态,顺序正确,未发现设置页回归。新增 e2e 用例覆盖“下载完成后切换语言仍保持 ready 状态”。pet-debug 页新增 agent-cat-config-changed 监听以实时应用语言;messages.json 修复一处中文文案。主要问题:pet-debug 的实时语言应用不完整——loadPet() 烘焙进 #debug-validation 的动态译文与原生 i18n(sync_native_i18n)不会随语言切换刷新,导致调试窗口出现新旧语言混杂。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/settings.ts (1)

432-435: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

下载失败与检查失败共用同一文案。

update.download() 抛出异常时也会进入该 catch,界面显示“Unable to check for updates”。此时检查已成功,失败发生在下载阶段。用户看到的原因描述不准确。

可以增加 download-error 状态与对应消息键,区分两个阶段。重试路径不变。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/settings.ts` around lines 432 - 435, 区分检查阶段与下载阶段的失败状态:在涉及
update.download() 的 catch 中将 updatePresentation.phase 设置为
download-error,并增加对应的界面消息键;保留检查失败使用 check-error,且不要改变现有重试路径。
e2e/settings.e2e.ts (1)

297-312: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

该测试未覆盖安装按钮文本的动态写入路径。

第 311 行断言的按钮文本来自 settings.html 的静态翻译,renderUpdatePresentationready 分支不写入该文本。因此测试无法发现 install-errorinstalling 之后重新进入 ready 时按钮文本陈旧的问题(见 src/settings.ts 第 347-355 行)。

可以增加一个用例:先触发安装失败,再重新检查更新,然后断言按钮文本为安装文案。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@e2e/settings.e2e.ts` around lines 297 - 312, Extend the update-state coverage
near the existing “keeps the downloaded update state when switching languages”
test by exercising an install failure, then checking for updates again and
returning to the ready state. Assert that the install button text is rewritten
to the current install label after recovery, covering the dynamic ready branch
in renderUpdatePresentation rather than relying only on static settings.html
translation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/settings.ts`:
- Around line 347-355: 在 src/settings.ts#L347-L355 的 renderUpdatePresentation
ready 分支中写入 installButton.textContent = t("Install and Restart"),确保重新进入 ready
状态时显示正确文案;在 e2e/settings.e2e.ts#L297-L312
增加覆盖该路径的测试:先触发安装失败,再重新检查更新,并断言安装按钮文本为安装文案。
- Around line 323-328: Prevent the `#check-update` action from running before
initialize() has assigned currentVersion, either by binding its listener only
after initialization or by guarding the handler until initialization completes.
Ensure the "current" branch displays the initialized version and cannot render
the empty initial value.

---

Nitpick comments:
In `@e2e/settings.e2e.ts`:
- Around line 297-312: Extend the update-state coverage near the existing “keeps
the downloaded update state when switching languages” test by exercising an
install failure, then checking for updates again and returning to the ready
state. Assert that the install button text is rewritten to the current install
label after recovery, covering the dynamic ready branch in
renderUpdatePresentation rather than relying only on static settings.html
translation.

In `@src/settings.ts`:
- Around line 432-435: 区分检查阶段与下载阶段的失败状态:在涉及 update.download() 的 catch 中将
updatePresentation.phase 设置为 download-error,并增加对应的界面消息键;保留检查失败使用
check-error,且不要改变现有重试路径。
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 77e05b33-9d73-4c97-bdbd-c80d00e6c456

📥 Commits

Reviewing files that changed from the base of the PR and between c286b71 and a708eba.

📒 Files selected for processing (4)
  • e2e/settings.e2e.ts
  • src/i18n/messages.json
  • src/pet-debug.ts
  • src/settings.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/pet-debug.ts
  • src/i18n/messages.json

Comment thread src/settings.ts
Comment on lines +323 to +328
case "current":
icon.textContent = "\u2713";
title.textContent = t("You are up to date");
detail.textContent = t("The current version is v{version}. No updates are available.", { version: currentVersion });
checkButton.textContent = t("Check Again");
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 查找 currentVersion 的声明与赋值
rg -nP -C3 '\bcurrentVersion\b' src/settings.ts

Repository: LRainner/AgentCat

Length of output: 2786


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- declarations and initialization flow ---'
sed -n '100,230p' src/settings.ts

printf '%s\n' '--- update rendering flow ---'
sed -n '280,350p' src/settings.ts
sed -n '380,420p' src/settings.ts

printf '%s\n' '--- renderUpdatePresentation call sites ---'
rg -n -C4 '\brenderUpdatePresentation\b|\binitialize\(\)' src/settings.ts

printf '%s\n' '--- static ordering check ---'
python3 - <<'PY'
from pathlib import Path
text = Path("src/settings.ts").read_text()
for name in ("let currentVersion = \"\";", "function initialize", "function applyLanguage", "function renderUpdatePresentation", "void initialize()"):
    positions = [i for i in range(len(text)) if text.startswith(name, i)]
    print(name, positions)
PY

Repository: LRainner/AgentCat

Length of output: 15089


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- imports and version provider ---'
sed -n '1,100p' src/settings.ts
rg -n -C5 '\bgetVersion\b|\bcheckForUpdates\b|`#check-update`|addEventListener\("click"' src/settings.ts

printf '%s\n' '--- event binding and module startup ---'
sed -n '820,960p' src/settings.ts

printf '%s\n' '--- getVersion definitions and return types ---'
rg -n -C6 'function getVersion|const getVersion|export .*getVersion|invoke<.*version|app.*version|version' src -g '*.ts'

Repository: LRainner/AgentCat

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- update button markup ---'
rg -n -C4 'check-update|install-update|update-status-card' . -g '*.html' -g '*.tsx' -g '*.jsx'

printf '%s\n' '--- route and page rendering ---'
sed -n '230,280p' src/settings.ts
sed -n '760,825p' src/settings.ts

printf '%s\n' '--- focused call sequence ---'
python3 - <<'PY'
from pathlib import Path
text = Path("src/settings.ts").read_text().splitlines()
for i, line in enumerate(text, 1):
    if any(token in line for token in (
        'let currentVersion = ""',
        'async function initialize',
        '[config, currentVersion, petDirectoryInfo]',
        'applyLanguage(config.language)',
        '`#check-update`',
        'async function checkForUpdates',
        'updatePresentation = { phase: "current" }',
        'renderUpdatePresentation();',
        'void initialize()',
    )):
        print(f"{i}: {line}")
PY

Repository: LRainner/AgentCat

Length of output: 8522


在初始化完成前禁用更新检查

#check-updateinitialize() 完成前已绑定且可点击。若此时检查不到更新,"current" 分支会使用初始值 "",显示为 v。在 currentVersion 赋值后再绑定监听器,或在赋值前阻止检查。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/settings.ts` around lines 323 - 328, Prevent the `#check-update` action
from running before initialize() has assigned currentVersion, either by binding
its listener only after initialization or by guarding the handler until
initialization completes. Ensure the "current" branch displays the initialized
version and cannot render the empty initial value.

Comment thread src/settings.ts
Comment on lines +347 to +355
case "ready":
icon.textContent = "\u2713";
title.textContent = t("v{version} is ready", { version: updatePresentation.version });
detail.textContent = t("The update package was downloaded and passed signature verification. It is safe to install.");
progressBar.style.width = "100%";
progressElement.hidden = false;
checkButton.hidden = true;
installButton.hidden = false;
break;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

ready 分支缺少安装按钮文本写入,测试也未覆盖该路径。 renderUpdatePresentation 的公共重置不清除 installButton.textContent,只有 installinginstall-error 分支写入文本。因此从这些状态重新进入 ready 时,按钮显示上一次的文本。

  • src/settings.ts#L347-L355: 在 ready 分支加入 installButton.textContent = t("Install and Restart");
  • e2e/settings.e2e.ts#L297-L312: 增加用例,先触发安装失败,再重新检查更新,然后断言安装按钮文本为安装文案。
📍 Affects 2 files
  • src/settings.ts#L347-L355 (this comment)
  • e2e/settings.e2e.ts#L297-L312
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/settings.ts` around lines 347 - 355, 在 src/settings.ts#L347-L355 的
renderUpdatePresentation ready 分支中写入 installButton.textContent = t("Install and
Restart"),确保重新进入 ready 状态时显示正确文案;在 e2e/settings.e2e.ts#L297-L312
增加覆盖该路径的测试:先触发安装失败,再重新检查更新,并断言安装按钮文本为安装文案。

Comment thread src/pet-debug.ts
type SpriteInspection = { unusedCells: number; nonTransparentPixels: number; transparent: boolean };

renderer.onFrame = (frame) => { info.textContent = `模式: ${frame.mode}\n行: ${frame.row}\n列: ${frame.column}\n帧: ${frame.frame}${frame.angle === undefined ? "" : `\n角度: ${String(frame.angle).padStart(3, "0")}°`}`; };
function applyLanguage(config: AppConfig): void {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pet-debug 页切换语言后动态校验信息与原生标题不会随语言更新

本次改动为 pet-debug 页新增了 agent-cat-config-changed 监听,在语言变化时调用 applyLanguage() 实时应用新语言。但该 applyLanguage() 仅执行 setLanguage() 与 translateDocument()。translateDocument() 只处理带 data-i18n 的静态元素;而 loadPet() 通过 validation.innerHTML = ... + t(...) 写入的宠物校验信息(如「尺寸正确」「未使用格完全透明」等)是在加载时烘焙的译文,不带有 data-i18n,切换语言后不会刷新。此外,settings.ts 的 applyLanguage() 会调用 sync_native_i18n 同步原生窗口标题等,而 pet-debug 的 applyLanguage() 未调用,因此调试窗口的原生标题(Agent Cat Animation Tester)也不会更新。结果是打开调试窗口时切换语言,会出现静态文案已翻译、而 #debug-validation 校验块与原生标题仍停留在旧语言的中英文混杂状态,与本次“保留运行时状态并重新翻译”的目标不一致。

Problem code:

Changed code at src/pet-debug.ts:18-22

Recommendation:
在 pet-debug.ts 的 applyLanguage() 中补齐动态内容与原生 i18n 的刷新:与 settings.ts 保持一致调用 void invoke("sync_native_i18n", { value: nativeMessages() }),并在 pets 已加载时对当前宠物重新执行 loadPet(Number(select.value)) 以重渲染 #debug-validation 中的译文(或将这些文案改为 data-i18n 以复用 translateDocument)。

Suggested diff:

diff --git a/src/pet-debug.ts b/src/pet-debug.ts
--- a/src/pet-debug.ts
+++ b/src/pet-debug.ts
@@ function applyLanguage(config: AppConfig): void {
   setLanguage(config.language);
   translateDocument();
+  void invoke("sync_native_i18n", { value: nativeMessages() });
+  if (pets.length) void loadPet(Number(select.value));
 }

@LRainner
LRainner merged commit 1594d3e into master Aug 7, 2026
9 of 14 checks passed
@LRainner
LRainner deleted the codex/add-i18n-support branch August 7, 2026 00:59
LRainner added a commit that referenced this pull request Aug 7, 2026
🤖 I have created a release *beep* *boop*
---


## [1.8.0](v1.7.0...v1.8.0)
(2026-08-07)


### Features

* **i18n:** add English and Chinese localization
([#44](#44))
([1594d3e](1594d3e))
* **status:** allow dismissing live bubbles
([#42](#42))
([5c91d5e](5c91d5e))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **新功能**
  * 支持英文和中文本地化。
  * 支持关闭实时气泡显示。

* **文档**
  * 更新 1.8.0 版本变更记录,并补充上述功能说明。

* **版本更新**
  * 产品版本已升级至 1.8.0。

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant