Files
opencode/specs/06-app-i18n-audit.md
2026-01-20 17:58:06 -06:00

9.6 KiB

App i18n Audit (Remaining Work)

Scope: packages/app/

Date: 2026-01-20

This report documents the remaining user-facing strings in packages/app/src that are still hardcoded (not routed through useLanguage().t(...) / translation keys), plus i18n-adjacent issues like locale-sensitive formatting.

Current State

  • The app uses useLanguage().t("...") with dictionaries in packages/app/src/i18n/en.ts and packages/app/src/i18n/zh.ts.
  • Recent progress (already translated): packages/app/src/pages/home.tsx, packages/app/src/pages/layout.tsx, packages/app/src/pages/session.tsx, packages/app/src/components/prompt-input.tsx, packages/app/src/components/dialog-connect-provider.tsx, packages/app/src/components/session/session-header.tsx, packages/app/src/pages/error.tsx, packages/app/src/components/session/session-new-view.tsx, packages/app/src/components/session-context-usage.tsx, packages/app/src/components/session/session-context-tab.tsx (plus new keys added in both dictionaries).
  • Dictionary parity check: en.ts and zh.ts currently contain the same key set (362 keys each; no missing or extra keys).

Methodology

  • Scanned packages/app/src (excluding packages/app/src/i18n/* and tests).
  • Grepped for:
    • Hardcoded JSX text nodes (e.g. >Some text<)
    • Hardcoded prop strings (e.g. title="...", placeholder="...", label="...", description="...", Tooltip value="...")
    • Toast/notification strings, default fallbacks, and error message templates.
  • Manually reviewed top hits to distinguish:
    • User-facing UI copy (needs translation)
    • Developer-only logs (console.*) (typically does not need translation)
    • Technical identifiers (e.g. MCP, LSP, URLs) (may remain untranslated by choice).

Highest Priority: Pages

1) Error Page

File: packages/app/src/pages/error.tsx

Completed (2026-01-20):

  • Localized page UI copy via error.page.* keys (title, description, buttons, report text, version label).
  • Localized error chain framing and common init error templates via error.chain.* keys.
  • Kept raw server/provider error messages as-is when provided (only localizing labels and structure).

Highest Priority: Components

2) Prompt Input

File: packages/app/src/components/prompt-input.tsx

Completed (2026-01-20):

  • Localized placeholder examples by replacing the hardcoded PLACEHOLDERS list with prompt.example.* keys.
  • Localized toast titles/descriptions via prompt.toast.* and reused common.requestFailed for fallback error text.
  • Localized popover empty states and drag/drop overlay copy (prompt.popover.*, prompt.dropzone.label).
  • Localized smaller labels (slash "custom" badge, attach button tooltip, Send/Stop tooltip labels).
  • Kept the ESC keycap itself untranslated (key label).

3) Provider Connection / Auth Flow

File: packages/app/src/components/dialog-connect-provider.tsx

Completed (2026-01-20):

  • Localized all user-visible copy via provider.connect.* keys (titles, statuses, validations, instructions, OpenCode Zen onboarding).
  • Added common.submit and used it for both API + OAuth submit buttons.
  • Localized the success toast via provider.connect.toast.connected.*.

4) Session Header (Share/Publish UI)

File: packages/app/src/components/session/session-header.tsx

Completed (2026-01-20):

  • Localized search placeholder via session.header.search.placeholder.
  • Localized share/publish UI via session.share.* keys (popover title/description, button states, copy tooltip).
  • Reused existing command keys for toggle/share tooltips (command.review.toggle, command.terminal.toggle, command.session.share).

Medium Priority: Components

5) New Session View

File: packages/app/src/components/session/session-new-view.tsx

Completed (2026-01-20):

  • Reused existing command.session.new for the heading.
  • Localized worktree labels via session.new.worktree.* (main branch, main branch w/ branch name, create worktree).
  • Localized "Last modified" via session.new.lastModified and used language.locale() for Luxon relative time.

6) Context Usage Tooltip

File: packages/app/src/components/session-context-usage.tsx

Completed (2026-01-20):

  • Localized tooltip labels + CTA via context.usage.* keys.
  • Switched currency and number formatting to the active locale (language.locale()).

7) Session Context Tab (Formatting)

File: packages/app/src/components/session/session-context-tab.tsx

Completed (2026-01-20):

  • Switched currency formatting to the active locale (language.locale()).
  • Also used language.locale() for number/date formatting.
  • Note: "—" placeholders remain hardcoded; optional to localize.

8) LSP Indicator

File: packages/app/src/components/session-lsp-indicator.tsx

Untranslated strings

  • Tooltip: "No LSP servers"
  • Label suffix: "{connected} LSP" (acronym likely fine; the framing text should be localized)

9) Session Tab Close Tooltip

File: packages/app/src/components/session/session-sortable-tab.tsx

Untranslated strings

  • Tooltip: "Close tab"

Note: you already have common.closeTab.

10) Titlebar Tooltip

File: packages/app/src/components/titlebar.tsx

Untranslated strings

  • "Toggle sidebar"

Note: can likely reuse command.sidebar.toggle.

11) Model Selection "Recent" Group

File: packages/app/src/components/dialog-select-model.tsx

Untranslated / fragile string

  • Hardcoded category name comparisons against "Recent".

Recommendation: introduce a key (e.g. model.group.recent) and ensure both the grouping label and the comparator use the localized label, or replace the comparator with an internal enum.

12) Select Server Dialog Placeholder (Optional)

File: packages/app/src/components/dialog-select-server.tsx

  • Placeholder: http://localhost:4096

This is an example URL; you may choose to keep it as-is even after translating surrounding labels.

Medium Priority: Context Modules

13) OS/Desktop Notifications

File: packages/app/src/context/notification.tsx

Untranslated notification titles / fallback copy

  • "Response ready"
  • "Session error"
  • Fallback description: "An error occurred"

Recommendation: notification.session.* namespace (separate from the permission/question notifications already added).

14) Global Sync (Bootstrap Errors + Toast)

File: packages/app/src/context/global-sync.tsx

Untranslated toast title

  • Failed to load sessions for ${project}

Untranslated fatal init error

  • Could not connect to server. Is there a server running at \${globalSDK.url}`?`

15) File Load Failure Toast (Duplicate)

Files:

  • packages/app/src/context/file.tsx
  • packages/app/src/context/local.tsx

Untranslated toast title

  • "Failed to load file"

Recommendation: create one shared key (e.g. toast.file.loadFailed.title) and reuse it in both contexts.

16) Terminal Naming (Tricky)

File: packages/app/src/context/terminal.tsx

  • User-visible terminal titles are generated as "Terminal" and "Terminal N".
  • There is parsing logic ^Terminal (\d+)$ to compute the next number.

Recommendation:

  • Either keep these English intentionally (stable internal naming), OR
  • Change the data model to store a stable numeric titleNumber and render the localized display label separately.

Low Priority: Utils / Dev-Only Copy

17) Default Attachment Filename

File: packages/app/src/utils/prompt.ts

  • Default filename fallback: "attachment"

Recommendation: common.attachment or prompt.attachment.defaultFilename.

18) Dev-only Root Mount Error

File: packages/app/src/entry.tsx

  • Dev-only error string: "Root element not found..."

This is only thrown in DEV and is more of a developer diagnostic. Optional to translate.

Prioritized Implementation Plan

  1. Small stragglers:
    • packages/app/src/components/session-lsp-indicator.tsx
    • packages/app/src/components/session/session-sortable-tab.tsx
    • packages/app/src/components/titlebar.tsx
    • packages/app/src/components/dialog-select-model.tsx
    • packages/app/src/components/dialog-select-server.tsx (optional URL placeholder)
  2. Context modules:
    • packages/app/src/context/notification.tsx
    • packages/app/src/context/global-sync.tsx
    • packages/app/src/context/file.tsx + packages/app/src/context/local.tsx
    • packages/app/src/utils/prompt.ts
  3. Decide on the terminal naming approach (packages/app/src/context/terminal.tsx).

Suggested Key Naming Conventions

To keep the dictionaries navigable, prefer grouping by surface:

  • error.page.*, error.chain.*
  • prompt.* (including examples, tooltips, empty states, toasts)
  • provider.connect.* (auth flow UI + validation + success)
  • session.share.* (publish/unpublish/copy link)
  • context.usage.* (Tokens/Usage/Cost + call to action)
  • lsp.* (and potentially mcp.* if expanded)
  • notification.session.*
  • toast.file.*, toast.session.*

Also reuse existing command keys for tooltip titles whenever possible (e.g. command.sidebar.toggle, command.review.toggle, command.terminal.toggle).

Appendix: Remaining Files At-a-Glance

Pages:

  • (none)

Components:

  • packages/app/src/components/session-lsp-indicator.tsx
  • packages/app/src/components/session/session-sortable-tab.tsx
  • packages/app/src/components/titlebar.tsx
  • packages/app/src/components/dialog-select-model.tsx
  • packages/app/src/components/dialog-select-server.tsx (optional URL placeholder)

Context:

  • packages/app/src/context/notification.tsx
  • packages/app/src/context/global-sync.tsx
  • packages/app/src/context/file.tsx
  • packages/app/src/context/local.tsx
  • packages/app/src/context/terminal.tsx (naming)

Utils:

  • packages/app/src/utils/prompt.ts
  • packages/app/src/entry.tsx (dev-only)