From 2032dd33ecc7dd5f5617d1150d23d9e544a1a225 Mon Sep 17 00:00:00 2001 From: ClaudiaFang Date: Mon, 13 Jul 2026 14:28:40 +0000 Subject: [PATCH] chore: update harness state for i18n session Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_011BNWwPd5zudtW2JQr6ZAUm --- feature_list.json | 8 ++++++++ progress.md | 42 ++++++++++++++++++++++-------------------- session-handoff.md | 37 +++++++++++++++++++------------------ 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/feature_list.json b/feature_list.json index af3e3e5..665c129 100644 --- a/feature_list.json +++ b/feature_list.json @@ -40,6 +40,14 @@ "dependencies": [], "status": "not-started", "evidence": "" + }, + { + "id": "feat-006", + "name": "feat: add i18n (multi-language) support (issue #38)", + "description": "Extract hardcoded UI text (settings tab, Notice messages) into i18n keys; detect language via window.moment.locale() with English fallback; ship English (default) and Traditional Chinese (zh-tw)", + "dependencies": [], + "status": "in-review", + "evidence": "Branch claude/i18n-support-260713 (based on origin/claude/fix-directory-symlink-pull-260713) - added src/i18n/{index,locales/en,locales/zh-tw}.ts and tests/i18n/index.test.ts; ~130 strings replaced across settings.ts, main.ts, and 7 ui/ files; lint/build clean, 308 tests pass; not yet pushed/PR'd, to be merged back into claude/fix-directory-symlink-pull-260713" } ], "_evidenceStyle": "Keep evidence to one line: commit hash + short pointer (e.g. 'Commit abc1234 - added X, tests pass'). Debugging narrative and design discussion belong in the commit message, not this file." diff --git a/progress.md b/progress.md index 658a8db..cb56fcf 100644 --- a/progress.md +++ b/progress.md @@ -12,28 +12,28 @@ Completed work is archived in [archive/](./archive/), one file per calendar mont ## Current State -**Last Updated:** 2026-07-13 11:40 -**Session ID:** session_01YYCTyZw7gUmJ7oh1VTmAqh -**Active Feature:** feat-002 - Settings UX bundle (issues #40, #41, #42) +**Last Updated:** 2026-07-13 14:20 +**Session ID:** (this session) +**Active Feature:** feat-006 - i18n (multi-language) support (issue #38) ## Status ### What's Done - [x] feat-001 - Project Setup verified (see archive/2026-07.md) -- [x] feat-002 implementation - all three sub-features coded, tested, linted, built (see archive/2026-07.md) +- [x] feat-002 - Settings UX bundle (see archive/2026-07.md); this branch's history already contains it (merged upstream of `claude/fix-directory-symlink-pull-260713`) +- [x] feat-006 implementation - i18n core (`src/i18n/index.ts`, `locales/en.ts`, `locales/zh-tw.ts`), ~130 strings extracted across settings.ts, main.ts, and 7 `ui/` files, tests added, lint/build/test all clean ### What's In Progress -- [ ] feat-002 - Open a PR for branch `claude/settings-ux-improvements-260713` and get it merged - - Details: commit 28f4f8e is pushed to origin; no PR opened yet - - Blockers: none, just needs `gh pr create` +- [ ] feat-006 - push branch `claude/i18n-support-260713` and open a PR (or fold it back into `claude/fix-directory-symlink-pull-260713` per the user's stated intent) + - Details: worked in a separate branch/worktree because `claude/fix-directory-symlink-pull-260713` was already checked out elsewhere in this repo's other worktree (main checkout at `/home/tianyao/git-files-sync`), so git wouldn't allow checking out the same branch twice + - Blockers: none technically; needs the user's go-ahead on push/merge direction ### What's Next -1. Open PR for `claude/settings-ux-improvements-260713`, close issues #40/#41/#42 on merge -2. Pick up feat-003 (issue #33, symlink pull fails) — needs repro investigation first -3. Re-sync this file's backlog entries against `gh issue list --repo firstsun-dev/git-files-sync --state open` since new issues may have been filed (e.g. #48 folder picker was added mid-session) +1. Confirm with user whether to push `claude/i18n-support-260713` and open a PR, or merge it locally into `claude/fix-directory-symlink-pull-260713` +2. Re-sync this file's backlog (feat-003..005) against `gh issue list --repo firstsun-dev/git-files-sync --state open` ## Blockers / Risks @@ -41,26 +41,28 @@ Completed work is archived in [archive/](./archive/), one file per calendar mont ## Decisions Made -- **Discarded a stale local WIP for Obsidian 1.12.x compatibility**: origin/main already shipped this via PR #46 (`applyDestructiveStyle`, `typecheck-compat.mjs`) with a different mechanism. Local main was fast-forwarded to origin/main and the new features (#40/#41/#42) were manually re-applied on top of the correct base rather than merged via `git stash pop` (which would have conflicted/duplicated the compat layer). -- **feat-002 bundles three issues in one commit**: #40/#41/#42 touch overlapping files (`src/settings.ts`, `styles.css`, `tests/setup.ts`) closely enough that splitting into three atomic commits wasn't worth the risk of an intermediate broken state. +- **Worked on a new branch instead of the pre-existing `claude/fix-directory-symlink-pull-260713`**: that branch was already checked out in another worktree (the main repo checkout), and git disallows the same branch in two worktrees. Created `claude/i18n-support-260713` off `origin/claude/fix-directory-symlink-pull-260713` instead, per the user's choice. +- **Flat key-value i18n dict, not nested namespaces**: matches this plugin's small scale; simpler `t(key, vars)` lookup, no external i18n library dependency. +- **Locale detection via `window.moment.locale()`**: per issue #38's suggested approach; unknown/unmapped locales fall back to English. A bare `zh` locale code is mapped to `zh-tw` since that's the only Chinese variant shipped. +- **Diff-format markers, changelog release-note text, and proper nouns (GitHub/GitLab/Gitea) were left untranslated** — out of scope for UI-chrome i18n. ## Files Modified This Session -- `src/settings.ts` - connection status badge (#41), ignore patterns setting (#40) -- `src/ui/SyncConflictModal.ts` - Diff/Local/Remote tab switcher (#42) -- `src/logic/gitignore-manager.ts`, `src/main.ts` - local ignore pattern matching (#40) -- `styles.css` - badge + modal + tab styles -- `tests/setup.ts`, `tests/ui/setup-dom.ts` - expanded Obsidian mocks (TextAreaComponent, removeClass, configDir, etc.) -- `tests/logic/gitignore-manager.test.ts`, `tests/logic/sync-manager*.test.ts`, `tests/ui/SyncConflictModal.test.ts`, `tests/ui/SettingsConnectionStatus.test.ts` - new/updated tests +- `src/i18n/index.ts` (new) - `t(key, vars?)` helper, locale detection/resolution +- `src/i18n/locales/en.ts`, `src/i18n/locales/zh-tw.ts` (new) - 159 keys each, full parity +- `src/settings.ts`, `src/main.ts` - all hardcoded UI strings replaced with `t()` calls +- `src/ui/SyncStatusView.ts`, `src/ui/SyncConflictModal.ts`, `src/ui/WhatsNewModal.ts`, `src/ui/ConfirmModal.ts` - same +- `src/ui/components/ActionBar.ts`, `FileListItem.ts`, `DiffPanel.ts` - same +- `tests/i18n/index.test.ts` (new) - 6 test cases covering fallback, locale resolution, interpolation ## Evidence of Completion -- [x] Tests pass: `npx vitest run` → 254/254 passed +- [x] Tests pass: `npx vitest run` → 308/308 passed (302 pre-existing + 6 new i18n tests) - [x] Type check clean: `npm run build` (tsc + Obsidian 1.11.0 compat typecheck + esbuild) → clean - [x] Lint clean: `npx eslint .` → 0 errors - [ ] Manual verification in Obsidian: not done (no Obsidian instance available in this environment) ## Notes for Next Session -- Branch `claude/settings-ux-improvements-260713` is pushed but has no PR yet — check with the user before opening one (they were asked and hadn't confirmed as of session end). +- Branch `claude/i18n-support-260713` has uncommitted working-tree changes as of this session's end — not yet committed or pushed. - `feature_list.json`'s backlog (feat-003..005) is a snapshot from 2026-07-13; re-check `gh issue list` before trusting it. diff --git a/session-handoff.md b/session-handoff.md index eece67c..ed18676 100644 --- a/session-handoff.md +++ b/session-handoff.md @@ -9,17 +9,19 @@ ## Current Objective -- Goal: Implement issues #40 (local ignore patterns), #41 (settings connection status badge), #42 (resize conflict modal) -- Current status: Implemented, tested, linted, built clean; committed and pushed. PR not yet opened (pending user confirmation). -- Branch / commit: `claude/settings-ux-improvements-260713` @ 28f4f8e +- Goal: Implement issue #38 (i18n / multi-language support for settings + Notice messages) +- Current status: Implemented, tested, linted, built clean. Not yet committed or pushed. +- Branch / commit: `claude/i18n-support-260713` (working tree, uncommitted) — branched off `origin/claude/fix-directory-symlink-pull-260713` ## Completed This Session -- [x] #42 - Resized conflict modal (`min(1100px,92vw) x min(85vh,800px)`, flex layout, removed 280px content cap, added Diff/Local/Remote tab switcher on narrow screens) -- [x] #41 - Persistent connection status badge in settings tab (Checking/Connected/Not connected), 800ms debounce on token/branch/URL/owner/repo edits, updates in place (no focus-stealing re-render) -- [x] #40 - "Ignore patterns" setting (multi-line, .gitignore-style), applied in `GitignoreManager.isIgnored()` additively alongside remote/local `.gitignore` -- [x] Filed issue #48 (folder picker for root path / vault folder settings) at user's request mid-session -- [x] Rebased local `main` onto `origin/main` to adopt the already-shipped Obsidian 1.12.x compat work (PR #46), discarding a stale duplicate local WIP, then re-applied the above three features cleanly on top +- [x] Created `src/i18n/index.ts` — `t(key, vars?)` flat-dict lookup with `{placeholder}` interpolation, English fallback for missing keys +- [x] Locale detection via `window.moment.locale()`; unresolvable/unsupported locales fall back to `en`; bare `zh` maps to `zh-tw` +- [x] `src/i18n/locales/en.ts` (source of truth, 159 keys) and `zh-tw.ts` (full parity, verified no missing/extra keys) +- [x] Replaced ~130 hardcoded strings across `src/settings.ts`, `src/main.ts`, `src/ui/SyncStatusView.ts`, `SyncConflictModal.ts`, `WhatsNewModal.ts`, `ConfirmModal.ts`, `components/ActionBar.ts`, `FileListItem.ts`, `DiffPanel.ts` +- [x] Left untranslated on purpose: GitHub/GitLab/Gitea proper nouns, diff-format markers (`--- Remote`/`+++ Local`), URL placeholders, changelog release-note content +- [x] Fixed a lint regression (cognitive-complexity + nested-ternary) introduced by the change in `SyncStatusView.runBatchOperation` by extracting a lookup table and a helper method +- [x] Added `tests/i18n/index.test.ts` (6 cases: fallback with no `window.moment`, fallback for unsupported locale, zh-tw resolution, bare `zh` → `zh-tw` mapping, interpolation, fallback-per-key when zh-tw is missing a translation) ## Verification Evidence @@ -27,24 +29,23 @@ |---|---|---|---| | Lint | `npx eslint .` | 0 errors | Repo-wide, no exceptions | | Type check + compat | `npm run build` | Pass | Includes `typecheck-compat.mjs` against Obsidian 1.11.0 | -| Tests | `npx vitest run` | 254/254 passed | 17 test files | +| Tests | `npx vitest run` | 308/308 passed | 23 test files (302 pre-existing + 6 new) | | Manual (in Obsidian) | — | Not done | No Obsidian instance available in this environment | ## Files Changed -- `src/settings.ts`, `src/ui/SyncConflictModal.ts`, `src/logic/gitignore-manager.ts`, `src/main.ts`, `styles.css` -- `tests/setup.ts`, `tests/ui/setup-dom.ts` (expanded Obsidian test mocks) -- `tests/logic/gitignore-manager.test.ts`, `tests/logic/sync-manager.test.ts`, `tests/logic/sync-manager-mapping.test.ts` -- `tests/ui/SyncConflictModal.test.ts`, `tests/ui/SettingsConnectionStatus.test.ts` (new) +- New: `src/i18n/index.ts`, `src/i18n/locales/en.ts`, `src/i18n/locales/zh-tw.ts`, `tests/i18n/index.test.ts` +- Modified: `src/settings.ts`, `src/main.ts`, `src/ui/SyncStatusView.ts`, `src/ui/SyncConflictModal.ts`, `src/ui/WhatsNewModal.ts`, `src/ui/ConfirmModal.ts`, `src/ui/components/ActionBar.ts`, `src/ui/components/FileListItem.ts`, `src/ui/components/DiffPanel.ts` ## Decisions Made -- Bundled #40/#41/#42 into a single commit rather than three, since they touch overlapping files closely enough that atomic per-issue commits risked an intermediate broken build. -- Discarded the local uncommitted 1.12.x-compat WIP (user confirmed it was superseded by origin/main's PR #46) rather than trying to merge two different compat mechanisms. +- Worked on a fresh branch (`claude/i18n-support-260713`) instead of `claude/fix-directory-symlink-pull-260713` directly, because that branch was already checked out in this repo's other worktree (main checkout) and git disallows the same branch in two worktrees. User confirmed this approach and indicated intent to eventually merge back into `claude/fix-directory-symlink-pull-260713`. +- Flat key-value dict per locale (not nested namespaces) — simplest fit for this plugin's scale, user-confirmed. +- `window.moment.locale()` detection with English fallback — matches issue #38's suggested approach, user-confirmed. ## Blockers / Risks -- None blocking. Open item: PR for the pushed branch hasn't been created — user was asked "要接著幫你開 PR 嗎?" and the session moved to harness setup before they answered. +- None blocking. Nothing has been committed yet — working tree only. ## Next Session Startup @@ -52,8 +53,8 @@ 2. Read `feature_list.json` and `progress.md`. 3. Review this handoff. 4. Run `./init.sh` before editing. -5. Check whether the user wants a PR opened for `claude/settings-ux-improvements-260713` before starting new work. +5. Ask the user whether to commit + push `claude/i18n-support-260713` (and open a PR), or merge these changes locally into `claude/fix-directory-symlink-pull-260713` instead. ## Recommended Next Step -- Ask the user whether to open the PR for the pushed branch; if yes, use `gh pr create` per the repo's PR conventions (see `CLAUDE.md` / firstsun-pm workflow) and reference issues #40/#41/#42 so they auto-close on merge. +- Get the user's decision on push/PR vs. local merge, then commit with a `feat: add i18n (multi-language) support` message referencing issue #38 so it auto-closes on merge.