Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
7b4fd19
docs: SEO titles for the 67 English pages whose title tag was two wor…
objectstack-fleet[bot] Oct 6, 2026
50f7841
Merge remote-tracking branch 'origin/main' into ff/issue-301
claude Oct 6, 2026
b421fbd
docs: muted-text and code-comment contrast, phone table affordance, F…
claude Oct 6, 2026
c5740f9
docs: record the measured search cold start and the smoke search requ…
claude Oct 6, 2026
21ef209
docs: state the measured contrast ratios in the theme and code-theme …
claude Oct 6, 2026
911a174
docs(views): declare views in a defineView container; list only the s…
claude Oct 6, 2026
c49dc6d
Merge remote-tracking branch 'origin/main' into ff/issue-311
claude Oct 6, 2026
5e666c3
fix(docs): run the awaited fumadocs-mdx write after next typegen in t…
claude Oct 6, 2026
5ad14ce
Merge remote-tracking branch 'origin/main' into ff/issue-305
claude Oct 6, 2026
41a1994
docs: localize fumadocs' accessible names, mark English page-tree ent…
claude Oct 6, 2026
c47c544
Merge remote-tracking branch 'origin/main' into ff/issue-307
claude Oct 6, 2026
69f7f1e
docs: make the views and flows code samples parse with @objectstack/s…
claude Oct 6, 2026
9709c50
Merge remote-tracking branch 'origin/main' into ff/issue-308
claude Oct 6, 2026
7c161c3
docs: a main landmark, a language switcher named by its text, a decor…
claude Oct 6, 2026
cc14430
ci: read the built pages for English chrome names and unmarked page-t…
claude Oct 6, 2026
77ad6ba
docs: the docs page's table-of-contents bar is not a second banner
claude Oct 6, 2026
5a07fbc
docs: the heading-anchor and code-copy buttons keep their own languag…
claude Oct 6, 2026
fa2390f
ci: the built-pages guard counts docs pages only
claude Oct 6, 2026
f8920d5
Merge remote-tracking branch 'origin/main' into ff/issue-312
claude Oct 6, 2026
482ff8f
docs: legal pages mark their English fallback lang="en" with the noti…
claude Oct 6, 2026
7c17974
docs: legal pages render an article inside HomeLayout's main, not a s…
claude Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 285 additions & 3 deletions .github/scripts/check-locale-surface.mjs

Large diffs are not rendered by default.

66 changes: 35 additions & 31 deletions apps/docs/app/[lang]/privacy/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { Callout } from 'fumadocs-ui/components/callout';
import { baseOptions } from '@/lib/layout.shared';
import { staticPageMetadata } from '@/lib/seo';
import { i18n } from '@/lib/i18n';
import { uiText } from '@/lib/ui-text';
import zhHans from './zh-Hans.json';
import zhHant from './zh-Hant.json';

/**
* This page's copy, one entry per locale it is written in. English is written
* here. The Simplified entry is `zh-Hans.json`, and `zh-Hant.json` is GENERATED
* from it by `scripts/gen-zh-hant.mjs` (OpenCC `s2twp`, the converter behind
* every other zh-Hant string on this site), so never edit it by hand: CI runs
* `gen-zh-hant --check`. Both are JSON because that generator converts a data
* file, the same reason `lib/ui-text/` is JSON.
*/
const content = {
en: {
title: 'Privacy Policy',
Expand All @@ -29,30 +42,8 @@ const content = {
],
back: '← Back to home',
},
'zh-Hans': {
title: '隐私政策',
description: 'ObjectStack AI LLC 从公开网站和托管账号收集哪些信息,以及不会收集的自管部署内部数据。',
updated: '最近更新:2026 年 10 月 6 日',
body: [
{
heading: '概述',
text: 'ObjectOS 以托管方式运行(ObjectOS Cloud),或由你自管部署在自己的基础设施中(ObjectOS Enterprise)。当你在自己的基础设施中自管运行 ObjectOS 时,ObjectStack AI LLC 不会收集、存储或处理流经你部署的数据。ObjectOS Cloud 的数据处理,受其在你注册时呈现的服务协议约束。本政策仅描述你访问我们的公开网站(objectstack.ai、docs.objectstack.ai)及任选的云服务时,我们所收集的有限信息。',
},
{
heading: '我们会收集什么',
text: '我们会出于安全与运营目的,收集公开网站的标准请求日志(IP、User-Agent、Referer、请求 URL)。若你在我们运营的托管服务上注册账号,我们会收集你为完成登录而提供的身份标识与凭证。',
},
{
heading: '我们不会收集什么',
text: '我们不会收集自管 ObjectOS 部署(ObjectOS Enterprise)内部的数据,也不会收集开源 ObjectStack 运行时部署内部的数据;你的应用数据始终留在你自己运营的边界内。ObjectOS Self-Managed 会在线校验许可证(Enterprise 隔离网络许可证为离线校验);开源的 ObjectStack 运行时没有遥测、没有许可证校验、没有更新探活。',
},
{
heading: '联系方式',
text: '隐私相关问题请联系 privacy@objectstack.ai。',
},
],
back: '← 返回首页',
},
'zh-Hans': zhHans,
'zh-Hant': zhHant,
};

