Skip to content

Commit 66a8822

Browse files
i18n(service-storage): ship the file and upload-session objects in all eleven platform languages (#30649)
<!-- claude-projects-attribution: {"github_login":"os-bill"} --> _Requested by **Bill** · [project thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgBxjikPH2bUin9o95gbAxsx)_ domain:server#2 · os-bill · session_01Utp6Cai5CRdAs4u9gTipWU Refs #30512 — package 10 of 11 (`@objectstack/service-storage`), moved ahead in the order by the seat now that #30335's storage half (#30627) has merged. The card stays open: the last PR of the series flips the bundle check to the platform locale table. Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么:** 文件与上传会话两个对象(`sys_file`、`sys_upload_session`)的名称、字段、选项、帮助和视图名补上 7 种语言:繁中、阿语、法语、巴葡、俄语、德语、韩语,与平台语言表的 11 种一致。 - **为什么改:** 平台语言表(#29428 裁决 F)要求每个界面带齐 11 种语言;这是第 3 期按包补齐的第 10 个包(68 条),按席位安排插队。 - **风险与回滚:** 只加翻译数据和注册行,不动逻辑、schema、接口;原有 4 种一字未改;已包含 #30627 合入后的全部键。回滚即撤 PR。 - **先看:** `src/translations/index.ts`(按表标签注册,zh-CN 在 zh-Hant 前),再抽看 `ar.objects.generated.ts`。 - **两分钟验证:** `node scripts/check-i18n-bundles.mjs --filter=storage` 输出 in sync;`node scripts/check-i18n-stale-fill.mjs` 退出 0。 - **需要你做的:** 无,席位落地。 ## What changes - Seven new locales for the storage objects under the platform locale table's tags (`zh-Hant`, `ar`, `fr`, `pt-BR`, `ru`, `de`, `ko`): each a `TAG.objects.generated.ts` with all 68 leaves plus its `TAG.source-hashes.generated.ts`, written by the repo's own `os i18n extract --fill=default --source-hashes`, served through `withSourceFallback` like the existing three. `zh-CN` stays ahead of `zh-Hant` in `index.ts`. - The extract command in `scripts/i18n-extract.config.ts` lists the seven tags and its merge baseline imports the seven bundles, so `check:i18n` covers them from this PR on. ## Acceptance notes - **Quality bar (#17508 / PR #19345):** every leaf written for the reader; placeholders, code spans and identifiers byte-identical, checked per leaf against `en`. Arabic is RTL prose with identifiers in Latin script. - **Leaves equal to English, on purpose:** the HTTP header name `ETag` in every locale; `Bucket` (the object-storage term the providers' own pt-BR and de documentation use) and `Status` (a native word) in `pt-BR` and `de`. The extractor records each as a source copy. - No cross-locale coincidence: `check:i18n-stale-fill` passes with the baseline untouched. ## Verification <details><summary>Package suite, typecheck, build (verify lock)</summary> ``` turbo build --filter=@objectstack/service-storage...: 17 tasks successful, exit 0 pnpm --filter @objectstack/service-storage test && typecheck Test Files 73 passed (73) Tests 1353 passed (1353) os-verify-lock: VERDICT command-exit 0 ``` </details> <details><summary>i18n gates and size</summary> ``` node scripts/check-i18n-bundles.mjs --filter=storage in sync EXIT 0 node scripts/check-i18n-stale-fill.mjs OK (no new stale fills, 1 baselined) EXIT 0 eslint --no-inline-config on the changed .ts files: exit 0 changed lines 1483 (+1482 / -1), 17 files: under the 3000-line threshold ``` </details> Derived gate families (dispatch-gates --commands, reconciled with --ran): 56 run, 0 not measured, all exit 0; recorded in the os-dev-report on #30512. Dogfood: not run — content-only package PR, no `!` in the title and no `(narrowing)` arm. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Utp6Cai5CRdAs4u9gTipWU Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8fefefd commit 66a8822

17 files changed

Lines changed: 1482 additions & 1 deletion
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/service-storage': patch
3+
---
4+
5+
i18n(service-storage): the file and upload-session objects ship in all eleven platform languages
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`sys_file` and `sys_upload_session` now carry Traditional Chinese (`zh-Hant`), Arabic (`ar`), French (`fr`), Brazilian Portuguese (`pt-BR`), Russian (`ru`), German (`de`) and Korean (`ko`) beside the existing `en`, `zh-CN`, `ja-JP` and `es-ES`, so a reader in one of those languages sees the file and upload screens in their own language instead of English. Each new locale is registered under its platform-table tag with its source-hash companion, and the package's extract command lists the seven tags, so the existing `check:i18n` bundle check covers them. Package 10 of #30512.

‎packages/services/service-storage/scripts/i18n-extract.config.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* decomposition (see that package's extract config).
1212
*
1313
* os i18n extract packages/services/service-storage/scripts/i18n-extract.config.ts \
14-
* --locales=zh-CN,ja-JP,es-ES --fill=default --objects-only --no-metadata-forms \
14+
* --locales=zh-CN,ja-JP,es-ES,zh-Hant,ar,fr,pt-BR,ru,de,ko --fill=default --objects-only --no-metadata-forms \
1515
* --source-hashes \
1616
* --out=packages/services/service-storage/src/translations
1717
*
@@ -45,6 +45,13 @@ import { enObjects } from '../src/translations/en.objects.generated.js';
4545
import { zhCNObjects } from '../src/translations/zh-CN.objects.generated.js';
4646
import { jaJPObjects } from '../src/translations/ja-JP.objects.generated.js';
4747
import { esESObjects } from '../src/translations/es-ES.objects.generated.js';
48+
import { zhHantObjects } from '../src/translations/zh-Hant.objects.generated.js';
49+
import { arObjects } from '../src/translations/ar.objects.generated.js';
50+
import { frObjects } from '../src/translations/fr.objects.generated.js';
51+
import { ptBRObjects } from '../src/translations/pt-BR.objects.generated.js';
52+
import { ruObjects } from '../src/translations/ru.objects.generated.js';
53+
import { deObjects } from '../src/translations/de.objects.generated.js';
54+
import { koObjects } from '../src/translations/ko.objects.generated.js';
4855

4956
/**
5057
* The annotation is load-bearing, not decoration (#10868). `defineStack`
@@ -67,6 +74,13 @@ const config: ObjectStackDefinition = defineStack({
6774
{ 'zh-CN': { objects: zhCNObjects } },
6875
{ 'ja-JP': { objects: jaJPObjects } },
6976
{ 'es-ES': { objects: esESObjects } },
77+
{ 'zh-Hant': { objects: zhHantObjects } },
78+
{ 'ar': { objects: arObjects } },
79+
{ 'fr': { objects: frObjects } },
80+
{ 'pt-BR': { objects: ptBRObjects } },
81+
{ 'ru': { objects: ruObjects } },
82+
{ 'de': { objects: deObjects } },
83+
{ 'ko': { objects: koObjects } },
7084
],
7185
});
7286

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* Auto-generated by 'os i18n extract' for locale 'ar'.
5+
* Edit translations in place; re-run extract (with --merge) to fill new gaps.
6+
* Do not hand-edit the structure — only the leaf string values.
7+
* Merge only fills gaps: correcting a source label/description does not
8+
* push the correction into a leaf here that already holds a translation —
9+
* a present-but-stale string is not a gap, so it is left as-is. Re-translate
10+
* it by hand when its source changes; nothing here or in `os i18n check`
11+
* tells a leaf a translator updated on purpose from one nobody has looked
12+
* at since the source moved.
13+
*/
14+
15+
import type { TranslationData } from '@objectstack/spec/system';
16+
17+
export const arObjects: NonNullable<TranslationData['objects']> = {
18+
sys_file: {
19+
label: "ملف النظام",
20+
pluralLabel: "ملفات النظام",
21+
description: "البيانات الوصفية لملفات خدمة التخزين (ربط fileId ↔ key)",
22+
fields: {
23+
id: {
24+
label: "معرّف الملف"
25+
},
26+
key: {
27+
label: "مفتاح التخزين"
28+
},
29+
name: {
30+
label: "اسم الملف"
31+
},
32+
mime_type: {
33+
label: "نوع MIME"
34+
},
35+
size: {
36+
label: "الحجم (بايت)"
37+
},
38+
scope: {
39+
label: "النطاق",
40+
options: {
41+
user: "المستخدم",
42+
tenant: "المستأجر",
43+
private: "خاص",
44+
temp: "مؤقت",
45+
attachments: "المرفقات"
46+
}
47+
},
48+
bucket: {
49+
label: "الحاوية"
50+
},
51+
acl: {
52+
label: "قائمة التحكم بالوصول",
53+
options: {
54+
private: "خاص",
55+
public_read: "قراءة عامة"
56+
}
57+
},
58+
status: {
59+
label: "الحالة",
60+
options: {
61+
pending: "بانتظار الرفع",
62+
committed: "مُثبَّت",
63+
deleted: "محذوف"
64+
}
65+
},
66+
etag: {
67+
label: "ETag"
68+
},
69+
owner_id: {
70+
label: "معرّف المالك",
71+
help: "المستخدم الذي رفع الملف (صفة التأليف، لا مالك مرجع الحقل)"
72+
},
73+
ref_object: {
74+
label: "الكائن المُشير",
75+
help: "الاسم المختصر لكائن السجل الذي يملك حقلُه هذا الملف"
76+
},
77+
ref_id: {
78+
label: "السجل المُشير",
79+
help: "المفتاح الأساسي للسجل الذي يملك حقلُه هذا الملف"
80+
},
81+
ref_field: {
82+
label: "الحقل المُشير",
83+
help: "اسم الحقل في السجل المالك الذي يحمل معرّف هذا الملف"
84+
},
85+
released_ref_object: {
86+
label: "الكائن الذي حُرِّر منه",
87+
help: "الاسم المختصر لكائن السجل الذي امتلك هذا الملف آخر مرة، بعد أن تخلّى عنه"
88+
},
89+
released_ref_id: {
90+
label: "السجل الذي حُرِّر منه",
91+
help: "المفتاح الأساسي للسجل الذي امتلك هذا الملف آخر مرة، بعد أن تخلّى عنه"
92+
},
93+
metadata: {
94+
label: "البيانات الوصفية (JSON)"
95+
},
96+
created_at: {
97+
label: "تاريخ الإنشاء"
98+
},
99+
updated_at: {
100+
label: "تاريخ التحديث"
101+
},
102+
deleted_at: {
103+
label: "تاريخ الحذف",
104+
help: "طابع زمني للشاهد — يُضبط عند إزالة آخر مرجع sys_attachment لملف في نطاق المرفقات؛ وبعد انقضاء فترة السماح يستردّ TTL دورة الحياة الصف (وبايتات تخزينه، عبر حارس الاسترداد في sys_file). قيمته NULL للصفوف الحيّة."
105+
}
106+
}
107+
},
108+
sys_upload_session: {
109+
label: "جلسة رفع النظام",
110+
pluralLabel: "جلسات رفع النظام",
111+
description: "جلسات رفع متعدد الأجزاء قابلة للاستئناف تتتبّعها service-storage",
112+
fields: {
113+
id: {
114+
label: "معرّف جلسة الرفع"
115+
},
116+
file_id: {
117+
label: "معرّف الملف"
118+
},
119+
key: {
120+
label: "مفتاح التخزين"
121+
},
122+
filename: {
123+
label: "اسم الملف"
124+
},
125+
mime_type: {
126+
label: "نوع MIME"
127+
},
128+
total_size: {
129+
label: "الحجم الإجمالي (بايت)"
130+
},
131+
chunk_size: {
132+
label: "حجم الجزء (بايت)"
133+
},
134+
total_chunks: {
135+
label: "إجمالي الأجزاء"
136+
},
137+
uploaded_chunks: {
138+
label: "الأجزاء المرفوعة"
139+
},
140+
uploaded_size: {
141+
label: "الحجم المرفوع (بايت)"
142+
},
143+
parts: {
144+
label: "الأجزاء المرفوعة (JSON)"
145+
},
146+
resume_token: {
147+
label: "رمز الاستئناف"
148+
},
149+
backend_upload_id: {
150+
label: "معرّف الرفع في الخلفية"
151+
},
152+
scope: {
153+
label: "النطاق"
154+
},
155+
bucket: {
156+
label: "الحاوية"
157+
},
158+
metadata: {
159+
label: "البيانات الوصفية (JSON)"
160+
},
161+
status: {
162+
label: "الحالة",
163+
options: {
164+
in_progress: "قيد التنفيذ",
165+
completing: "جارٍ الإكمال",
166+
completed: "مكتمل",
167+
failed: "فشل",
168+
expired: "منتهي الصلاحية"
169+
}
170+
},
171+
started_at: {
172+
label: "وقت البدء"
173+
},
174+
expires_at: {
175+
label: "وقت الانتهاء"
176+
},
177+
updated_at: {
178+
label: "تاريخ التحديث"
179+
}
180+
}
181+
}
182+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.
2+
3+
/**
4+
* Auto-generated by 'os i18n extract' for locale 'ar'. Do not hand-edit.
5+
*
6+
* Each entry is the digest of the SOURCE REVISION that this locale's leaf at
7+
* that path is still a byte copy of — provenance for the generated half of the
8+
* bundles (commit 09b4f4e4e): a leaf whose digest no longer matches its source is stale and serves the source text instead.
9+
*
10+
* An entry exists only while the leaf IS such a copy. Re-translate the leaf in
11+
* `<locale>.objects.generated.ts` and the next extract drops its entry by
12+
* itself — the table makes no claim about text a translator wrote. A path with
13+
* no entry is LEGACY-TRUSTED and never reported stale.
14+
*
15+
* ⚠️ Do not "fix" a staleness report by editing this file. Refreshing a digest
16+
* records that the current text was copied from the current source, which is
17+
* the false claim the mechanism exists to detect. Fix the TRANSLATION.
18+
*/
19+
20+
export const arGeneratedSourceHashes: Readonly<Record<string, string>> = {
21+
"objects.sys_file.fields.etag.label": "a62e7fe0bac46fcb",
22+
};

0 commit comments

Comments
 (0)