| 1 | /** |
| 2 | * Dictionary shapes for the website localization layer (#3091, #4934). |
| 3 | * |
| 4 | * `ChromeDict` covers shared chrome: the newspaper masthead, nav, mobile |
| 5 | * menu, theme toggle, live ticker, footer, and the locale switcher with its |
| 6 | * visible partial-pack badge. `HomeDict` covers the landing page |
| 7 | * (`app/[locale]/page.tsx`). Templates use `{name}` tokens interpolated |
| 8 | * with `fill()` from dictionaries/index.ts — never concatenate translated |
| 9 | * sentences around variables in JSX. |
| 10 | * |
| 11 | * English (`dictionaries/en/`) is the reference shape; every routed locale — |
| 12 | * including Chinese — must define exactly the same keys. Parity is enforced |
| 13 | * by `web/scripts/check-locales.mjs` and `web/lib/i18n/dictionaries.test.ts`. |
| 14 | * A locale without a dictionary falls back to the English one at lookup |
| 15 | * time, so an untranslated string renders English copy — never a key. |
| 16 | * |
| 17 | * Code-owned strings stay out of these dictionaries per docs/VOICE.md: |
| 18 | * "Plan · Work · Operate", "Ask · Auto-Review · Full Access", |
| 19 | * "TUI · exec · web · API", "Codewhale", "GitHub", "Issues", |
| 20 | * `npm install -g codewhale`, `cargo test --locked`, `codewhale exec`, |
| 21 | * package-manager proper nouns, mirror names, and captured media paths. |
| 22 | */ |
| 23 | |
| 24 | export interface ChromeDict { |
| 25 | // --- primary nav labels (components/nav.tsx via lib/i18n/links.ts) --- |
| 26 | navDocs: string; |
| 27 | navStart: string; |
| 28 | navInstall: string; |
| 29 | navFaq: string; |
| 30 | navCommunity: string; |
| 31 | navContribute: string; |
| 32 | |
| 33 | /** |
| 34 | * Bilingual secondary nav labels — the small companion label the |
| 35 | * newspaper masthead sets beside each primary link. |
| 36 | * |
| 37 | * The English edition uses the Han seal pair (文档 / 指引 / …) as an |
| 38 | * editorial device; every other locale supplies its OWN pairing (native |
| 39 | * primary, short English secondary). Never hardcode Han characters at a |
| 40 | * call site — a locale that wants no second label still needs a value |
| 41 | * here, because empty strings are rejected by dictionaries.test.ts. |
| 42 | */ |
| 43 | navDocsSecondary: string; |
| 44 | navStartSecondary: string; |
| 45 | navInstallSecondary: string; |
| 46 | navFaqSecondary: string; |
| 47 | navCommunitySecondary: string; |
| 48 | navContributeSecondary: string; |
| 49 | |
| 50 | /** |
| 51 | * The primary strip: Product / Models / Plugins / Docs. The |
| 52 | * older six (Start, Install, FAQ, Community, Contribute) stay in the |
| 53 | * dictionary for the compact sheet's second group and the footer. |
| 54 | */ |
| 55 | navProduct: string; |
| 56 | navModels: string; |
| 57 | navPlugins: string; |
| 58 | navProductSecondary: string; |
| 59 | navModelsSecondary: string; |
| 60 | navPluginsSecondary: string; |
| 61 | |
| 62 | /** |
| 63 | * Skip-to-content link rendered before the nav in app/[locale]/layout.tsx. |
| 64 | * It sits on EVERY page of EVERY locale, so it belongs to shared chrome — |
| 65 | * leaving it hardcoded is what kept an EN/ZH branch alive in the layout. |
| 66 | */ |
| 67 | skipToContent: string; |
| 68 | |
| 69 | /** aria-label for the primary <nav> landmark (components/nav-links.tsx). */ |
| 70 | navPrimaryAria: string; |
| 71 | /** aria-label for the wordmark link back to the locale home. */ |
| 72 | navHomeAria: string; |
| 73 | |
| 74 | /** Mobile-menu and masthead call to action, e.g. "Install →". */ |
| 75 | installCta: string; |
| 76 | |
| 77 | /** Header account links to the Codewhale app (app.codewhale.net). */ |
| 78 | authSignIn: string; |
| 79 | authRegister: string; |
| 80 | /** aria-label for the header account link group. */ |
| 81 | authGroupAria: string; |
| 82 | |
| 83 | /** Wordmark seal glyph beside the masthead brand (components/seal.tsx). */ |
| 84 | wordmarkSeal: string; |
| 85 | /** Wordmark strapline under the brand, e.g. "any model, on your machine". */ |
| 86 | wordmarkTag: string; |
| 87 | |
| 88 | /** Masthead issue line, e.g. "Issue {date}". */ |
| 89 | issueLabel: string; |
| 90 | /** |
| 91 | * BCP 47 tag used for the masthead weekday via `toLocaleDateString` — not |
| 92 | * rendered copy, but per-locale, so it belongs beside it. Without this the |
| 93 | * masthead date renders in English for every non-Chinese locale. |
| 94 | */ |
| 95 | dateLocale: string; |
| 96 | |
| 97 | /** aria-label on the star-count link, e.g. "GitHub stars". */ |
| 98 | starsAria: string; |
| 99 | /** Star-badge label when the live count is unavailable. */ |
| 100 | githubFallback: string; |
| 101 | |
| 102 | /** Live-ticker seal label (components/ticker.tsx). */ |
| 103 | tickerLiveLabel: string; |
| 104 | /** Live-ticker mono tag beside the seal label, e.g. "LIVE". */ |
| 105 | tickerLiveTag: string; |
| 106 | |
| 107 | /** |
| 108 | * Ticker event verbs — the chrome around the repository's own record. |
| 109 | * Pull-request titles, issue titles, release tags, and contributor handles |
| 110 | * are CONTENT and stay verbatim in every locale; these verbs are copy and |
| 111 | * must be translated. |
| 112 | * |
| 113 | * `tickerReleased` covers `state: "published"`, and `tickerOpened` covers |
| 114 | * both a newly filed issue and an open pull request. There is deliberately |
| 115 | * no draft verb: the strip reports events, and a draft pull request is one |
| 116 | * its author has marked not-ready (components/ticker.tsx `EVENT_STATES`). |
| 117 | */ |
| 118 | tickerMerged: string; |
| 119 | tickerOpened: string; |
| 120 | tickerClosed: string; |
| 121 | tickerReleased: string; |
| 122 | /** |
| 123 | * Mark shown when GitHub itself reports the author as a |
| 124 | * FIRST_TIME_CONTRIBUTOR — the warmest item on the strip, and never our |
| 125 | * inference. Keep it short; it sits inline in a scrolling mono line. |
| 126 | */ |
| 127 | tickerFirstContribution: string; |
| 128 | /** |
| 129 | * By-line template carrying a `{handle}` token, e.g. "by {handle}". The |
| 130 | * handle is typeset in its own element, so a locale may place it anywhere |
| 131 | * (or make it the whole value, as ja/ko do with an honorific suffix). |
| 132 | */ |
| 133 | tickerBy: string; |
| 134 | /** aria-label for the ticker's group landmark. */ |
| 135 | tickerAria: string; |
| 136 | |
| 137 | /** Reasoning trace title-bar label, e.g. "reasoning trace". */ |
| 138 | traceLabel: string; |
| 139 | /** aria-label for the reasoning trace scene tablist. */ |
| 140 | traceTabsAria: string; |
| 141 | |
| 142 | /** Mobile-menu toggle labels. */ |
| 143 | menuOpen: string; |
| 144 | menuClose: string; |
| 145 | |
| 146 | /** Docs theme toggle: the three cycle states. */ |
| 147 | themeAuto: string; |
| 148 | themeLight: string; |
| 149 | themeDark: string; |
| 150 | /** Theme toggle aria-label, e.g. "Docs theme: {mode} (click to cycle)". */ |
| 151 | themeAria: string; |
| 152 | /** Theme toggle title attribute. */ |
| 153 | themeTitle: string; |
| 154 | |
| 155 | // --- footer --- |
| 156 | footerTagline: string; |
| 157 | footerProduct: string; |
| 158 | footerProject: string; |
| 159 | footerDocs: string; |
| 160 | footerGuide: string; |
| 161 | footerInstall: string; |
| 162 | footerModels: string; |
| 163 | footerRuntime: string; |
| 164 | footerFaq: string; |
| 165 | footerIssues: string; |
| 166 | footerContribute: string; |
| 167 | footerLicense: string; |
| 168 | /** Footer link to the terms route, e.g. "Terms". */ |
| 169 | footerTerms: string; |
| 170 | /** Footer link to the privacy route, e.g. "Privacy". */ |
| 171 | footerPrivacy: string; |
| 172 | /** Footer Product-column link to the release record, e.g. "Changelog". */ |
| 173 | footerChangelog: string; |
| 174 | /** Prefix before the canonical-source link, e.g. "Canonical source: ". */ |
| 175 | footerCanonicalSource: string; |
| 176 | /** Separator + label before the releases link, e.g. " · Releases: ". */ |
| 177 | footerReleases: string; |
| 178 | /** Link text for the GitHub releases page. */ |
| 179 | footerReleasesLink: string; |
| 180 | /** Link text for the security-contact mailto. */ |
| 181 | footerSecurity: string; |
| 182 | |
| 183 | /** aria-label for the locale switcher control. */ |
| 184 | switcherLabel: string; |
| 185 | /** Two-locale toggle aria-label, e.g. "Switch to {label}". */ |
| 186 | switcherSwitchTo: string; |
| 187 | /** |
| 188 | * Visible badge marking a partial locale pack in the switcher, e.g. |
| 189 | * "(partial)" — honest scope signal, per the localization quality |
| 190 | * contract. Keep it short. |
| 191 | */ |
| 192 | partialBadge: string; |
| 193 | } |
| 194 | |
| 195 | export interface HomeDict { |
| 196 | /** |
| 197 | * `<title>` and meta description for the locale home route, consumed by |
| 198 | * `generateMetadata` in app/[locale]/layout.tsx. |
| 199 | */ |
| 200 | metaTitle: string; |
| 201 | metaDescription: string; |
| 202 | |
| 203 | /** A complete headline that wraps naturally in each locale. */ |
| 204 | heroTitle: string; |
| 205 | /** |
| 206 | * Hero lede. Carries a `{brand}` token so the brand can be typeset in its |
| 207 | * own span wherever the sentence needs it — the page splits on the token |
| 208 | * instead of concatenating fragments around it. |
| 209 | */ |
| 210 | heroIntro: string; |
| 211 | /** Primary action → /install, e.g. "Get Codewhale". */ |
| 212 | getCodewhale: string; |
| 213 | /** Secondary action → /product, e.g. "Explore the product". */ |
| 214 | exploreProduct: string; |
| 215 | |
| 216 | /** Screenshot caption, first item of the dot chain, e.g. "Terminal preview". */ |
| 217 | shotPreview: string; |
| 218 | /** Screenshot caption, build item with a `{version}` token. */ |
| 219 | shotBuild: string; |
| 220 | /** Screenshot alt text for the current media manifest capture. */ |
| 221 | screenshotAlt: string; |
| 222 | |
| 223 | /** "Latest release {tag}" */ |
| 224 | latestRelease: string; |
| 225 | releaseUnavailable: string; |
| 226 | /** "Source" / "Unreleased" — prepended to `v{version}`. */ |
| 227 | currentSource: string; |
| 228 | sourceCandidate: string; |
| 229 | /** "{count} providers" */ |
| 230 | providerRoutes: string; |
| 231 | /** "released" / "unreleased" — the machine-readable source-state label. */ |
| 232 | publishedRelease: string; |
| 233 | figcaptionSourceCandidate: string; |
| 234 | |
| 235 | /** The running head on the water beside the capture. */ |
| 236 | chapterTerminal: string; |
| 237 | chapterTerminalTitle: string; |
| 238 | |
| 239 | /** What a person gains: heading, lede, and three [title, body] columns. */ |
| 240 | gainHeading: string; |
| 241 | gainLede: string; |
| 242 | gain: [string, string][]; |
| 243 | |
| 244 | /** Models chapter. */ |
| 245 | chapterModels: string; |
| 246 | modelsHeading: string; |
| 247 | modelsBody: string; |
| 248 | /** Three [route kind, description] rows. */ |
| 249 | modelsFacts: [string, string][]; |
| 250 | modelsLink: string; |
| 251 | |
| 252 | startHeading: string; |
| 253 | startLede: string; |
| 254 | startGuideLink: string; |
| 255 | startVocabularyLink: string; |
| 256 | |
| 257 | /** |
| 258 | * Availability chapter: four [surface, status, detail] rows stating what |
| 259 | * is released, what is a development build, and what is not available. |
| 260 | */ |
| 261 | chapterAccount: string; |
| 262 | availabilityHeading: string; |
| 263 | availabilityLede: string; |
| 264 | availability: [string, string, string][]; |
| 265 | availabilityNote: string; |
| 266 | accountLink: string; |
| 267 | |
| 268 | surfacesHeading: string; |
| 269 | /** Five [name, description] surfaces. */ |
| 270 | surfaces: [string, string][]; |
| 271 | runtimeLink: string; |
| 272 | |
| 273 | installBandHeading: string; |
| 274 | copy: string; |
| 275 | copied: string; |
| 276 | binaries: string; |
| 277 | chinaMirrors: string; |
| 278 | installGuideLink: string; |
| 279 | |
| 280 | communityHeading: string; |
| 281 | communityBody: string; |
| 282 | communityLinksAria: string; |
| 283 | contribute: string; |
| 284 | } |
| 285 | |
| 286 | /** |
| 287 | * Docs "Getting started" page (`app/[locale]/docs/guide/page.tsx`). |
| 288 | * |
| 289 | * First of the per-page dictionaries that retire the page-body `isZh` |
| 290 | * branches left after #4934. Page dictionaries are optional per locale: |
| 291 | * English is the required reference, any other locale that ships the file |
| 292 | * is held to exact key parity (`check-locales.mjs` OPTIONAL_FILES), and a |
| 293 | * locale without it falls back to English at lookup time — matching how |
| 294 | * page bodies already behave for partial locales. |
| 295 | */ |
| 296 | export interface DocsGuideDict { |
| 297 | metaTitle: string; |
| 298 | metaDescription: string; |
| 299 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 300 | bodyClassName: string; |
| 301 | overviewTitle: string; |
| 302 | overviewLead: string; |
| 303 | sessionTitle: string; |
| 304 | sessionLead: string; |
| 305 | nextTitle: string; |
| 306 | sourceNote: string; |
| 307 | } |
| 308 | |
| 309 | /** |
| 310 | * The docs shell: the portal hero in `app/[locale]/docs/layout.tsx` that |
| 311 | * wraps every docs page, plus the metadata of the hub page it frames |
| 312 | * (`app/[locale]/docs/page.tsx`, whose body is the `DocsSearch` component). |
| 313 | * |
| 314 | * No `bodyClassName` here: the hero typesets through `portal-*` classes, |
| 315 | * which never varied by locale. |
| 316 | */ |
| 317 | export interface DocsShellDict { |
| 318 | metaTitle: string; |
| 319 | metaDescription: string; |
| 320 | portalMark: string; |
| 321 | heroTitle: string; |
| 322 | heroLead: string; |
| 323 | installCta: string; |
| 324 | sourceDocsCta: string; |
| 325 | |
| 326 | // --- release truth band (docs layout; facts + CHANGELOG.md) --- |
| 327 | /** Eyebrow over the band, e.g. "Release truth". */ |
| 328 | releaseLabel: string; |
| 329 | /** "Latest release {tag} · {date}" — date already formatted per locale. */ |
| 330 | releasePublished: string; |
| 331 | /** Shown while the source candidate is ahead of the published release. */ |
| 332 | releaseCandidate: string; |
| 333 | /** Shown when the pages describe exactly the published release. */ |
| 334 | releaseMatches: string; |
| 335 | /** Link to the /changelog route. */ |
| 336 | releaseChangelog: string; |
| 337 | |
| 338 | // --- task/topic search (components/docs-search.tsx) --- |
| 339 | searchLabel: string; |
| 340 | searchPlaceholder: string; |
| 341 | searchClear: string; |
| 342 | /** "{matched} of {total} entries match “{query}”". */ |
| 343 | searchMatches: string; |
| 344 | /** "Nothing matches “{query}”". */ |
| 345 | searchNoMatches: string; |
| 346 | tasksHeading: string; |
| 347 | tasksLead: string; |
| 348 | topicsHeading: string; |
| 349 | /** Row tag for a first-party page. */ |
| 350 | webGuideTag: string; |
| 351 | /** Row tag for a GitHub source document. */ |
| 352 | sourceDocTag: string; |
| 353 | emptyTitle: string; |
| 354 | emptyBody: string; |
| 355 | emptyCta: string; |
| 356 | indexNote: string; |
| 357 | |
| 358 | // --- sidebar and breadcrumb (components/docs-sidebar.tsx, docs-breadcrumb.tsx) --- |
| 359 | sidebarHeading: string; |
| 360 | sidebarAria: string; |
| 361 | breadcrumbAria: string; |
| 362 | breadcrumbHome: string; |
| 363 | breadcrumbDocs: string; |
| 364 | |
| 365 | // --- contextual help band under every docs page --- |
| 366 | helpTitle: string; |
| 367 | helpLead: string; |
| 368 | /** "Source: {name}" — the topic's repository document(s). */ |
| 369 | helpSource: string; |
| 370 | helpTroubleshooting: string; |
| 371 | helpFaq: string; |
| 372 | helpDiscord: string; |
| 373 | helpIssue: string; |
| 374 | } |
| 375 | |
| 376 | /** |
| 377 | * Shared surface states (`components/surface-state.tsx`, |
| 378 | * `components/connection-banner.tsx`, the `loading.tsx` / `error.tsx` / |
| 379 | * `not-found.tsx` boundaries). One dictionary for every empty, loading, |
| 380 | * error, retry, recovery, and connection state so no page invents its own. |
| 381 | */ |
| 382 | export interface StatesDict { |
| 383 | loadingLabel: string; |
| 384 | emptyTitle: string; |
| 385 | emptyBody: string; |
| 386 | errorTitle: string; |
| 387 | errorBody: string; |
| 388 | retry: string; |
| 389 | reload: string; |
| 390 | homeLink: string; |
| 391 | /** The 404 plate's primary action: the docs index, which the body names. */ |
| 392 | docsIndexLink: string; |
| 393 | notFoundTitle: string; |
| 394 | notFoundBody: string; |
| 395 | /** |
| 396 | * A data-bearing page whose source was not asked (build-time prerender) |
| 397 | * or refused (rate limit, outage). Distinct from `empty`, which asserts |
| 398 | * that nothing exists, and from `error`, which means the render threw. |
| 399 | */ |
| 400 | unavailableTitle: string; |
| 401 | unavailableBody: string; |
| 402 | /** Connection banner (typed state in lib/connection-state.ts). */ |
| 403 | offlineTitle: string; |
| 404 | offlineBody: string; |
| 405 | reconnectingTitle: string; |
| 406 | /** "Checking the connection (attempt {attempt})." */ |
| 407 | reconnectingBody: string; |
| 408 | degradedTitle: string; |
| 409 | degradedBody: string; |
| 410 | onlineTitle: string; |
| 411 | onlineBody: string; |
| 412 | retryNow: string; |
| 413 | dismiss: string; |
| 414 | /** "Last checked {time}". */ |
| 415 | lastChecked: string; |
| 416 | } |
| 417 | |
| 418 | /** |
| 419 | * `app/[locale]/docs/computers/page.tsx` — cloud computers and dispatch. |
| 420 | * Every claim traces to docs/DAYTONA_CLOUD_DISPATCH.md and |
| 421 | * docs/CODEWHALE_AGENT.md; commands stay code-owned literals in the page. |
| 422 | */ |
| 423 | export interface DocsComputersDict { |
| 424 | metaTitle: string; |
| 425 | metaDescription: string; |
| 426 | bodyClassName: string; |
| 427 | overviewTitle: string; |
| 428 | overviewLead: string; |
| 429 | proposeTitle: string; |
| 430 | proposeLead: string; |
| 431 | jobsLead: string; |
| 432 | remotesTitle: string; |
| 433 | remotesLead: string; |
| 434 | /** `[remote name, forge]` rows of the explicit-forge table. */ |
| 435 | remotes: [string, string][]; |
| 436 | enableTitle: string; |
| 437 | enableLead: string; |
| 438 | /** `[step, detail]` rows. */ |
| 439 | enableSteps: [string, string][]; |
| 440 | cliNote: string; |
| 441 | rulesTitle: string; |
| 442 | /** `[situation, outcome]` rows of the fail-closed table. */ |
| 443 | rules: [string, string][]; |
| 444 | membershipTitle: string; |
| 445 | membershipLead: string; |
| 446 | leftoverTitle: string; |
| 447 | /** `[item, note]` rows. */ |
| 448 | leftover: [string, string][]; |
| 449 | sourceNote: string; |
| 450 | } |
| 451 | |
| 452 | /** |
| 453 | * `app/[locale]/docs/auth/page.tsx` — account, sign-in, and key storage. |
| 454 | * Claims trace to docs/CONFIGURATION.md, docs/CODEWHALE_AGENT.md, and |
| 455 | * docs/PROVIDERS.md. |
| 456 | */ |
| 457 | export interface DocsAuthDict { |
| 458 | metaTitle: string; |
| 459 | metaDescription: string; |
| 460 | bodyClassName: string; |
| 461 | overviewTitle: string; |
| 462 | overviewLead: string; |
| 463 | /** `[credential, role]` rows. */ |
| 464 | credentials: [string, string][]; |
| 465 | providerTitle: string; |
| 466 | providerLead: string; |
| 467 | accountTitle: string; |
| 468 | accountLead: string; |
| 469 | /** `[command, effect]` rows. */ |
| 470 | accountCommands: [string, string][]; |
| 471 | storageTitle: string; |
| 472 | storageLead: string; |
| 473 | vaultTitle: string; |
| 474 | vaultLead: string; |
| 475 | portableTitle: string; |
| 476 | portableLead: string; |
| 477 | appTitle: string; |
| 478 | appLead: string; |
| 479 | appSignIn: string; |
| 480 | appRegister: string; |
| 481 | sourceNote: string; |
| 482 | } |
| 483 | |
| 484 | /** |
| 485 | * `app/[locale]/docs/trust/page.tsx` — security and trust reference. |
| 486 | * Claims trace to docs/SANDBOX.md, docs/AUTHORIZATION_ORDER.md, |
| 487 | * docs/TELEMETRY.md, and docs/public-surface-facts.json. |
| 488 | */ |
| 489 | export interface DocsTrustDict { |
| 490 | metaTitle: string; |
| 491 | metaDescription: string; |
| 492 | bodyClassName: string; |
| 493 | overviewTitle: string; |
| 494 | overviewLead: string; |
| 495 | boundaryTitle: string; |
| 496 | /** `[boundary, statement]` rows. */ |
| 497 | boundaries: [string, string][]; |
| 498 | approvalTitle: string; |
| 499 | approvalLead: string; |
| 500 | sandboxTitle: string; |
| 501 | sandboxLead: string; |
| 502 | /** `[platform, behaviour]` rows. */ |
| 503 | sandboxes: [string, string][]; |
| 504 | sandboxNote: string; |
| 505 | telemetryTitle: string; |
| 506 | telemetryLead: string; |
| 507 | /** `[fact, detail]` rows. */ |
| 508 | telemetry: [string, string][]; |
| 509 | auditTitle: string; |
| 510 | auditLead: string; |
| 511 | reportTitle: string; |
| 512 | reportLead: string; |
| 513 | reportCta: string; |
| 514 | sourceNote: string; |
| 515 | } |
| 516 | |
| 517 | /** `app/[locale]/changelog/page.tsx` — version-aware release record. */ |
| 518 | export interface ChangelogDict { |
| 519 | metaTitle: string; |
| 520 | metaDescription: string; |
| 521 | kicker: string; |
| 522 | title: string; |
| 523 | lead: string; |
| 524 | publishedLabel: string; |
| 525 | /** "{tag} · published {date}" */ |
| 526 | publishedValue: string; |
| 527 | candidateLabel: string; |
| 528 | /** "{version} · unreleased" */ |
| 529 | candidateValue: string; |
| 530 | /** Shown when the candidate equals the published release. */ |
| 531 | candidateMatches: string; |
| 532 | releasesLink: string; |
| 533 | unreleasedHeading: string; |
| 534 | unreleasedNote: string; |
| 535 | compareLink: string; |
| 536 | releasePageLink: string; |
| 537 | /** "{shown} of {total} entries" */ |
| 538 | moreEntries: string; |
| 539 | fullNotes: string; |
| 540 | /** "Full notes for {version}" — per-release deep link into CHANGELOG.md. */ |
| 541 | releaseNotesLink: string; |
| 542 | emptyTitle: string; |
| 543 | emptyBody: string; |
| 544 | } |
| 545 | |
| 546 | /** |
| 547 | * `app/[locale]/docs/hooks/page.tsx`. |
| 548 | * |
| 549 | * `configIntro` carries three `{token}` placeholders for the literal |
| 550 | * `[[hooks.hooks]]`, `/hooks` and `[hooks].enabled` spans the page typesets |
| 551 | * as inline `<code>`. They stay out of the prose because they are config |
| 552 | * syntax rather than copy, and the token-parity half of `check-locales.mjs` |
| 553 | * then guards the sentence for free. |
| 554 | */ |
| 555 | export interface DocsHooksDict { |
| 556 | metaTitle: string; |
| 557 | metaDescription: string; |
| 558 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 559 | bodyClassName: string; |
| 560 | overviewTitle: string; |
| 561 | overviewLead: string; |
| 562 | configIntro: string; |
| 563 | /** Lifecycle events as `[name, detail]`, in the order the page lists them. */ |
| 564 | events: [string, string][]; |
| 565 | projectTitle: string; |
| 566 | projectLead: string; |
| 567 | sourceNote: string; |
| 568 | } |
| 569 | |
| 570 | /** `app/[locale]/docs/troubleshooting/page.tsx`. */ |
| 571 | export interface DocsTroubleshootingDict { |
| 572 | metaTitle: string; |
| 573 | metaDescription: string; |
| 574 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 575 | bodyClassName: string; |
| 576 | overviewTitle: string; |
| 577 | overviewLead: string; |
| 578 | /** Triage entries as `[name, detail]`, in the order the page lists them. */ |
| 579 | incidents: [string, string][]; |
| 580 | dockerTitle: string; |
| 581 | dockerLead: string; |
| 582 | dockerToolboxNote: string; |
| 583 | sourceNote: string; |
| 584 | } |
| 585 | |
| 586 | /** `app/[locale]/docs/configuration/page.tsx`. */ |
| 587 | export interface DocsConfigurationDict { |
| 588 | metaTitle: string; |
| 589 | metaDescription: string; |
| 590 | bodyClassName: string; |
| 591 | overviewTitle: string; |
| 592 | overviewLead: string; |
| 593 | auditLead: string; |
| 594 | overlayTitle: string; |
| 595 | overlayLead: string; |
| 596 | overlayLimits: string; |
| 597 | credentialsTitle: string; |
| 598 | credentialsLead: string; |
| 599 | legacyTitle: string; |
| 600 | legacyLead: string; |
| 601 | sourceNote: string; |
| 602 | } |
| 603 | |
| 604 | /** |
| 605 | * `app/[locale]/docs/constitution/page.tsx`. |
| 606 | * |
| 607 | * `overviewLead` carries three `{token}` placeholders and `authorityNote` one |
| 608 | * more. Per `docs/VOICE.md` — keep commands, key names and paths as code-owned |
| 609 | * placeholders — the literals themselves live in the page, along with the |
| 610 | * en/zh badge pair on each principle row, which is a fixed bilingual glyph |
| 611 | * rather than copy. |
| 612 | */ |
| 613 | export interface DocsConstitutionDict { |
| 614 | metaTitle: string; |
| 615 | metaDescription: string; |
| 616 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 617 | bodyClassName: string; |
| 618 | overviewTitle: string; |
| 619 | /** Opposite-language echo the heading prints beside the title. */ |
| 620 | overviewTitleAside: string; |
| 621 | overviewLead: string; |
| 622 | /** Three `[key, detail]` rows; the key selects the page's badge pair. */ |
| 623 | principles: [string, string][]; |
| 624 | authorityNote: string; |
| 625 | /** Link text inside `authorityNote`'s `{configDocs}` slot. */ |
| 626 | configDocsLabel: string; |
| 627 | sourceNote: string; |
| 628 | } |
| 629 | |
| 630 | /** `app/[locale]/docs/fleet/page.tsx` (the `DocsFleetDict` name is internal compatibility). */ |
| 631 | export interface DocsFleetDict { |
| 632 | metaTitle: string; |
| 633 | metaDescription: string; |
| 634 | bodyClassName: string; |
| 635 | overviewTitle: string; |
| 636 | overviewLead: string; |
| 637 | runTitle: string; |
| 638 | runLead: string; |
| 639 | statusLead: string; |
| 640 | profilesTitle: string; |
| 641 | profilesLead: string; |
| 642 | workflowTitle: string; |
| 643 | workflowLead: string; |
| 644 | workflowLimits: string; |
| 645 | sourceNote: string; |
| 646 | } |
| 647 | |
| 648 | /** `app/[locale]/docs/mcp/page.tsx`. */ |
| 649 | export interface DocsMcpDict { |
| 650 | metaTitle: string; |
| 651 | metaDescription: string; |
| 652 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 653 | bodyClassName: string; |
| 654 | overviewLead: string; |
| 655 | overviewConfig: string; |
| 656 | setupTitle: string; |
| 657 | setupLead: string; |
| 658 | setupReload: string; |
| 659 | authTitle: string; |
| 660 | authLead: string; |
| 661 | toolsTitle: string; |
| 662 | toolsLead: string; |
| 663 | toolsTrust: string; |
| 664 | serverTitle: string; |
| 665 | serverLead: string; |
| 666 | sourceNote: string; |
| 667 | } |
| 668 | |
| 669 | /** `app/[locale]/docs/modes/page.tsx`. */ |
| 670 | export interface DocsModesDict { |
| 671 | metaTitle: string; |
| 672 | metaDescription: string; |
| 673 | bodyClassName: string; |
| 674 | overviewTitle: string; |
| 675 | overviewLead: string; |
| 676 | modes: [string, string][]; |
| 677 | switchingTitle: string; |
| 678 | switchingLead: string; |
| 679 | switchingCommandLead: string; |
| 680 | permissionsTitle: string; |
| 681 | permissionsLead: string; |
| 682 | postures: [string, string][]; |
| 683 | sourceNote: string; |
| 684 | } |
| 685 | |
| 686 | /** |
| 687 | * `app/[locale]/docs/runtime-api/page.tsx`. |
| 688 | * |
| 689 | * Only `securityLead` is tokenized. The command names elsewhere on the page |
| 690 | * are set as prose rather than `<code>`, so they stay inside the sentences |
| 691 | * exactly as the `isZh` ternaries had them. |
| 692 | */ |
| 693 | export interface DocsRuntimeApiDict { |
| 694 | metaTitle: string; |
| 695 | metaDescription: string; |
| 696 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 697 | bodyClassName: string; |
| 698 | overviewTitle: string; |
| 699 | overviewLead: string; |
| 700 | /** Seven `[key, detail]` rows; the key selects the page's command literal. */ |
| 701 | entries: [string, string][]; |
| 702 | stdioTitle: string; |
| 703 | stdioLead: string; |
| 704 | interruptNote: string; |
| 705 | securityTitle: string; |
| 706 | securityLead: string; |
| 707 | sourceNote: string; |
| 708 | } |
| 709 | |
| 710 | export interface DocsSandboxDict { |
| 711 | metaTitle: string; |
| 712 | metaDescription: string; |
| 713 | bodyClassName: string; |
| 714 | overviewTitle: string; |
| 715 | overviewLead: string; |
| 716 | /** Four `[name, detail]` rows; the name is also the row's key. */ |
| 717 | platforms: [string, string][]; |
| 718 | policiesTitle: string; |
| 719 | policiesLead: string; |
| 720 | diagnosticsTitle: string; |
| 721 | diagnosticsLead: string; |
| 722 | diagnosticsLimits: string; |
| 723 | sourceNote: string; |
| 724 | } |
| 725 | |
| 726 | /** `app/[locale]/docs/subagents/page.tsx`. */ |
| 727 | export interface DocsSubagentsDict { |
| 728 | metaTitle: string; |
| 729 | metaDescription: string; |
| 730 | /** Body-copy typography for this locale (CJK needs looser leading). */ |
| 731 | bodyClassName: string; |
| 732 | overviewTitle: string; |
| 733 | overviewLead: string; |
| 734 | overviewFleetNote: string; |
| 735 | /** Eight `[key, detail]` rows; the key names the page's role literal. */ |
| 736 | roles: [string, string][]; |
| 737 | forkTitle: string; |
| 738 | forkLead: string; |
| 739 | worktreeTitle: string; |
| 740 | worktreeLead: string; |
| 741 | capacityTitle: string; |
| 742 | capacityLead: string; |
| 743 | sourceNote: string; |
| 744 | } |
| 745 | |
| 746 | export interface DocsWebDict { |
| 747 | metaTitle: string; |
| 748 | metaDescription: string; |
| 749 | bodyClassName: string; |
| 750 | overviewTitle: string; |
| 751 | overviewLead: string; |
| 752 | overviewBody: string; |
| 753 | authTitle: string; |
| 754 | authLead: string; |
| 755 | localTitle: string; |
| 756 | localLead: string; |
| 757 | /** Remote control of a running local session from the signed-in web app. */ |
| 758 | remoteTitle: string; |
| 759 | remoteLead: string; |
| 760 | remoteBody: string; |
| 761 | troubleshootingTitle: string; |
| 762 | troubleshootingLead: string; |
| 763 | sourceNote: string; |
| 764 | } |
| 765 | |
| 766 | /** Copy for `app/[locale]/computer-use/page.tsx` and the install page's Computer Use section. */ |
| 767 | export interface ComputerUseDict { |
| 768 | metaTitle: string; |
| 769 | metaDescription: string; |
| 770 | title: string; |
| 771 | lead: string; |
| 772 | publisher: string; |
| 773 | /** Primary button: the notarized disk image when the release carries one, else the archive. */ |
| 774 | download: string; |
| 775 | /** Secondary link to the archive the in-app updater consumes. */ |
| 776 | downloadZip: string; |
| 777 | requirements: string; |
| 778 | included: string; |
| 779 | pendingTitle: string; |
| 780 | pendingBody: string; |
| 781 | unavailableTitle: string; |
| 782 | unavailableBody: string; |
| 783 | releases: string; |
| 784 | receipt: string; |
| 785 | setup: string; |
| 786 | /** Four numbered setup steps, rendered in order. */ |
| 787 | steps: { title: string; body: string }[]; |
| 788 | controlsTitle: string; |
| 789 | controlsBody: string; |
| 790 | updateTitle: string; |
| 791 | updateBody: string; |
| 792 | help: string; |
| 793 | notes: string; |
| 794 | demo: string; |
| 795 | source: string; |
| 796 | platforms: string; |
| 797 | installTitle: string; |
| 798 | installLead: string; |
| 799 | installLink: string; |
| 800 | } |
| 801 |