/**
Expand Down Expand Up @@ -87,27 +78,40 @@ export default async function PrivacyPage({
params: Promise<{ lang: string }>;
}) {
const { lang } = await params;
const t = content[lang as keyof typeof content] ?? content.en;
// Any other locale is served the English entry. That text is English inside
// `<html lang="LOCALE">`, so it is marked `lang="en"` and introduced by the
// notice docs pages show on a fallback (#298), in the route locale and before
// the English it describes. An English or written page is unchanged.
const isFallback = !Object.hasOwn(content, lang);
const t = isFallback ? content.en : content[lang as keyof typeof content];
const contentLang = isFallback ? i18n.defaultLanguage : undefined;

return (
<HomeLayout {...baseOptions(lang)} i18n>
<main className="mx-auto w-full max-w-3xl px-4 py-16 sm:py-24">
<h1 className="text-3xl sm:text-4xl font-bold tracking-tight mb-2">{t.title}</h1>
<p className="text-sm text-foreground/60 mb-12">{t.updated}</p>
<div className="space-y-8">
{/* An article, not a main: HomeLayout already renders main#nd-home-layout
around this, and a second main nested in it is a duplicate landmark. */}
<article className="mx-auto w-full max-w-3xl px-4 py-16 sm:py-24">
{isFallback && (
<Callout type="info" role="note" className="mt-0 mb-8" data-untranslated-notice="">
{uiText(lang).notTranslated}
</Callout>
)}
<h1 lang={contentLang} className="text-3xl sm:text-4xl font-bold tracking-tight mb-2">{t.title}</h1>
<p lang={contentLang} className="text-sm text-foreground/60 mb-12">{t.updated}</p>
<div lang={contentLang} className="space-y-8">
{t.body.map((s) => (
<section key={s.heading}>
<h2 className="text-xl font-semibold mb-3">{s.heading}</h2>
<p className="text-foreground/80 leading-relaxed">{s.text}</p>
</section>
))}
</div>
<div className="mt-16 pt-8 border-t border-border/60">
<div lang={contentLang} className="mt-16 pt-8 border-t border-border/60">
<Link href={`/${lang}`} className="text-sm text-primary hover:underline">
{t.back}
</Link>
</div>
</main>
</article>
</HomeLayout>
);
}
24 changes: 24 additions & 0 deletions apps/docs/app/[lang]/privacy/zh-Hans.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"title": "隐私政策",
"description": "ObjectStack AI LLC 从公开网站和托管账号收集哪些信息,以及不会收集的自管部署内部数据。",
"updated": "最近更新:2026 年 10 月 6 日",
"body": [
{
"heading": "概述",
"text": "ObjectOS 以托管方式运行(ObjectOS Cloud),或由你自管部署在自己的基础设施中(ObjectOS Enterprise)。当你在自己的基础设施中自管运行 ObjectOS 时,ObjectStack AI LLC 不会收集、存储或处理流经你部署的数据。ObjectOS Cloud 的数据处理,受其在你注册时呈现的服务协议约束。本政策仅描述你访问我们的公开网站(objectstack.ai、docs.objectstack.ai)及任选的云服务时,我们所收集的有限信息。"
},
{
"heading": "我们会收集什么",
"text": "我们会出于安全与运营目的,收集公开网站的标准请求日志(IP、User-Agent、Referer、请求 URL)。若你在我们运营的托管服务上注册账号,我们会收集你为完成登录而提供的身份标识与凭证。"
},
{
"heading": "我们不会收集什么",
"text": "我们不会收集自管 ObjectOS 部署(ObjectOS Enterprise)内部的数据,也不会收集开源 ObjectStack 运行时部署内部的数据;你的应用数据始终留在你自己运营的边界内。ObjectOS Self-Managed 会在线校验许可证(Enterprise 隔离网络许可证为离线校验);开源的 ObjectStack 运行时没有遥测、没有许可证校验、没有更新探活。"
},
{
"heading": "联系方式",
"text": "隐私相关问题请联系 privacy@objectstack.ai。"
}
],
"back": "← 返回首页"
}
24 changes: 24 additions & 0 deletions apps/docs/app/[lang]/privacy/zh-Hant.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"title": "隱私政策",
"description": "ObjectStack AI LLC 從公開網站和託管賬號收集哪些資訊,以及不會收集的自管部署內部資料。",
"updated": "最近更新:2026 年 10 月 6 日",
"body": [
{
"heading": "概述",
"text": "ObjectOS 以託管方式執行(ObjectOS Cloud),或由你自管部署在自己的基礎設施中(ObjectOS Enterprise)。當你在自己的基礎設施中自管執行 ObjectOS 時,ObjectStack AI LLC 不會收集、儲存或處理流經你部署的資料。ObjectOS Cloud 的資料處理,受其在你註冊時呈現的服務協議約束。本政策僅描述你訪問我們的公開網站(objectstack.ai、docs.objectstack.ai)及任選的雲服務時,我們所收集的有限資訊。"
},
{
"heading": "我們會收集什麼",
"text": "我們會出於安全與運營目的,收集公開網站的標準請求日誌(IP、User-Agent、Referer、請求 URL)。若你在我們運營的託管服務上註冊賬號,我們會收集你為完成登入而提供的身份標識與憑證。"
},
{
"heading": "我們不會收集什麼",
"text": "我們不會收集自管 ObjectOS 部署(ObjectOS Enterprise)內部的資料,也不會收集開源 ObjectStack 執行時部署內部的資料;你的應用資料始終留在你自己運營的邊界內。ObjectOS Self-Managed 會線上校驗許可證(Enterprise 隔離網路許可證為離線校驗);開源的 ObjectStack 執行時沒有遙測、沒有許可證校驗、沒有更新探活。"
},
{
"heading": "聯絡方式",
"text": "隱私相關問題請聯絡 privacy@objectstack.ai。"
}
],
"back": "← 返回首頁"
}
70 changes: 35 additions & 35 deletions apps/docs/app/[lang]/terms/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import type { Metadata } from 'next';
import Link from 'next/link';
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { Callout } from 'fumadocs-ui/components/callout';
import { baseOptions } from '@/lib/layout.shared';
import { staticPageMetadata } from '@/lib/seo';
import { i18n } from '@/lib/i18n';
import { uiText } from '@/lib/ui-text';
import zhHans from './zh-Hans.json';
import zhHant from './zh-Hant.json';

