Skip to content

docs: a book's label and its group labels cannot be translated, so a zh-CN reader sees the book and every sidebar section in the authoring language #26690

Closed

Description

@objectstack-fleet

Filing gate ③ a task the maintainer directed. The maintainer's words, verbatim, in the HotCRM project thread: 「hotcrm 的文档类型元数据还没有好好利用,综合评估一下应该写哪些文档,以及如何挂到菜单上」 (2026-10-27T12:09Z), then, on the evaluation whose step 6 is this card ("platform cards: book-label localization and a doc knowledge source, filed in objectstack"), 「同意,立卡派发。」 and 「立卡,你不需要派发」 (2026-10-27T12:54Z). Evaluation (Chinese): https://claude.ai/artifact/FSRbbgsT8uFhTxYe5jMBvS. Filed from that thread (session_01FEkQ5n3dhGrDN5nEgsJyck). Filed at destination for triage; ⛔ not a claim.

维护者速读

  • 事由: 文档正文可以按语言出(<name>.zh.md),但书名和书里的分组名只能写一种语言。HotCRM 准备给中文用户上「使用手册」,侧栏的分组标题会是英文。
  • 要做: 让书和分组的标题能走翻译(形状由分诊和 spec 车道定,例如进翻译包,和导航项、页面一样)。
  • 完成标准: 一个带中文翻译的书,中文用户在 /apps/<pkg>/docs 侧栏和 GET /meta/book/:name/tree 里看到中文书名和分组名;英文用户不变。

Business reason: a package that ships docs in two languages today shows a half-translated manual: the body follows the reader's locale, the frame does not. HotCRM's in-app docs plan (batch 1 adds crm_manual, crm_admin_manual, crm_revenue_manual) is the first exhibit with zh variants, and every other package with localized docs hits the same frame.

Reader (who acts): objectstack triage (domain:spec for the shape, then the resolver and console consumers). HotCRM is not blocked: its batch-1 card objectstack-ai/hotcrm#2327 ships with group labels in one language until this lands.

