Files
qiming/qiming-mobile/docs/i18n-h5-20260410-execution-log.md

1070 lines
48 KiB
Markdown

# i18n-h5-20260410 Execution Log
## Metadata
- Project: `qiming-mobile`
- Target: `H5 i18n rollout`
- Branch: `feature/i18n-h5-20260410`
- Timezone: `Asia/Shanghai (+0800)`
## Step Records
### S01
- Start: `2026-03-30 12:58:41 +0800`
- Goal: verify baseline git state before implementation
- Action:
- `git status -sb`
- `git rev-parse --abbrev-ref HEAD`
- Result:
- current branch confirmed as `feat-2026.4.10`
- worktree clean
- Evidence:
- output snapshot: `## feat-2026.4.10...origin/feat-2026.4.10`
- Risk / Rollback:
- none
### S02
- Start: `2026-03-30 12:58:41 +0800`
- Goal: sync remote refs and create feature branch
- Action:
- `git fetch origin --prune`
- `git checkout feat-2026.4.10`
- `git pull --ff-only origin feat-2026.4.10`
- `git checkout -b feature/i18n-h5-20260410`
- Result:
- remote refs fetched successfully
- branch `feature/i18n-h5-20260410` created and checked out
- `git pull` failed once due to SSL connect error
- Evidence:
- output snapshot: `Switched to a new branch 'feature/i18n-h5-20260410'`
- error snapshot: `LibreSSL SSL_connect: SSL_ERROR_SYSCALL`
- Risk / Rollback:
- risk: local branch may miss very latest remote commits if remote changed after fetch
- rollback: re-run `git pull --ff-only origin feat-2026.4.10` after network recovery and rebase feature branch if needed
### M0 Baseline
- Completed:
- branch bootstrap
- execution log initialized
- Pending:
- i18n runtime, API integration, UI replacement
- Next:
- build i18n foundation modules and wire app bootstrap
### S03
- Start: `2026-03-30 13:00:00 +0800`
- Goal: create i18n foundation (types/constants/runtime/API)
- Action:
- added `types/interfaces/i18n.uts`
- added `constants/i18n.constants.uts`
- added `constants/i18n.local.constants.uts`
- added `servers/i18n.uts`
- added `utils/i18n.uts`
- Result:
- i18n runtime ready with cache bootstrap, language normalization, language loading, manual language switch, and fallback lookup
- API encapsulation for `/api/i18n/lang/list`, `/api/i18n/query`, and `setLang` endpoint
- Evidence:
- new file list present in `git status`
- Risk / Rollback:
- risk: `/api/i18n/lang/set` path may differ by backend deploy
- rollback: update `I18N_SET_LANG_API` constant only, no cross-file refactor needed
### S04
- Start: `2026-03-30 13:12:00 +0800`
- Goal: wire app bootstrap and request language context
- Action:
- updated `main.uts` to bootstrap i18n cache before app creation
- updated `App.uvue` to load i18n on app launch
- updated `servers/useRequest.uts` to add `Accept-Language` and `lang` headers
- updated `types/interfaces/login.uts` to include `UserInfo.lang`
- Result:
- i18n now initializes at app startup
- all HTTP/SSE requests carry language context
- Evidence:
- touched files: `main.uts`, `App.uvue`, `servers/useRequest.uts`, `types/interfaces/login.uts`
- Risk / Rollback:
- risk: header key mismatch in backend gateway
- rollback: keep only one header key by editing `servers/useRequest.uts`
### S05
- Start: `2026-03-30 13:20:00 +0800`
- Goal: reduce page-level migration cost through shared component adaptation
- Action:
- updated `custom-nav-bar`, `pane-tabs`, `menu-dropdown` to pass labels through i18n translator
- Result:
- common title/menu/tab labels can be translated without repeating per-page conversion
- Evidence:
- changed files under `components/custom-nav-bar`, `components/pane-tabs`, `components/menu-dropdown`
- Risk / Rollback:
- risk: component label props that are dynamic business text could be over-translated
- rollback: switch translation helper to key-only mode
### S06
- Start: `2026-03-30 13:28:00 +0800`
- Goal: implement H5 language switch in profile page
- Action:
- updated `subpackages/pages/about-me/about-me.uvue`
- added language picker for H5
- wired `setLanguage()` + re-query flow + success/fail feedback
- Result:
- profile page supports manual language switching with immediate effect
- Evidence:
- H5-only picker section added in template
- Risk / Rollback:
- risk: set language endpoint failure degrades switch action
- rollback: keep picker visible but disable submit and show toast
### S07
- Start: `2026-03-30 13:35:00 +0800`
- Goal: migrate high-frequency user-visible copy in core flows
- Action:
- converted index/home/header/login/temp-session/agent-list/conversation-list/agent-union key texts to i18n keys
- converted login-related toasts/modals/placeholders in:
- `components/auth-login-popup.uvue`
- `subpackages/pages/login-weixin/login-weixin.uvue`
- `subpackages/pages/login/components/login-form/login-form.uvue`
- `subpackages/pages/login/components/captcha-verify/captcha-verify.uvue`
- `subpackages/pages/login/components/reset-password/reset-password.uvue`
- `components/agreement-checkbox/agreement-checkbox.uvue`
- updated reusable list component `components/published-agent-list.uvue` empty/loading/error copy
- Result:
- primary login + homepage + profile + list browsing flow now translated through i18n runtime
- Evidence:
- modified file set visible in `git status --short`
- Risk / Rollback:
- risk: some long-tail pages still contain hard-coded Chinese
- rollback: fallback map keeps existing zh output; incremental migration remains safe
### S08
- Start: `2026-03-30 13:50:00 +0800`
- Goal: run static verification for syntax and formatting safety
- Action:
- ran `npx prettier --check` on changed files
- fixed parse issue in `subpackages/pages/temporary-session/temporary-session.uvue` (`textarea` conditional attribute comment)
- Result:
- syntax-blocking issue resolved
- formatting warnings remain (non-blocking)
- Evidence:
- check output recorded with one syntax error fixed
- Risk / Rollback:
- risk: style warnings indicate non-formatted files
- rollback: run targeted prettier write before merge if required
### M1 Foundation + Core Flow
- Completed:
- i18n runtime/API/cache foundation
- request header language injection
- profile language switch (H5)
- core page copy migration for login/home/profile/list
- Pending:
- long-tail module full copy migration and exhaustive regression
- Next:
- QA pass against H5 login and conversation flows
### S09
- Start: `2026-03-30 13:55:01 +0800`
- Goal: resolve syntax blockers and run static diff sanity checks
- Action:
- fixed literal-map key quoting issue in `constants/i18n.local.constants.uts`
- ran:
- `npx prettier --check ...` (all changed files)
- `git diff --check`
- Result:
- no syntax parse errors remain in changed files
- formatter still reports style warnings (not auto-written in this round)
- `git diff --check` passed (no whitespace errors)
- Evidence:
- previous parser error at `constants/i18n.local.constants.uts:232` no longer appears
- Risk / Rollback:
- risk: style inconsistency until formatting pass is executed
- rollback: run `npx prettier --write <target-files>` before final merge
### S10
- Start: `2026-03-30 14:10:00 +0800`
- Goal: full omission audit against "全部覆盖" requirement
- Action:
- scanned user-facing Chinese literals across `pages/`, `subpackages/`, `components/`
- grouped results by high-frequency modules and user-visible patterns
- extracted representative remaining strings (template text, placeholder, toast/modal text)
- Result:
- "not fully covered" confirmed
- rough metrics:
- total Chinese-hit lines: `2296` (includes comments)
- non-comment Chinese-hit lines: `376`
- likely user-visible unresolved lines (heuristic): `61`
- top remaining modules:
- `subpackages/pages/chat-conversation-component/*`
- `components/chat-input-phone/*`
- `subpackages/pages/agent-search/agent-search.uvue`
- `subpackages/pages/file-preview-page/file-preview-page.uvue`
- `subpackages/pages/webview/webview.uvue`
- `components/voice-recorder-button/voice-recorder-button.uvue`
- Evidence:
- scan commands and outputs retained in session logs
- Risk / Rollback:
- risk: if merged now, H5 i18n claim cannot be "full coverage"
- rollback: continue incremental module migration until unresolved user-visible literals reach zero
### S11
- Start: `2026-03-30 14:20:00 +0800`
- Goal: complete user-visible copy migration by module batches (A/B/C/D)
- Action:
- Batch A (chat main chain):
- updated `subpackages/pages/chat-conversation-component/chat-conversation-component.uvue`
- updated `subpackages/pages/chat-conversation-component/components/more-popup/more-popup.uvue`
- updated `subpackages/pages/chat-conversation-component/components/more-info/more-info.uvue`
- updated `subpackages/pages/chat-conversation-component/components/related-conversation/related-conversation.uvue`
- updated `subpackages/pages/chat-conversation-component/components/agent-conversation-history/agent-conversation-history.uvue`
- updated `subpackages/pages/chat-conversation-component/components/file-tree/file-tree.uvue`
- updated `subpackages/pages/chat-conversation-component/layers/AgentDetailService.uts`
- Batch B (input + voice):
- updated `components/chat-input-phone/chat-input-phone.uvue`
- updated `components/chat-input-phone/manual-component-item/manual-component-item.uvue`
- updated `components/chat-input-phone/skill-select-modal/skill-select-modal.uvue`
- updated `components/chat-input-phone/sandbox-select-modal/sandbox-select-modal.uvue`
- updated `components/voice-recorder-button/voice-recorder-button.uvue`
- Batch C (search/preview/webview/file export):
- updated `subpackages/pages/agent-search/agent-search.uvue`
- updated `subpackages/pages/file-preview-page/file-preview-page.uvue`
- updated `subpackages/components/file-preview-h5.vue`
- updated `subpackages/pages/webview/webview.uvue`
- updated `subpackages/utils/fileTree.uts`
- Batch D (residual components/pages):
- updated `components/page-card/page-card.uvue`
- updated `subpackages/pages/category-agent-list/category-agent-list.uvue`
- updated `subpackages/pages/login/components/captcha-verify/captcha-verify.uvue`
- updated `components/menu-dropdown/menu-dropdown.uvue`
- updated `subpackages/pages/chat-conversation-component/components/new-conversation-set/new-conversation-set.uvue`
- Result:
- migrated unresolved user-visible literals from `54` to `0` (same scan heuristic as S10)
- all newly migrated runtime keys use `Mobile.*` prefix only
- Evidence:
- `/tmp/i18n_user_visible_pending_latest.txt` line count transitioned to `0`
- repo grep check: no `System.Mobile` / `System.Mobile` references
- Risk / Rollback:
- risk: key-value coverage mismatch can surface as raw key on rare pages
- rollback: add missing key into local fallback bundle (`constants/i18n.local.constants.uts`) without reverting code-path migration
### S12
- Start: `2026-03-30 14:45:00 +0800`
- Goal: complete fallback dictionary for all newly used keys
- Action:
- expanded zh/en fallback bundles in `constants/i18n.local.constants.uts`
- added literal lookup mappings for high-frequency literals (e.g. `搜索智能体`, `页面首页`, `对话设置`, `智能体电脑选择`)
- executed key parity check:
- extract keys from code usage (`Mobile.*`)
- compare with fallback dictionary keys
- Result:
- missing key count reduced from `91` to `0`
- Evidence:
- check artifact `/tmp/missing_i18n_keys.txt` shows `0` lines
- Risk / Rollback:
- risk: translation wording may need product review
- rollback: adjust values in fallback file only, no API/logic rollback required
### S13
- Start: `2026-03-30 14:58:00 +0800`
- Goal: implement enforceable i18n audit gate
- Action:
- added audit script: `scripts/i18n-audit.mjs`
- scans `pages/`, `subpackages/`, `components/`
- excludes `components/pane-tabs/example.uvue`
- strips block/html comments
- checks Chinese literals only in user-visible contexts (template text, placeholder/title, toast/modal/loading/title setters)
- added npm command in `package.json`:
- `i18n:audit`
- Result:
- gate command available and aligned with "hit count must be 0" merge threshold
- Evidence:
- `npm run i18n:audit` output: `[i18n audit] passed: 0 user-visible Chinese hardcoded lines.`
- Risk / Rollback:
- risk: audit uses heuristic patterns, may need pattern tuning for edge cases
- rollback: update `scripts/i18n-audit.mjs` rule list; keep command name stable for CI integration
### S14
- Start: `2026-03-30 15:04:00 +0800`
- Goal: final static gate verification
- Action:
- executed user-visible Chinese scan (same heuristic command as S10)
- executed `npm run i18n:audit`
- executed `git diff --check`
- executed targeted `npx prettier --check` to verify parser safety on changed files
- fixed parser-blocking template annotations (inline `#ifdef` comments inside tags) in:
- `subpackages/pages/agent-search/agent-search.uvue`
- `components/chat-input-phone/chat-input-phone.uvue`
- `subpackages/pages/chat-conversation-component/components/new-conversation-set/new-conversation-set.uvue`
- fixed one trailing whitespace issue in `new-conversation-set.uvue` and re-ran checks
- Result:
- user-visible hardcoded Chinese scan result: `0`
- audit script: pass
- diff whitespace check: pass
- no syntax parse errors in targeted prettier check (style warnings remain)
- Evidence:
- `/tmp/i18n_user_visible_pending_latest.txt` count `0`
- terminal outputs for `i18n:audit` and `git diff --check passed`
- Risk / Rollback:
- risk: runtime verification still required on real H5 and MP-WEIXIN environments
- rollback: key-level rollback supported by fallback dictionary edits and per-file revert
### M2 全量覆盖收口
- Completed:
- `Mobile.*` single-prefix migration for changed user-visible copy
- H5 full user-visible copy migration in audited scope
- MP-WEIXIN fixed-language behavior retained (no language switch entry added)
- `i18n:audit` command implemented and passing
- Pending:
- end-to-end runtime regression on target environments (H5 + MP-WEIXIN)
- Next:
- run manual regression matrix for login/chat/search/preview/file-export flows in both language states
### S15
- Start: `2026-03-30 15:30:18 +0800`
- Goal: close residual i18n misses in `utils/servers` adjacent paths and restore zero-hit gate
- Action:
- executed `npm run i18n:audit`; initial result found 5 hits:
- `subpackages/pages/chat-conversation-component/layers/AgentDetailService.uts`
- `components/chat-input-phone/chat-input-phone.uvue`
- `servers/agentDev.uts`
- `servers/audioUploader.uts`
- replaced residual hardcoded messages with i18n keys or english logs:
- upload reject fallback in `components/chat-input-phone/chat-input-phone.uvue`
- download failure message in `servers/agentDev.uts` -> `Mobile.AgentDev.downloadFailedWithCode`
- status-code failure message in `servers/audioUploader.uts` -> `Mobile.AudioUploader.requestFailedWithCode`
- error callback / processing logs in `AgentDetailService.uts` converted to english
- expanded fallback dictionary in `constants/i18n.local.constants.uts` (zh/en) for new keys
- extended static quality checks:
- `git diff --check`
- key parity compare (`Mobile.*` used vs fallback dictionary)
- `npx prettier --check` on touched files, then `--write`, then re-check
- Result:
- i18n audit hit count returned to `0`
- no missing `Mobile.*` keys in fallback dictionary
- whitespace/style gates passed on touched files
- Evidence:
- `npm run i18n:audit` => `[i18n audit] passed: 0 user-visible Chinese hardcoded lines.`
- key parity output => `Missing in dict:` empty
- `git diff --check` => no output
- `npx prettier --check ...` => `All matched files use Prettier code style!`
- Risk / Rollback:
- risk: any new future chinese literal in `utils/servers` can bypass coverage if outside audit patterns
- rollback: revert specific files and keep dictionary keys; no runtime API rollback needed
### M3 收口加固
- Completed:
- residual 5-hit gap fixed and re-verified to zero
- audit + key parity + formatting checks all passed for this batch
- Pending:
- optional CI integration to enforce `npm run i18n:audit` before merge
### S16
- Start: `2026-03-30 15:38:30 +0800`
- Goal: provide local default language files for platform bootstrap and import seeding
- Action:
- split local fallback dictionary into independent locale files:
- `constants/i18n-locales/zh-CN.uts`
- `constants/i18n-locales/en-US.uts`
- refactored `constants/i18n.local.constants.uts` to aggregate from split files while keeping existing `I18N_LITERAL_LOOKUP` and runtime helper APIs unchanged
- added export command for platform default import package:
- script: `scripts/i18n-export-defaults.mjs`
- npm: `npm run i18n:export-defaults`
- generated import artifacts:
- `docs/i18n-platform-default-import.csv`
- `docs/i18n-platform-default-import.json`
- Result:
- local runtime now has explicit zh/en default language source files
- platform maintenance can directly import generated default package from local source-of-truth
- exported key count: `230`
- Evidence:
- `npm run i18n:export-defaults` => `[i18n export] wrote 230 keys ...`
- key parity checks:
- used keys missing in zh-cn: `0`
- used keys missing in en-us: `0`
- zh/en mismatch: `0`
- `npm run i18n:audit` passed; `git diff --check` passed
- Risk / Rollback:
- risk: if locale source format changes, export script regex may need同步调整
- rollback: keep split locale files and temporarily disable export script while preserving runtime fallback behavior
### S17
- Start: `2026-03-30 15:46:30 +0800`
- Goal: complete additional user-visible literal cleanup and partial delivery checkpoint
- Action:
- replaced residual user-visible literals with i18n keys in:
- `App.uvue` (`Mobile.App.pressAgainToExit`)
- `components/page-preview-iframe/page-preview-iframe.uvue` (`Mobile.PagePreview.defaultTitle`)
- `components/button-wrapper/button-wrapper.uvue` (`Mobile.ButtonWrapper.pagePathParamConfigError`, `Mobile.ButtonWrapper.pagePathConfigError`)
- `components/chat-upload-image/chat-upload-image.uvue` (`Mobile.Chat.previewTypeUnsupported`)
- expanded locale defaults in:
- `constants/i18n-locales/zh-CN.uts`
- `constants/i18n-locales/en-US.uts`
- expanded audit scope to include `App.uvue` in `scripts/i18n-audit.mjs`
- regenerated platform import defaults via `npm run i18n:export-defaults`
- Result:
- default import package key count from `230` -> `234`
- audit still passes at `0` hit
- Evidence:
- `npm run i18n:export-defaults` => wrote `234` keys
- `npm run i18n:audit` => passed
- `git diff --check` => no output
- Risk / Rollback:
- risk: App 端提示 key 需依赖 i18n 词典加载(已有本地兜底)
- rollback: 可按文件维度回退,不影响 i18n 主流程接口
### S18
- Start: `2026-03-30 16:02:59 +0800`
- Goal: align initialization behavior with backend language-hit logic
- Action:
- updated `utils/i18n.uts` init path:
- H5 init now calls `/api/i18n/query` without `lang`
- MP-WEIXIN still enforces fixed `zh-cn` via explicit query target
- kept manual switch behavior unchanged (`setLanguage` uses save-lang + explicit query)
- Result:
- initialization semantics now match requirement: "page-load prefetch uses backend-hit language logic"
- Evidence:
- code path in `loadI18n` calls `fetchLangMap("")` on H5
- `npm run i18n:audit` passed; `git diff --check` passed
- Risk / Rollback:
- risk: when local cache is empty, `currentLang` may differ from backend-hit language label until explicit switch/save
- rollback: revert `utils/i18n.uts` only, no API contract rollback required
### S19
- Start: `2026-03-30 16:07:51 +0800`
- Goal: close remaining accessibility/visible literal gaps after review
- Action:
- localized `alt` accessibility text:
- `components/page-card/page-card.uvue` (`cover image`, `avatar`)
- `components/agent-component/agent-component.uvue` (`avatar`)
- localized image-choose failure toast in `components/chat-input-phone/chat-input-phone.uvue`
- replaced hardcoded english with `Mobile.Chat.chooseImageFailed`
- expanded locale dictionaries:
- `Mobile.Common.coverImageAlt`
- `Mobile.Common.avatarAlt`
- `Mobile.Chat.chooseImageFailed`
- strengthened audit rule to include `alt=` in visible-line patterns (`scripts/i18n-audit.mjs`)
- regenerated platform default import artifacts (`npm run i18n:export-defaults`)
- Result:
- static `alt` hardcoded literals removed from business components
- fallback/export dictionary key count increased to `237`
- review-raised missing points are closed for this batch
- Evidence:
- `rg '\balt="[^"]+"'` now returns only `:alt="t(...)"` bindings in relevant components
- `npm run i18n:audit` => pass (0 hit)
- `git diff --check` => no output
- Risk / Rollback:
- risk: audit still focuses on chinese hardcoded detection and visible patterns; non-standard literal paths may need rule extension
- rollback: per-file revert for component-level changes; dictionary additions are backward compatible
### S20
- Start: `2026-03-30 16:10:59 +0800`
- Goal: verify residual omissions and harden multilingual behavior in mixed-language names
- Action:
- executed residual scans:
- hardcoded `alt` attribute scan
- hardcoded `title:` literal scan in toast/modal contexts
- locale key parity checks (used keys vs zh/en bundles)
- updated `components/chat-input-phone/manual-component-item/manual-component-item.uvue` icon mapping logic:
- from Chinese-only keyword matching to Chinese + English keyword matching (`search/internet/research/deep`)
- Result:
- no remaining business `alt` hardcoded literal found (all switched to `:alt="t(...)"`)
- no remaining business `title:` hardcoded visible literal (excluding commented lines / empty placeholder)
- key parity remains complete
- multilingual display no longer causes icon match fallback in english keyword cases
- Evidence:
- `npm run i18n:audit` => pass
- `git diff --check` => pass
- parity output: `Missing in zh-cn:` empty, `Missing in en-us:` empty
- Risk / Rollback:
- risk: keyword-based icon mapping still heuristic; future locale text variants may require type-based mapping
- rollback: revert `manual-component-item` logic only
### S21
- Start: `2026-03-30 16:16:48 +0800`
- Goal: continue omission closure and strengthen gate for non-Chinese hardcoded visible literals
- Action:
- fixed residual visible literals:
- `components/page-card/page-card.uvue`: `alt` switched to i18n keys
- `components/agent-component/agent-component.uvue`: `alt` switched to i18n key
- `components/chat-input-phone/chat-input-phone.uvue`: image choose failure toast switched to i18n key
- `subpackages/pages/chat-conversation-component/components/more-info/more-info.uvue`: removed hardcoded author initial (`A`) -> dynamic initial derivation
- expanded zh/en locale dictionaries with:
- `Mobile.Common.coverImageAlt`
- `Mobile.Common.avatarAlt`
- `Mobile.Chat.chooseImageFailed`
- hardened audit script `scripts/i18n-audit.mjs`:
- keeps chinese visible literal detection
- adds non-chinese hardcoded visible literal detection for `title/content/confirmText/cancelText/placeholder/alt`
- excludes i18n-key form (`Mobile.*`) and avoids dynamic binding false positives
- regenerated platform default import artifacts via `npm run i18n:export-defaults`
- Result:
- no remaining business static `alt` literal
- no remaining direct toast `title` hardcoded visible literal in active code paths
- audit gate now can block english hardcoded visible literals in key scenes
- default import key count increased to `237`
- Evidence:
- `npm run i18n:audit` => pass
- `git diff --check` => pass
- `rg '\\balt="[^\\"]+"'` returns only `:alt="t(...)"` in business components
- Risk / Rollback:
- risk: regex-based audit still heuristic and may need incremental rule tuning for edge syntax
- rollback: rule rollback limited to `scripts/i18n-audit.mjs`, does not affect runtime behavior
### S22
- Start: `2026-03-30 16:24:56 +0800`
- Goal: close tabBar multilingual omission for H5 runtime
- Action:
- implemented tabBar runtime i18n sync in `utils/i18n.uts`:
- added `TAB_BAR_I18N_ITEMS` mapping (home/unionRecord/agent/app)
- added `applyTabBarI18n()` using `uni.setTabBarItem`
- trigger points:
- `bootstrapI18nCache`
- `loadI18n` success path
- `setLanguage` success path
- maintained platform isolation:
- only applies on H5/WEB
- MP-WEIXIN remains fixed `zh-cn`
- Result:
- H5 tabBar text now follows active language instead of static `pages.json` defaults only
- Evidence:
- code added in `utils/i18n.uts`
- `npm run i18n:audit` passed
- `git diff --check` passed
- Risk / Rollback:
- risk: on non-tab pages, `setTabBarItem` may throw; protected with try/catch
- rollback: remove `applyTabBarI18n()` calls only
### S23
- Start: `2026-03-30 16:33:17 +0800`
- Goal: continue final omission closure for hardcoded fallback app titles
- Action:
- replaced hardcoded fallback app title `Qiming` with i18n key `Mobile.Common.appName` in:
- `utils/commonBusiness.uts`
- `subpackages/pages/webview/webview.uvue`
- `subpackages/pages/category-agent-list/category-agent-list.uvue`
- added locale key in zh/en bundles:
- `Mobile.Common.appName`
- regenerated platform import artifacts via `npm run i18n:export-defaults`
- Result:
- business runtime no longer contains direct `Qiming` fallback literal; all app-name fallback now goes through i18n layer
- default import key count increased to `238`
- Evidence:
- `rg -n 'Qiming' ...` now only hits locale dictionary values
- `npm run i18n:audit` passed
- `git diff --check` passed
- Risk / Rollback:
- risk: none functionally; key missing would fallback to local dictionary immediately
- rollback: revert three usage files while keeping key definitions
### S24
- Start: `2026-03-30 17:01:42 +0800`
- Goal: continue final omission closure for residual visible text edge-cases
- Action:
- replaced static agreement separator in `components/agreement-checkbox/agreement-checkbox.uvue` with i18n key:
- `Mobile.Auth.agreementSeparator`
- normalized published-agent-list default title to translated default instead of raw key literal:
- `components/published-agent-list/published-agent-list.uvue`
- updated locale defaults (zh/en) with:
- `Mobile.Auth.agreementSeparator`
- adjusted audit output wording in `scripts/i18n-audit.mjs` to align with “hardcoded user-visible text” gate scope
- regenerated platform default import artifacts via `npm run i18n:export-defaults`
- Result:
- agreement line punctuation now language-aware
- no raw i18n-key fallback title leak when published-agent-list is reused without explicit title prop
- platform import default key count increased to `239`
- Evidence:
- `npm run i18n:audit` => pass (`0 user-visible hardcoded lines`)
- `git diff --check` => pass
- `docs/i18n-platform-default-import.json` => `totalKeys: 239`
- Risk / Rollback:
- risk: minimal; only text rendering defaults changed
- rollback: revert S24 touched files without impacting i18n runtime core
### S25
- Start: `2026-03-30 16:45:19 +0800`
- Goal: close review concern on accessibility `alt` internationalization and prevent regression
- Action:
- re-checked business `alt` usage:
- `components/page-card/page-card.uvue`
- `components/agent-component/agent-component.uvue`
- confirmed all existing `alt=` in business code are `t(...)` based and use:
- `Mobile.Common.coverImageAlt`
- `Mobile.Common.avatarAlt`
- hardened `scripts/i18n-audit.mjs` to detect bound-literal hardcoding patterns, including:
- `:alt="'...'"`, `:placeholder="'...'"`, `:title="'...'"`, `:content="'...'"`, `:confirmText="'...'"`, `:cancelText="'...'"`
- Result:
- review-mentioned `alt` hardcoding risk is closed in current branch
- audit gate now can block both static and bound-literal forms for key user-visible fields
- Evidence:
- `rg -n "alt=" components pages subpackages --glob '*.uvue'` shows only `:alt="t(...)"` usages
- `npm run i18n:audit` => pass (`0 user-visible hardcoded lines`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; regex expansion may introduce rare false positives in future complex expressions
- rollback: revert only new bound-literal regex lines in `scripts/i18n-audit.mjs`
### S26
- Start: `2026-03-30 16:51:00 +0800`
- Goal: expand accessibility alt coverage beyond card components
- Action:
- added i18n-based avatar `alt` to additional user-visible avatar scenes:
- `pages/index/header-menu/header-menu.uvue`
- `subpackages/pages/about-me/about-me.uvue`
- `subpackages/pages/chat-conversation-component/components/more-info/more-info.uvue`
- all above use existing key:
- `Mobile.Common.avatarAlt`
- Result:
- avatar alt text coverage expanded from card components to header/profile/conversation-more-info scenes
- no new dictionary key needed, keeps import set stable
- Evidence:
- `rg -n "alt=" components pages subpackages --glob '*.uvue'` shows all current `alt` bindings use `t(...)`
- `npm run i18n:audit` => pass (`0 user-visible hardcoded lines`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: very low, template attribute-only change
- rollback: revert the three S26 view files only
### S27
- Start: `2026-03-30 17:09:03 +0800`
- Goal: continue full-coverage i18n closure for image accessibility text and enforce gate
- Action:
- performed repo-wide business scan for `<image>` tags in `pages/components/subpackages` and closed all missing `alt` cases (non-comment code).
- completed alt coverage in key scenes:
- list empty states (`agent-list-content`, `conversation-list-content`, `published-agent-list`, `agent-search`)
- agent/card icons (`agent-component`, `recent-used-agent-item`, `category-agent-list`, `agent-union-record`)
- chat/attachment chain (`chat-upload-image`, `chat-conversation-component`, `file-tree`, `file-tree-node`)
- common UI (`custom-nav-bar`, `login-layout`, `empty-state`, `button-wrapper`, `skill-select-modal`, `voice-recorder-button`)
- semantics strategy:
- meaningful images use i18n alt (`t(...)`)
- decorative icons use empty alt (`alt=""`)
- enhanced `scripts/i18n-audit.mjs`:
- added hard gate for `<image>` without `alt`/`:alt`
- expanded locale defaults (zh/en):
- `Mobile.Common.noDataImageAlt`
- `Mobile.Common.agentIconAlt`
- `Mobile.Common.skillIconAlt`
- `Mobile.Common.appLogoAlt`
- `Mobile.Common.deleteIconAlt`
- `Mobile.Chat.uploadImageAlt`
- `Mobile.Chat.uploadFileAlt`
- regenerated platform default import artifacts via `npm run i18n:export-defaults`
- Result:
- business code now has zero missing `alt` for image tags in `pages/components/subpackages`
- i18n gate upgraded to prevent future missing-alt regression
- platform import key count increased to `246`
- Evidence:
- `npm run i18n:audit` => pass (`0 user-visible hardcoded lines`)
- `git diff --check` => pass
- repo scan script output => `TOTAL_MISSING_ALT=0` (comments excluded)
- `docs/i18n-platform-default-import.json` => `totalKeys: 246`
- Risk / Rollback:
- risk: low, broad template attribute updates may expose minor rendering differences on niche devices
- rollback: revert S27 touched files in batches (components/pages/subpackages/audit/locales) without changing i18n runtime core
### S28
- Start: `2026-03-30 17:18:39 +0800`
- Goal: improve runtime language-switch consistency for dynamic UI labels
- Action:
- replaced static-at-init translation patterns with dynamic evaluation:
- `components/chat-input-phone/skill-select-modal/skill-select-modal.uvue`
- `tabs` switched from static array to computed array to follow language switch
- `subpackages/pages/webview/webview.uvue`
- `pageTitle` fallback switched to computed (`displayPageTitle`) instead of init-time `t(...)`
- `pages/index/index.uvue`
- share title fallback changed to computed (`fallbackShareTitle`) to avoid stale language text when tenant title absent
- `utils/commonBusiness.uts`
- function default params no longer evaluate `t(...)` at module-load time
- fallback appName moved to call-time resolution
- improved generic empty-state component i18n behavior:
- `components/empty-state/empty-state.uvue`
- default `text` changed to i18n key
- render switched to `translateText(...)` for runtime language responsiveness
- adjusted `components/published-agent-list/published-agent-list.uvue` default title back to key form for dynamic translation path
- Result:
- reduced stale-text risk after language switching without page reload
- component defaults align with key-driven translation flow
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; mostly fallback and computed wiring changes
- rollback: revert S28 touched files only (`skill-select-modal`, `webview`, `index`, `commonBusiness`, `empty-state`, `published-agent-list`)
### S29
- Start: `2026-03-30 17:22:01 +0800`
- Goal: continue full-coverage key management for remaining visible login literal
- Action:
- replaced login area-code visible literal in:
- `subpackages/pages/login/components/login-form/login-form.uvue`
- `+86` -> `t("Mobile.Auth.defaultAreaCode")`
- added locale keys (zh/en):
- `Mobile.Auth.defaultAreaCode`
- regenerated platform import artifacts via `npm run i18n:export-defaults`
- Result:
- login area-code text now managed in i18n dictionary and can be imported/maintained on platform uniformly
- platform default import key count increased to `247`
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- `docs/i18n-platform-default-import.json` => contains `Mobile.Auth.defaultAreaCode`
- Risk / Rollback:
- risk: very low, text source replacement only
- rollback: revert login-form + locale key entries + regenerated import artifacts
### S30
- Start: `2026-03-30 17:32:21 +0800`
- Goal: improve placeholder language-switch consistency between union-record and search page
- Action:
- changed union-record search handoff to pass i18n key instead of translated text:
- `pages/agent-union-record/agent-union-record.uvue`
- `app.globalData.searchPlaceholder = "Mobile.AgentUnion.searchPlaceholder"`
- refactored agent-search placeholder rendering to key-driven runtime translation:
- `subpackages/pages/agent-search/agent-search.uvue`
- introduced `searchPlaceholderSource` (key source)
- `searchPlaceholder` switched to computed + `translateText(...)`
- local-search handoff now writes source key directly, not one-time translated literal
- Result:
- placeholder can follow current language at runtime more consistently
- avoids stale translated string handoff across page jump boundary
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- code references confirm key-driven flow in both pages
- Risk / Rollback:
- risk: low; affects only search placeholder source plumbing
- rollback: revert S30 two files to prior string-handoff behavior
### S31
- Start: `2026-03-30 17:35:43 +0800`
- Goal: strengthen i18n audit gate for key completeness and prefix policy
- Action:
- enhanced `scripts/i18n-audit.mjs` with key-level checks:
- collect all used `Mobile.*` keys from business code
- validate keys exist in both locale defaults:
- `constants/i18n-locales/zh-CN.uts`
- `constants/i18n-locales/en-US.uts`
- enforce zh/en locale key-set parity
- block legacy key prefix usage:
- code-side `System.*`
- locale-side `System.*`
- preserved existing visible-text/alt gate checks
- Result:
- audit now catches missing dictionary definitions and bilingual key drift early
- key-prefix policy (`Mobile.*` only) is enforced by gate
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- Risk / Rollback:
- risk: low; stricter gate may expose pre-existing key debt in future branches
- rollback: revert S31 delta in `scripts/i18n-audit.mjs`
### S32
- Start: `2026-03-30 17:39:58 +0800`
- Goal: remove residual literal symbols from form UI to approach strict key-only visible text policy
- Action:
- converted two visible literals in new-conversation-set to i18n keys:
- required marker: `*` -> `Mobile.Common.requiredMark`
- single-select separator: `/` -> `Mobile.Common.optionSeparator`
- added locale entries in zh/en defaults:
- `Mobile.Common.requiredMark`
- `Mobile.Common.optionSeparator`
- regenerated platform import artifacts via `npm run i18n:export-defaults`
- Result:
- form visible symbols are now key-managed and platform-importable
- platform default import key count increased to `249`
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- export artifacts contain both new keys
- Risk / Rollback:
- risk: very low; symbol rendering source only
- rollback: revert `new-conversation-set` and locale/export artifact updates
### S33
- Start: `2026-03-30 18:18:57 +0800`
- Goal: improve language-switch behavior for published-agent category tab labels
- Action:
- refactored category label render path in:
- `components/published-agent-list/published-agent-list.uvue`
- changes:
- template label render switched to `translateText(category.label)`
- default "all" category label source changed from translated literal to key:
- `t("Mobile.Common.all")` -> `"Mobile.Common.all"`
- imported `translateText` alongside `useI18n`
- Result:
- "all" tab label can follow runtime language changes through key-driven rendering path
- backend-provided category labels remain compatible (non-key labels pass through unchanged)
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; label render path adjusted but category key/value behavior unchanged
- rollback: revert S33 file only
### S34
- Start: `2026-03-30 18:28:28 +0800`
- Goal: strengthen i18n audit gate for non-Chinese hardcoded visible text coverage
- Action:
- updated `scripts/i18n-audit.mjs`
- added hardcoded visible literal detection for object field `text: "..."`
- added `<text>/<button>` raw text-node scan to detect pure literal nodes without i18n
- handled self-closing text/button tags in scan path to avoid false positives and preserve line mapping
- Result:
- gate now covers additional non-Chinese hardcoded UI copy patterns
- final audit remains green after enhancement
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; only scan logic changes, no runtime behavior impact
- rollback: revert `scripts/i18n-audit.mjs` to previous revision
### S35
- Start: `2026-03-30 18:30:35 +0800`
- Goal: post-commit full sweep for remaining i18n coverage gaps
- Action:
- reran audit gate after S34 commit (`npm run i18n:audit`)
- executed targeted grep for visible-field literals (`title/content/confirmText/cancelText/label/description/placeholder/alt`)
- manually reviewed hits to confirm they are dynamic runtime data or i18n key-based render paths
- Result:
- no new i18n遗漏 found in current sweep
- working tree remained clean after scan
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git status --short --branch` => clean (`ahead 2` at scan end)
- Risk / Rollback:
- risk: none (scan/log only)
- rollback: remove S35 entry if not needed
### S36
- Start: `2026-03-30 18:44:57 +0800`
- Goal: align i18n runtime current language with backend user lang after login info fetch
- Action:
- added `syncLanguageFromUser(lang)` in `utils/i18n.uts`
- H5: sync `currentLang` and storage with user `lang`
- if lang changed, reload lang map by explicit `lang` query and refresh tabbar i18n
- MP: keep fixed `zh-cn`
- integrated lang sync call into login-info fetch points:
- `pages/index/index.uvue`
- `subpackages/pages/about-me/about-me.uvue`
- Result:
- runtime language state is now reconciled with backend persisted user language after user info load
- avoids state drift where UI map/actual language and `currentLang` could be inconsistent
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low-medium; adds one explicit i18n query when user-lang differs from current state
- rollback: revert the three files touched in S36
### S37
- Start: `2026-03-30 18:52:00 +0800`
- Goal: remove remaining hardcoded HTTP error literal in stream request path
- Action:
- updated `utils/streamRequest.uts`
- replaced `HTTP error! status: {code}` literal with i18n key:
- `Mobile.Stream.httpErrorWithCode`
- added locale defaults:
- `constants/i18n-locales/zh-CN.uts`
- `constants/i18n-locales/en-US.uts`
- regenerated platform import defaults:
- `docs/i18n-platform-default-import.csv`
- `docs/i18n-platform-default-import.json`
- Result:
- stream HTTP failure message is now fully translatable and follows `Mobile` key convention
- Evidence:
- `npm run i18n:export-defaults` => wrote 250 keys
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; error text source changed only
- rollback: revert `streamRequest` and locale/export artifacts in this step
### S38
- Start: `2026-03-30 18:55:17 +0800`
- Goal: close missed literal error prompts in message-event delegate hook
- Action:
- updated `subpackages/hooks/useMessageEventDelegate.uts`
- replaced hardcoded Chinese prompt calls:
- `'页面路径配置错误'` -> `t("Mobile.ButtonWrapper.pagePathConfigError")`
- `'页面路径参数配置错误'` -> `t("Mobile.ButtonWrapper.pagePathParamConfigError")`
- imported `t` from `@/utils/i18n`
- Result:
- page-event error prompts now follow unified i18n key mechanism
- removed a previously uncovered hardcoded visible literal
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; prompt source only
- rollback: revert `useMessageEventDelegate.uts` and this log entry
### S39
- Start: `2026-03-30 18:57:42 +0800`
- Goal: prevent future misses of helper-based literal prompt calls in i18n audit
- Action:
- updated `scripts/i18n-audit.mjs`
- added `showError(...)` into visible-scan trigger set
- added hardcoded literal rule for `showError('...')` / `showError("...")`
- Result:
- audit gate now blocks direct literal prompt text routed through `showError` helper
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; static scan rule extension only
- rollback: revert `scripts/i18n-audit.mjs` and this log entry
### S40
- Start: `2026-03-30 20:00:49 +0800`
- Goal: close audit gap for hardcoded error literals passed via `new Error('...')`
- Action:
- updated `scripts/i18n-audit.mjs`
- added hardcoded visible literal rule for `new Error('...')` / `new Error("...")`
- Result:
- audit now blocks additional non-i18n error-literal patterns that may surface to users
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; static rule extension only
- rollback: revert `scripts/i18n-audit.mjs` and this log entry
### S41
- Start: `2026-03-30 20:03:48 +0800`
- Goal: extend audit to template-literal error cases and eliminate newly detected SSE error literal
- Action:
- updated `scripts/i18n-audit.mjs`
- added hardcoded-literal checks for template forms:
- ``showError(`...`)``
- ``new Error(`...`)``
- audit surfaced one hit in `servers/useRequest.uts`:
- ``new Error(`SSE connection failed: ${response.statusText}`)``
- fixed SSE open error throw to avoid hardcoded literal text:
- `new Error(String(response.statusText || response.status || "SSE_ERROR"))`
- Result:
- template-literal hardcoded error prompts are now covered by gate
- SSE connection open failure message no longer uses literal sentence in code
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; gate enhancement + error text construction adjustment
- rollback: revert `scripts/i18n-audit.mjs` and `servers/useRequest.uts`
### S42
- Start: `2026-03-30 20:05:36 +0800`
- Goal: remove residual fallback literal in SSE open error path
- Action:
- adjusted `servers/useRequest.uts` SSE `onopen` error construction
- fallback changed:
- `String(response.statusText || response.status || "SSE_ERROR")`
- -> `String(response.statusText || response.status || 0)`
- Result:
- SSE open error fallback now avoids non-i18n literal text completely
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: very low; only fallback error string changed
- rollback: revert `servers/useRequest.uts` and this log entry
### S43
- Start: `2026-03-30 23:30:43 +0800`
- Goal: make post-login language reconciliation deterministic by awaiting user-lang sync
- Action:
- updated user-info fetch flows to `await` i18n user-lang sync:
- `pages/index/index.uvue`
- `subpackages/pages/about-me/about-me.uvue`
- change:
- `syncLanguageFromUser(data?.lang || "")`
- -> `await syncLanguageFromUser(data?.lang || "")`
- Result:
- language state + lang map reconciliation completes before fetch flow exits
- reduces timing race where UI could briefly use stale language state after user info load
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; only sequencing adjustment in existing async flow
- rollback: revert the two page files and this log entry
### S44
- Start: `2026-03-30 23:33:42 +0800`
- Goal: avoid empty-lang-map race when user lang equals current lang
- Action:
- updated `utils/i18n.uts` in `syncLanguageFromUser`
- when `userLang === currentLang` and `langMap` is empty:
- fetch lang map once by explicit user lang
- cache result to runtime/storage
- refresh tab bar i18n
- Result:
- prevents early-return branch from leaving runtime with empty dictionary
- improves determinism during login/startup timing races
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; only adds guarded fetch when map is empty
- rollback: revert `utils/i18n.uts` and this log entry
### S45
- Start: `2026-03-31 10:12:27 +0800`
- Goal: close review findings on init timing and merge gate enforcement
- Action:
- updated app launch sequence:
- `App.uvue` `onLaunch` changed to async and now `await loadI18n()`
- added CI merge gate workflow:
- `.github/workflows/i18n-audit.yml`
- runs `npm run -s i18n:audit` on `pull_request` and tracked branch pushes
- Result:
- i18n remote dictionary load is now explicitly awaited during app launch
- i18n audit is enforced in CI for merge-time blocking
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low; launch hook now async and CI workflow added
- rollback: revert `App.uvue` and `.github/workflows/i18n-audit.yml`
### S46
- Start: `2026-03-31 10:15:14 +0800`
- Goal: make `loadI18n()` await-safe for concurrent callers
- Action:
- refactored `utils/i18n.uts` load flow with shared task promise:
- added `loadI18nTask` singleton promise
- concurrent calls now await same task instead of returning early on `loading === true`
- preserved existing init logic and state/storage writes
- Result:
- all callers can deterministically await completion of the same i18n load cycle
- removes race where one caller could continue before language map actually loaded
- Evidence:
- `npm run i18n:audit` => pass (`0 i18n coverage issues`)
- `git diff --check` => pass
- Risk / Rollback:
- risk: low-medium; async orchestration changed, business logic unchanged
- rollback: revert `utils/i18n.uts` and this log entry