/**
* This page's copy, one entry per locale it is written in. English is written
* here. The Simplified entry is `zh-Hans.json`, and `zh-Hant.json` is GENERATED
* from it by `scripts/gen-zh-hant.mjs` (OpenCC `s2twp`, the converter behind
* every other zh-Hant string on this site), so never edit it by hand: CI runs
* `gen-zh-hant --check`. Both are JSON because that generator converts a data
* file, the same reason `lib/ui-text/` is JSON.
*/
const content = {
en: {
title: 'Terms of Service',
Expand Down Expand Up @@ -33,34 +46,8 @@ const content = {
],
back: '← Back to home',
},
'zh-Hans': {
title: '服务条款',
description: 'ObjectOS 各版本的许可方式、本站内容采用的 Apache-2.0 许可、ObjectOS 商标,以及自管部署的责任归属。',
updated: '最近更新:2026 年 10 月 6 日',
body: [
{
heading: '许可',
text: 'ObjectOS 是商业产品,没有开源版本。你对 ObjectOS 的使用,受你所使用版本(ObjectOS Cloud 或 ObjectOS Enterprise)的许可协议或服务协议约束。本文档站点所在仓库的内容(文档与站点代码)以 Apache License 2.0 授权;开源的 ObjectStack 框架及其运行时在其自己的仓库中以 Apache License 2.0 授权。"ObjectOS" 名称与 Logo 为 ObjectStack AI LLC 的商标,不在 Apache 2.0 的授权范围内 —— 详见仓库内的 TRADEMARK.md。',
},
{
heading: '自托管部署',
text: '当你在自己的基础设施中自管运行 ObjectOS(ObjectOS Enterprise)时,该部署的运行、安全、可用性、备份与合规性,完全由你自行负责;除你的商业协议明文约定外,ObjectStack AI LLC 对该部署不提供任何保证。若你自托管的是开源的 ObjectStack 运行时,则其以 Apache License 2.0 授权,除该许可证明文约定外,ObjectStack AI LLC 不提供任何保证。',
},
{
heading: '托管服务',
text: 'ObjectStack AI LLC 运营的任何托管服务(例如 ObjectOS Cloud),适用单独的服务协议,将在你注册时另行呈现。本网站的任何内容均不构成此类协议。',
},
{
heading: '条款变更',
text: '本条款可能不时更新。重大变更将通过上方的"最近更新"日期反映。',
},
{
heading: '联系方式',
text: '关于本条款的问题,请联系 legal@objectstack.ai。',
},
],
back: '← 返回首页',
},
'zh-Hans': zhHans,
'zh-Hant': zhHant,
};