Dedupe: objectstack issue search (repo-scoped), queries "localize book label and group labels translations i18n docs portal" and "book label untranslated docs sidebar group label locale", 2026-10-27 → 0 hits about books (closest: #25652 positions and permission sets had no translation key, closed; #24968 page:tabs labels, closed).

Readings (objectstack main 86ae47e1)

Governing text

  • ADR-0049 enforce-or-remove: the retirement was right for an unread key; this card asks for a read path, not for the old key back.
  • BookGroupSchema.label describe: "Section title — first-class, i18n-homed" — the declaration says the label is i18n-homed; no translation path reaches it today.

Done when

  • A book's label and each group's label resolve to the reader's locale on GET /meta/book/:name/tree, the book list, and the console sidebar, through the platform's one translation mechanism (shape decided at triage); a missing translation falls back to the authored string.
  • os i18n extract (or its successor) emits the keys, so a package's locale packs can carry them.

Requested by Leehom · project thread

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — enhancement · priority:p1 · domain:spec · area:i18n · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T14:01Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-27T16:01Z
    Session: session_01WGufzfhobWEgUUrjz4rrbh
    Account: os-support-ai
    Branch: claude/project-thread-g5q3wk (card thread session_01WGufzf4dTFmjsttVz7Pm8j. The platform assigns the thread's branch and the thread can push only that one, so the branch is written as measured instead of claude/issue-26690-<slug>.)
    Worktree: objectstack-issue-26690
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/system/translation.zod.ts (a translation-bundle group for a doc book's label and its group labels) and i18n-resolver.ts (the overlay), the i18n extract (packages/cli/src/utils/i18n-extract.ts), the readers GET /meta/book/:name/tree and the console docs sidebar as the dev measures them, their tests, generated artifacts, the docs and skills lines owed under #26369 B, and changesets. No second translation path. Stop on a breach and explain it in the report.
    Container & model: M, mode:thread, model: TIER_DEFAULT, effort: high
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: n/a. A maintainer-directed task (HotCRM docs evaluation, 「立卡,你不需要派发」 relayed on the card).
    Thread-read: 6443918209
    Premise: holds per the card's readings (a book's label and group labels carry no translation slot); the dev re-reads it at origin/main 7bdff7ec
    Serial constraints cleared: yes. #26619's PR #26786 also edits translation.zod.ts and i18n-resolver.ts, at the action slot. The book group is a different hunk; whichever lands second merges main.
    Ruling-ref: none — triage 6443918209 (p1 protocol addition, under #26368 ruling A)

  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26690,
      "status": "done",
      "branch": "claude/project-thread-g5q3wk",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26819",
      "session": "session_01WGufzf4dTFmjsttVz7Pm8j",
      "premise_still_valid": true,
      "summary": "A doc book's title, description and section titles get a translation slot on the one existing path: a strict `books` group on the shared per-app translation shape (`books.NAME.label`, `.description`, `.groups.KEY.label`), a `translateBook` translator registered in METADATA_DOCUMENT_TRANSLATORS (so GET /meta/book list and item translate on both transports with no further wiring), a translate step in createMetaBookTreeAnswer after the audience gate (RestServer and the runtime dispatcher both supply the i18n service), and `os i18n extract` emitting the keys with coverage bucket `i18n/missing-book`. No inline locale map on the book: the retired `translations` tombstone stays and now names the bundle keys. The console sidebar needed no code change (it reads GET /meta/book with Accept-Language); a console test pins bundle -> served book -> sidebar for zh-CN and en-US. Docs updated (doc-pages, translations, i18n-standard); Skills-docs: follow-up owed (skills/objectstack-i18n SKILL.md group list and its eval file at 0 token headroom). One file outside the listed surface: ui/packages/app-shell TranslationPreview CATEGORY_DEFS is `satisfies Record<TranslationGroup, ...>`, so the first full build failed until a `books` row and its en/zh labels were added.",
      "tests": "Head 1f17d1834, all under os-verify-lock. spec test 735 files / 22021 passed; rest 6498 passed; runtime 7448 passed; cli unit 4938 passed; each package typecheck exit 0. New or extended: spec i18n-book.test.ts 11/11; cli i18n-book-walk.test.ts 4/4; runtime meta-list-projection-parity.test.ts gains zh-CN and en-US book list, item and tree pins on both transports; console docs-portal.bookLocale-26690.test.tsx 2/2 and app-shell TranslationPreview.categories-11765 (with a books row): UI vitest 2 files, 23 passed; app-shell and console type-check exit 0. Ablations, each red then restored with `git diff HEAD` empty: drop `book: translateBook` -> i18n-book 2/11 fail and 3 runtime parity tests fail; replace the tree translate step with the untranslated book -> the tree test fails on both transports; drop `walkBooks(config, out)` -> cli walk 4/4 fail; console adapter serving the untranslated book -> the zh-CN sidebar test fails (the console test reads the built spec, so a source-only translator ablation does not reach it). Full pnpm build 116/116, VERDICT exit 0.",
      "gates": "dispatch-gates --commands: 123; --ran: 123 derived, 123 run, 0 NOT-MEASURED, 0 UNRUN, every exit 0 (check:skill-examples, check:dual-build-cjs-loads, check:i18n-coverage, check:test-source-alias, check:i18n and check:i18n-walk-parity re-run after the full build, all exit 0). The 12 artifact-roster gates whose roster sits in a touched directory: all exit 0. check:generated exit 0; check:liveness exit 0 (translation state counts 38 -> 41). eslint over the 16 touched TS/TSX files: 0 problems. CI check-runs on #26819: pending at report time, not yet citable.",
      "dogfood_battery": "n/a - no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "11 read-only: mcp__github__issue_read x5, mcp__github__get_file_contents x2, mcp__github__list_pull_requests x2, mcp__github__search_issues x2; no MCP write tool",
      "api_writes": "3 relay writes plus git push: fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, with its assignee leg POST /issues/26819/assignees); fleet-write pr_request_reviewers (POST /pulls/26819/requested_reviewers, os-support-ai), one write beyond the three-write budget, made to put the PR in the assignee's review queue; and this os-dev-report comment (POST /issues/26690/comments). The PR body was written once at creation and not patched.",
      "open_questions": [
        {
          "question": "Should MetaBookTreeSources.resolveI18nService (an exported port in @objectstack/rest) be required or optional?",
          "options": [
            "A required (as shipped): every transport must supply it, so none silently serves untranslated labels",
            "B optional: no break for an outside implementer, at the cost of a transport that forgets it serving the authored strings"
          ],
          "recommendation": "A, because both in-repo transports supply it and no outside implementer of the port is known; the contract review can flip it to B with one `?` if the seat reads the port as public."
        }
      ],
      "out_of_scope_findings": [
        "class: c · reach: os lint on a bundle - a typo in a book name or group key under `books` (books.crm_manaul.label) parses clean, raises no translation-target-unknown, and GET /meta/book serves the authored string · evidence: packages/lint/src/validate-translation-references.ts resolves objects, views, pages, actions, apps, dashboards, flows, positions, permissions and reports, with no `books` arm; outside this claim's file surface · dedupe words: translation-target-unknown books, unknown book key lint, i18n target books",
        "carrier: seat 1 · noted, not filed - the synthetic Uncategorized group in resolveBookTree keeps a hardcoded English label (not an authored group, no bundle key); pre-existing, unchanged here"
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T17:48Z

    Supersedes the File surface line of claim 6446870967. Everything else in it stands.

    File surface: everything the claim named, plus packages/lint translation-target-unknown. The lint gains a books.NAME arm (a namedItemGroups row with namesOf('books')) and a groups.KEY sub-leg, with its test and a header line. The surface also takes in ui/packages/app-shell TranslationPreview (its exhaustive group table needs the books row) and the fix for any CI red the new group causes. Stop on a breach and explain it in the report.

    Why: the contract review of PR #26819 (6449452917, PASS) found that a mistyped book name or group key lints clean. The two most recent named groups shipped their lint arm in the same PR (#25701 positions/permissions, #25826 reports), and the lint's own header calls an orphan key actively misleading. So the arm goes in this PR, not a follow-up.

  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T20:39Z

    PR #26819 merged at 031d97a0, which is an ancestor of origin/main. On 31 of the 35 paths the PR touched, the merge tree matches the accepted head 525ae464 byte for byte. The other 4 differ only by main's own hunks, and none of the differing lines touches books:

    A doc book's title, description and section titles are now translatable. They live in the translation bundle at books.NAME.label, books.NAME.description and books.NAME.groups.KEY.label. GET /meta/book (list and item) and GET /meta/book/:name/tree answer in the request locale, so the console's /apps/PKG/docs sidebar follows the reader's language. os i18n extract emits the keys, os i18n check reports i18n/missing-book, and translation-target-unknown refuses a mistyped book name or group key.

    @objectstack/spec, rest, runtime, cli and lint, plus @object-ui/i18n and @object-ui/app-shell, are minor. Clause-②: yes (widening) and Metadata-protocol: added. The card closed through Fixes #26690, and this seat removes pm:dispatched. The skills row is #26820.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsdomain:specenhancementNew feature or requestpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions