Skip to content

Commit a4c100d

Browse files
authored
Merge pull request #9 from objectstack-ai/docs/i18n-zh-hans-migration-and-audit
docs: audit English source + migrate i18n to zh-Hans and add ja/de/es/fr
2 parents 9aad64f + 299b599 commit a4c100d

331 files changed

Lines changed: 29828 additions & 1603 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/launch.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"version": "0.0.1",
3+
"configurations": [
4+
{
5+
"name": "Docs site (@objectos/docs)",
6+
"runtimeExecutable": "pnpm",
7+
"runtimeArgs": ["--filter", "@objectos/docs", "dev"],
8+
"port": 3000,
9+
"autoPort": true
10+
},
11+
{
12+
"name": "ObjectStack server (@objectos/server)",
13+
"runtimeExecutable": "pnpm",
14+
"runtimeArgs": ["--filter", "@objectos/server", "dev"],
15+
"port": 3001
16+
},
17+
{
18+
"name": "Desktop app (@objectos/one, Tauri)",
19+
"runtimeExecutable": "pnpm",
20+
"runtimeArgs": ["--filter", "@objectos/one", "dev"]
21+
}
22+
]
23+
}

apps/docs/app/[lang]/layout.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { i18n } from '@/lib/i18n';
55
// Language display names mapping
66
const LANGUAGE_NAMES: Record<string, string> = {
77
en: 'English',
8-
cn: '中文',
8+
'zh-Hans': '简体中文',
9+
ja: '日本語',
10+
de: 'Deutsch',
11+
es: 'Español',
12+
fr: 'Français',
913
};
1014

1115
export default async function LanguageLayout({

apps/docs/app/[lang]/privacy/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const content = {
2626
],
2727
back: '← Back to home',
2828
},
29-
cn: {
29+
'zh-Hans': {
3030
title: '隐私政策',
3131
updated: '最近更新:2026 年 5 月 27 日',
3232
body: [
@@ -57,7 +57,7 @@ export default async function PrivacyPage({
5757
params: Promise<{ lang: string }>;
5858
}) {
5959
const { lang } = await params;
60-
const t = content[lang === 'cn' ? 'cn' : 'en'];
60+
const t = content[lang as keyof typeof content] ?? content.en;
6161

6262
return (
6363
<HomeLayout {...baseOptions(lang)} i18n>

apps/docs/app/[lang]/terms/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const content = {
3030
],
3131
back: '← Back to home',
3232
},
33-
cn: {
33+
'zh-Hans': {
3434
title: '服务条款',
3535
updated: '最近更新:2026 年 5 月 27 日',
3636
body: [
@@ -65,7 +65,7 @@ export default async function TermsPage({
6565
params: Promise<{ lang: string }>;
6666
}) {
6767
const { lang } = await params;
68-
const t = content[lang === 'cn' ? 'cn' : 'en'];
68+
const t = content[lang as keyof typeof content] ?? content.en;
6969

7070
return (
7171
<HomeLayout {...baseOptions(lang)} i18n>

apps/docs/lib/download-i18n.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Download page translations + static install data.
33
*
4-
* English is the source of truth — edit `en` first, then sync `cn`.
4+
* English is the source of truth — edit `en` first, then sync `zhHans`.
55
*
66
* Only include install methods that have a real, published artifact:
77
* - Docker image: ghcr.io/objectstack-ai/objectos:latest (docker.yml)
@@ -198,7 +198,7 @@ export const en: DownloadTranslations = {
198198
copy: { copy: 'Copy', copied: 'Copied' },
199199
};
200200

201-
export const cn: DownloadTranslations = {
201+
export const zhHans: DownloadTranslations = {
202202
badge: `最新发布 · v${ONE_VERSION}`,
203203
hero: {
204204
title: '下载 ObjectOS',
@@ -313,8 +313,17 @@ export const cn: DownloadTranslations = {
313313
copy: { copy: '复制', copied: '已复制' },
314314
};
315315

316+
/**
317+
* Registry of available download-page translations. Locales absent
318+
* here (ja, de, es, fr until translated) resolve to English.
319+
*/
320+
const DOWNLOAD_TRANSLATIONS: Partial<Record<string, DownloadTranslations>> = {
321+
en,
322+
'zh-Hans': zhHans,
323+
};
324+
316325
export function getDownloadTranslations(lang: string): DownloadTranslations {
317-
return lang === 'cn' ? cn : en;
326+
return DOWNLOAD_TRANSLATIONS[lang] ?? en;
318327
}
319328

320329
/* ------------------------------------------------------------------ */

apps/docs/lib/homepage-i18n.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
* evaluating a customer-hosted runtime for ObjectStack applications —
88
* NOT framework developers.
99
*
10-
* Supports: en (English), cn (Chinese / 中文)
10+
* Supports: en (English), zh-Hans (简体中文). Additional locales
11+
* (ja, de, es, fr) fall back to English until their objects are added.
1112
*/
1213

1314
import { SPEC_VERSION, OBJECTOS_VERSION } from './version';
@@ -332,9 +333,9 @@ export const en: HomepageTranslations = {
332333
};
333334

334335
/**
335-
* Chinese Translations (中文翻译)
336+
* Chinese (Simplified) Translations (简体中文翻译)
336337
*/
337-
export const cn: HomepageTranslations = {
338+
export const zhHans: HomepageTranslations = {
338339
badge: {
339340
status: 'AI 原生业务平台',
340341
version: SPEC_VERSION,
@@ -487,14 +488,17 @@ export const cn: HomepageTranslations = {
487488
};
488489

489490
/**
490-
* Get translations for a specific language
491+
* Registry of available homepage translations. Locales absent here
492+
* (ja, de, es, fr until translated) resolve to English via the getter.
493+
*/
494+
const HOMEPAGE_TRANSLATIONS: Partial<Record<string, HomepageTranslations>> = {
495+
en,
496+
'zh-Hans': zhHans,
497+
};
498+
499+
/**
500+
* Get translations for a specific language, falling back to English.
491501
*/
492502
export function getHomepageTranslations(lang: string): HomepageTranslations {
493-
switch (lang) {
494-
case 'cn':
495-
return cn;
496-
case 'en':
497-
default:
498-
return en;
499-
}
503+
return HOMEPAGE_TRANSLATIONS[lang] ?? en;
500504
}

apps/docs/lib/i18n.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ import { defineI18n } from 'fumadocs-core/i18n';
22

33
/**
44
* i18n Configuration for ObjectStack Documentation
5-
*
6-
* Supported Languages:
7-
* - en: English (Default)
8-
* - cn: Chinese (中文)
5+
*
6+
* Supported Languages (BCP 47 tags):
7+
* - en: English (Default)
8+
* - zh-Hans: Chinese, Simplified (简体中文)
9+
* - ja: Japanese (日本語)
10+
* - de: German (Deutsch)
11+
* - es: Spanish (Español)
12+
* - fr: French (Français)
913
*/
1014
export const i18n = defineI18n({
1115
defaultLanguage: 'en',
12-
languages: ['en', 'cn'],
16+
languages: ['en', 'zh-Hans', 'ja', 'de', 'es', 'fr'],
1317
// Hide locale prefix for default language (e.g., /docs instead of /en/docs)
1418
hideLocale: 'default-locale',
1519
});

apps/docs/lib/layout.shared.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ export const gitConfig = {
99

1010
const NAV_LABELS: Record<string, { docs: string; download: string; changelog: string }> = {
1111
en: { docs: 'Docs', download: 'Download', changelog: 'Changelog' },
12-
cn: { docs: '文档', download: '下载', changelog: '更新日志' },
12+
'zh-Hans': { docs: '文档', download: '下载', changelog: '更新日志' },
13+
ja: { docs: 'ドキュメント', download: 'ダウンロード', changelog: '変更履歴' },
14+
de: { docs: 'Dokumentation', download: 'Download', changelog: 'Änderungen' },
15+
es: { docs: 'Documentación', download: 'Descargar', changelog: 'Cambios' },
16+
fr: { docs: 'Documentation', download: 'Télécharger', changelog: 'Journal' },
1317
};
1418

1519
const RELEASES_URL = 'https://github.com/objectstack-ai/objectos/releases';

apps/docs/middleware.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,21 @@ function setLocaleCookie(response: NextResponse, locale: string): void {
2424
* Maps browser language codes to our supported language codes
2525
*/
2626
const LANGUAGE_MAPPING: Record<string, string> = {
27-
'zh': 'cn', // Chinese -> cn
28-
'zh-CN': 'cn', // Chinese (China) -> cn
29-
'zh-TW': 'cn', // Chinese (Taiwan) -> cn
30-
'zh-HK': 'cn', // Chinese (Hong Kong) -> cn
27+
'zh': 'zh-Hans', // Chinese -> Simplified
28+
'zh-CN': 'zh-Hans', // Chinese (China) -> Simplified
29+
'zh-SG': 'zh-Hans', // Chinese (Singapore) -> Simplified
30+
'zh-Hans': 'zh-Hans', // already Simplified
31+
// Traditional variants fall back to Simplified until zh-Hant ships
32+
'zh-TW': 'zh-Hans',
33+
'zh-HK': 'zh-Hans',
34+
};
35+
36+
/**
37+
* Legacy locale redirects: old locale code -> current BCP 47 tag.
38+
* Permanent (308) so search engines transfer ranking to the new path.
39+
*/
40+
const LEGACY_LOCALE_REDIRECTS: Record<string, string> = {
41+
cn: 'zh-Hans',
3142
};
3243

3344
/**
@@ -83,7 +94,8 @@ function getPreferredLanguage(request: NextRequest): string {
8394
* - Detects the user's preferred language from browser settings or cookies
8495
* - Redirects users to the appropriate localized version
8596
* - For default language (en): keeps URL as "/" (with internal rewrite)
86-
* - For other languages (cn): redirects to "/cn/"
97+
* - For other languages (e.g. zh-Hans): redirects to "/zh-Hans/"
98+
* - Redirects legacy locale paths (e.g. /cn/*) to their new tag
8799
* - Stores language preference as a cookie
88100
*/
89101
export default function middleware(request: NextRequest) {
@@ -99,6 +111,20 @@ export default function middleware(request: NextRequest) {
99111

100112
const { pathname } = request.nextUrl;
101113

114+
// Legacy locale redirect (e.g. /cn/... -> /zh-Hans/...), permanent for SEO.
115+
const legacySeg = pathname.split('/')[1];
116+
if (legacySeg && LEGACY_LOCALE_REDIRECTS[legacySeg]) {
117+
const target = LEGACY_LOCALE_REDIRECTS[legacySeg];
118+
const url = new URL(request.url);
119+
url.pathname = pathname.replace(
120+
new RegExp(`^/${legacySeg}(/|$)`),
121+
`/${target}$1`,
122+
);
123+
const response = NextResponse.redirect(url, 308);
124+
setLocaleCookie(response, target);
125+
return response;
126+
}
127+
102128
// Check if the pathname already has a locale
103129
const pathnameHasLocale = i18n.languages.some(
104130
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`

content/docs/architecture.de.mdx

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
---
2+
title: Architektur
3+
description: Was tatsächlich auf Ihren Systemen läuft — für die Engineers, die abwägen, ob sie dies einführen sollen.
4+
---
5+
6+
# Architektur
7+
8+
Eine praxisnahe Sicht darauf, was auf Ihren Maschinen läuft, wenn Sie
9+
ObjectOS bereitstellen, welche Daten Ihr Netzwerk verlassen und welche nicht.
10+
11+
Das mentale Modell besteht aus zwei dünnen Schichten:
12+
13+
1. **Metadaten** — Pakete aus Objekten / Views / Actions / Flows /
14+
Agents. Größtenteils vom [AI Builder](/docs/build/ai-builder)
15+
gegen eine sandboxed Tool-API geschrieben; teils von Hand bearbeitet, stets
16+
versionskontrolliert und auditiert.
17+
2. **Eine einzige Node.js-Laufzeit**, die diese Metadaten in eine
18+
funktionierende Anwendung interpretiert — REST-API, Console-UI, Berechtigungen, Jobs, AI-Tools — alles in einem Prozess, der mit Ihrer Datenbank kommuniziert.
19+
20+
Kein Codegenerierungsschritt, keine Deploy-Pipeline zwischen „Benutzer hat
21+
beschrieben, was er möchte" und „es ist live". Die Laufzeit lädt die neuen
22+
Metadaten nach einer HITL-Freigabe per Hot-Reload.
23+
24+
## Was Sie bereitstellen
25+
26+
Ein Node.js-Prozess pro ObjectOS-Instanz. Das ist alles.
27+
28+
```text
29+
┌─────────────────────────────────────────────────────┐
30+
│ ObjectOS process │
31+
│ ┌───────────────────────────────────────────────┐ │
32+
│ │ HTTP dispatcher (/ · /api · /_console …) │ │
33+
│ ├───────────────────────────────────────────────┤ │
34+
│ │ Per-project ObjectKernel (LRU cached) │ │
35+
│ │ ├─ Auth (Better Auth) │ │
36+
│ │ ├─ Security (RBAC + row-level + field) │ │
37+
│ │ ├─ ObjectQL (data engine, generates SQL) │ │
38+
│ │ ├─ REST API generator │ │
39+
│ │ └─ Capabilities loaded per artifact │ │
40+
│ │ (audit, storage, jobs, queue, AI …) │ │
41+
│ └───────────────────────────────────────────────┘ │
42+
└──────────┬──────────────────────────────────────────┘
43+
44+
45+
Your business database
46+
(Postgres / MySQL / SQLite / Turso / MongoDB)
47+
```
48+
49+
Es hat die Komplexität einer einzigen statisch gelinkten Binärdatei. Kein
50+
Sidecar, kein Kafka, keine separate Cache-Schicht erforderlich. Fügen Sie diese hinzu, wenn Sie
51+
sie brauchen; zahlen Sie nicht am ersten Tag dafür.
52+
53+
## Wo Ihre Daten liegen
54+
55+
| Daten | Liegen in | Verlassen Ihr Netzwerk? |
56+
|---|---|---|
57+
| Geschäftsdatensätze | Ihrer Datenbank | **Nein** |
58+
| Benutzerkonten, Sitzungen, OAuth-Tokens | Ihrer Datenbank | **Nein** |
59+
| Audit-Log | Ihrer Datenbank | **Nein** |
60+
| Einstellungen, API-Schlüssel, Secrets | Ihrer Datenbank / Secret-Manager | **Nein** |
61+
| Hochgeladene Dateien | Ihrer Festplatte oder Ihrem S3/R2-Bucket | **Nein** |
62+
| Die kompilierte App-Definition (`objectstack.json`) | Einer Datei auf der Festplatte oder abgerufen von Ihrer Control Plane | Optional |
63+
64+
ObjectOS telefoniert nicht nach Hause. Keine Telemetrie. Keine Lizenzprüfung. Wenn Sie den
65+
Internetzugang vollständig kappen, läuft es unbegrenzt weiter. Siehe
66+
[Air-gapped](/docs/deploy/air-gapped).
67+
68+
## Wie eine Anfrage bedient wird
69+
70+
```text
71+
1. Ingress / TLS termination (your load balancer)
72+
2. HTTP dispatcher (security headers, request id)
73+
3. Hostname → project resolution (cached, TTL configurable)
74+
4. Get or build per-project kernel from LRU
75+
5. AuthPlugin — session cookie, bearer token, or API key
76+
6. SecurityPlugin — RBAC + row-level + field-level checks
77+
7. Route handler — generated REST, declarative action, or custom
78+
8. Data driver — ObjectQL compiles to SQL / Mongo query
79+
9. Response with X-Request-Id propagated
80+
```
81+
82+
Die Schritte 4–8 werden typischerweise in < 5 ms ausgeführt, sobald der Kernel warm ist.
83+
84+
## Die drei Schichten (nur relevant, wenn Sie integrieren)
85+
86+
Die meisten Kunden stellen nur **ObjectOS** bereit. Die anderen beiden Schichten existieren, falls
87+
Sie wissen möchten, woher das Artefakt stammt:
88+
89+
| Schicht | Was es ist | Wo es läuft |
90+
|---|---|---|
91+
| **Framework** (`@objectstack/*`) | Open-Source-Kernel, ObjectQL, Plugins, Treiber | npm — zur Build-Zeit eingebunden |
92+
| **Control Plane** (optional) | Veröffentlicht kompilierte `objectstack.json`-Artefakte; Sie können die gehostete ObjectStack Cloud nutzen, eine eigene betreiben oder sie ganz weglassen | Ihre CI, unsere Cloud oder Ihr Laptop |
93+
| **ObjectOS** | Die Laufzeit, die Sie betreiben | **Ihre Infrastruktur** |
94+
95+
Wenn Sie eine einzelne App ausliefern, benötigen Sie keine Control Plane —
96+
kompilieren Sie `objectstack.config.ts → dist/objectstack.json` in Ihrer CI und
97+
liefern Sie das JSON im Image aus. Wenn Sie einen internen App-Marketplace
98+
mit vielen Tenants und Apps betreiben, ist die Control Plane der Ort, an dem der
99+
Katalog liegt.
100+
101+
## Boot-Modi
102+
103+
| Modus | Wann | Wie |
104+
|---|---|---|
105+
| **Standalone** | Einzelne App, Entwicklung, Evaluierung, Air-gapped, die meisten Produktionsbereitstellungen | `pnpm dev` oder `dist/objectstack.json` von der Festplatte ausführen |
106+
| **File-backed** | Produktion mit extern verwalteten Artefakten | `OS_ARTIFACT_PATH=/path/to/objectstack.json` setzen |
107+
| **Cloud-connected** | Multi-Tenant- / Multi-App-Bereitstellungen, gespeist von einer Control Plane | `OS_CLOUD_URL` + `OS_CLOUD_API_KEY` setzen |
108+
109+
Der Modus wird automatisch anhand von Umgebungsvariablen erkannt.
110+
111+
## Performance-Eigenschaften
112+
113+
| Metrik | Wert |
114+
|---|---|
115+
| Kaltstart (Prozess hochgefahren, bereit für Traffic) | ~1 Sekunde |
116+
| Kernel-Warmup (erste Anfrage an ein Projekt) | 50–300 ms je nach Capabilities |
117+
| Latenz bei warmer Anfrage (CRUD via REST) | typischerweise < 10 ms + Datenbanklatenz |
118+
| Speicherbedarf | ~150 MB Basis; ~10–30 MB pro aktivem Projekt-Kernel |
119+
| Gleichzeitige Projekte pro Instanz | Begrenzt durch `OS_KERNEL_CACHE_SIZE` (Standard 32) |
120+
121+
## Warum diese Form
122+
123+
- **Ein Node-Prozess, keine Sidecars** → passt in ein `docker run`, passt in eine
124+
systemd-Unit, passt in eine Lambda-ähnliche Umgebung.
125+
- **Per-Projekt-Kernel, LRU-gecacht** → eine Instanz kann viele
126+
kleine Apps bedienen, ohne bei jeder Anfrage die Warmup-Kosten zu tragen.
127+
- **Generierte APIs auf Basis deklarierter Metadaten** → es gibt keinen Codegen-
128+
Schritt in Ihrer CI, kein Client-SDK zum Veröffentlichen; die API entspricht Ihrem Datenmodell konstruktionsbedingt.
129+
- **Alle Capabilities sind optionale Plugins** → die Image-Größe skaliert mit dem,
130+
was Sie tatsächlich nutzen.
131+
132+
## Wie es weitergeht
133+
134+
- [Production Readiness](/docs/operate/production) — Checkliste, bevor
135+
Sie es echtem Traffic aussetzen.
136+
- [Runtime Configuration](/docs/configure/runtime) — Verdrahtung von Datenbanken,
137+
Caches und Secrets.
138+
- [Runtime Capabilities](/docs/reference/runtime-capabilities)
139+
welche optionalen Pakete existieren und was sie ermöglichen.

0 commit comments

Comments
 (0)