/**
Expand Down Expand Up @@ -95,27 +82,40 @@ export default async function TermsPage({
params: Promise<{ lang: string }>;
}) {
const { lang } = await params;
const t = content[lang as keyof typeof content] ?? content.en;
// Any other locale is served the English entry. That text is English inside
// `<html lang="LOCALE">`, so it is marked `lang="en"` and introduced by the
// notice docs pages show on a fallback (#298), in the route locale and before
// the English it describes. An English or written page is unchanged.
const isFallback = !Object.hasOwn(content, lang);
const t = isFallback ? content.en : content[lang as keyof typeof content];
const contentLang = isFallback ? i18n.defaultLanguage : undefined;

return (
<HomeLayout {...baseOptions(lang)} i18n>
<main className="mx-auto w-full max-w-3xl px-4 py-16 sm:py-24">
<h1 className="text-3xl sm:text-4xl font-bold tracking-tight mb-2">{t.title}</h1>
<p className="text-sm text-foreground/60 mb-12">{t.updated}</p>
<div className="space-y-8">
{/* An article, not a main: HomeLayout already renders main#nd-home-layout
around this, and a second main nested in it is a duplicate landmark. */}
<article className="mx-auto w-full max-w-3xl px-4 py-16 sm:py-24">
{isFallback && (
<Callout type="info" role="note" className="mt-0 mb-8" data-untranslated-notice="">
{uiText(lang).notTranslated}
</Callout>
)}
<h1 lang={contentLang} className="text-3xl sm:text-4xl font-bold tracking-tight mb-2">{t.title}</h1>
<p lang={contentLang} className="text-sm text-foreground/60 mb-12">{t.updated}</p>
<div lang={contentLang} className="space-y-8">
{t.body.map((s) => (
<section key={s.heading}>
<h2 className="text-xl font-semibold mb-3">{s.heading}</h2>
<p className="text-foreground/80 leading-relaxed">{s.text}</p>
</section>
))}
</div>
<div className="mt-16 pt-8 border-t border-border/60">
<div lang={contentLang} className="mt-16 pt-8 border-t border-border/60">
<Link href={`/${lang}`} className="text-sm text-primary hover:underline">
{t.back}
</Link>
</div>
</main>
</article>
</HomeLayout>
);
}
28 changes: 28 additions & 0 deletions apps/docs/app/[lang]/terms/zh-Hans.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"title": "服务条款",
"description": "ObjectOS 各版本的许可方式、本站内容采用的 Apache-2.0 许可、ObjectOS 商标,以及自管部署的责任归属。",
"updated": "最近更新:2026 年 10 月 6 日",
"body": [
{
"heading": "许可",
"text": "ObjectOS 是商业产品,没有开源版本。你对 ObjectOS 的使用,受你所使用版本(ObjectOS Cloud 或 ObjectOS Enterprise)的许可协议或服务协议约束。本文档站点所在仓库的内容(文档与站点代码)以 Apache License 2.0 授权;开源的 ObjectStack 框架及其运行时在其自己的仓库中以 Apache License 2.0 授权。\"ObjectOS\" 名称与 Logo 为 ObjectStack AI LLC 的商标,不在 Apache 2.0 的授权范围内 —— 详见仓库内的 TRADEMARK.md。"
},
{
"heading": "自托管部署",
"text": "当你在自己的基础设施中自管运行 ObjectOS(ObjectOS Enterprise)时,该部署的运行、安全、可用性、备份与合规性,完全由你自行负责;除你的商业协议明文约定外,ObjectStack AI LLC 对该部署不提供任何保证。若你自托管的是开源的 ObjectStack 运行时,则其以 Apache License 2.0 授权,除该许可证明文约定外,ObjectStack AI LLC 不提供任何保证。"
},
{
"heading": "托管服务",
"text": "ObjectStack AI LLC 运营的任何托管服务(例如 ObjectOS Cloud),适用单独的服务协议,将在你注册时另行呈现。本网站的任何内容均不构成此类协议。"
},
{
"heading": "条款变更",
"text": "本条款可能不时更新。重大变更将通过上方的\"最近更新\"日期反映。"
},
{
"heading": "联系方式",
"text": "关于本条款的问题,请联系 legal@objectstack.ai。"
}
],
"back": "← 返回首页"
}
28 changes: 28 additions & 0 deletions apps/docs/app/[lang]/terms/zh-Hant.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"title": "服務條款",
"description": "ObjectOS 各版本的許可方式、本站內容採用的 Apache-2.0 許可、ObjectOS 商標,以及自管部署的責任歸屬。",
"updated": "最近更新:2026 年 10 月 6 日",
"body": [
{
"heading": "許可",
"text": "ObjectOS 是商業產品,沒有開源版本。你對 ObjectOS 的使用,受你所使用版本(ObjectOS Cloud 或 ObjectOS Enterprise)的許可協議或服務協議約束。本文件站點所在倉庫的內容(文件與站點程式碼)以 Apache License 2.0 授權;開源的 ObjectStack 框架及其執行時在其自己的倉庫中以 Apache License 2.0 授權。\"ObjectOS\" 名稱與 Logo 為 ObjectStack AI LLC 的商標,不在 Apache 2.0 的授權範圍內 —— 詳見倉庫內的 TRADEMARK.md。"
},
{
"heading": "自託管部署",
"text": "當你在自己的基礎設施中自管執行 ObjectOS(ObjectOS Enterprise)時,該部署的執行、安全、可用性、備份與合規性,完全由你自行負責;除你的商業協議明文約定外,ObjectStack AI LLC 對該部署不提供任何保證。若你自託管的是開源的 ObjectStack 執行時,則其以 Apache License 2.0 授權,除該許可證明文約定外,ObjectStack AI LLC 不提供任何保證。"
},
{
"heading": "託管服務",
"text": "ObjectStack AI LLC 運營的任何託管服務(例如 ObjectOS Cloud),適用單獨的服務協議,將在你註冊時另行呈現。本網站的任何內容均不構成此類協議。"
},
{
"heading": "條款變更",
"text": "本條款可能不時更新。重大變更將通過上方的\"最近更新\"日期反映。"
},
{
"heading": "聯絡方式",
"text": "關於本條款的問題,請聯絡 legal@objectstack.ai。"
}
],
"back": "← 返回首頁"
}
Loading
Loading