Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions .changeset/30512-service-storage-locales.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/service-storage': patch
---

i18n(service-storage): the file and upload-session objects ship in all eleven platform languages

Clause-②: no
Metadata-protocol: none

`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.
16 changes: 15 additions & 1 deletion packages/services/service-storage/scripts/i18n-extract.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* decomposition (see that package's extract config).
*
* os i18n extract packages/services/service-storage/scripts/i18n-extract.config.ts \
* --locales=zh-CN,ja-JP,es-ES --fill=default --objects-only --no-metadata-forms \
* --locales=zh-CN,ja-JP,es-ES,zh-Hant,ar,fr,pt-BR,ru,de,ko --fill=default --objects-only --no-metadata-forms \
* --source-hashes \
* --out=packages/services/service-storage/src/translations
*
Expand Down Expand Up @@ -45,6 +45,13 @@ import { enObjects } from '../src/translations/en.objects.generated.js';
import { zhCNObjects } from '../src/translations/zh-CN.objects.generated.js';
import { jaJPObjects } from '../src/translations/ja-JP.objects.generated.js';
import { esESObjects } from '../src/translations/es-ES.objects.generated.js';
import { zhHantObjects } from '../src/translations/zh-Hant.objects.generated.js';
import { arObjects } from '../src/translations/ar.objects.generated.js';
import { frObjects } from '../src/translations/fr.objects.generated.js';
import { ptBRObjects } from '../src/translations/pt-BR.objects.generated.js';
import { ruObjects } from '../src/translations/ru.objects.generated.js';
import { deObjects } from '../src/translations/de.objects.generated.js';
import { koObjects } from '../src/translations/ko.objects.generated.js';

/**
* The annotation is load-bearing, not decoration (#10868). `defineStack`
Expand All @@ -67,6 +74,13 @@ const config: ObjectStackDefinition = defineStack({
{ 'zh-CN': { objects: zhCNObjects } },
{ 'ja-JP': { objects: jaJPObjects } },
{ 'es-ES': { objects: esESObjects } },
{ 'zh-Hant': { objects: zhHantObjects } },
{ 'ar': { objects: arObjects } },
{ 'fr': { objects: frObjects } },
{ 'pt-BR': { objects: ptBRObjects } },
{ 'ru': { objects: ruObjects } },
{ 'de': { objects: deObjects } },
{ 'ko': { objects: koObjects } },
],
});

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

/**
* Auto-generated by 'os i18n extract' for locale 'ar'.
* Edit translations in place; re-run extract (with --merge) to fill new gaps.
* Do not hand-edit the structure — only the leaf string values.
* Merge only fills gaps: correcting a source label/description does not
* push the correction into a leaf here that already holds a translation —
* a present-but-stale string is not a gap, so it is left as-is. Re-translate
* it by hand when its source changes; nothing here or in `os i18n check`
* tells a leaf a translator updated on purpose from one nobody has looked
* at since the source moved.
*/

import type { TranslationData } from '@objectstack/spec/system';

export const arObjects: NonNullable<TranslationData['objects']> = {
sys_file: {
label: "ملف النظام",
pluralLabel: "ملفات النظام",
description: "البيانات الوصفية لملفات خدمة التخزين (ربط fileId ↔ key)",
fields: {
id: {
label: "معرّف الملف"
},
key: {
label: "مفتاح التخزين"
},
name: {
label: "اسم الملف"
},
mime_type: {
label: "نوع MIME"
},
size: {
label: "الحجم (بايت)"
},
scope: {
label: "النطاق",
options: {
user: "المستخدم",
tenant: "المستأجر",
private: "خاص",
temp: "مؤقت",
attachments: "المرفقات"
}
},
bucket: {
label: "الحاوية"
},
acl: {
label: "قائمة التحكم بالوصول",
options: {
private: "خاص",
public_read: "قراءة عامة"
}
},
status: {
label: "الحالة",
options: {
pending: "بانتظار الرفع",
committed: "مُثبَّت",
deleted: "محذوف"
}
},
etag: {
label: "ETag"
},
owner_id: {
label: "معرّف المالك",
help: "المستخدم الذي رفع الملف (صفة التأليف، لا مالك مرجع الحقل)"
},
ref_object: {
label: "الكائن المُشير",
help: "الاسم المختصر لكائن السجل الذي يملك حقلُه هذا الملف"
},
ref_id: {
label: "السجل المُشير",
help: "المفتاح الأساسي للسجل الذي يملك حقلُه هذا الملف"
},
ref_field: {
label: "الحقل المُشير",
help: "اسم الحقل في السجل المالك الذي يحمل معرّف هذا الملف"
},
released_ref_object: {
label: "الكائن الذي حُرِّر منه",
help: "الاسم المختصر لكائن السجل الذي امتلك هذا الملف آخر مرة، بعد أن تخلّى عنه"
},
released_ref_id: {
label: "السجل الذي حُرِّر منه",
help: "المفتاح الأساسي للسجل الذي امتلك هذا الملف آخر مرة، بعد أن تخلّى عنه"
},
metadata: {
label: "البيانات الوصفية (JSON)"
},
created_at: {
label: "تاريخ الإنشاء"
},
updated_at: {
label: "تاريخ التحديث"
},
deleted_at: {
label: "تاريخ الحذف",
help: "طابع زمني للشاهد — يُضبط عند إزالة آخر مرجع sys_attachment لملف في نطاق المرفقات؛ وبعد انقضاء فترة السماح يستردّ TTL دورة الحياة الصف (وبايتات تخزينه، عبر حارس الاسترداد في sys_file). قيمته NULL للصفوف الحيّة."
}
}
},
sys_upload_session: {
label: "جلسة رفع النظام",
pluralLabel: "جلسات رفع النظام",
description: "جلسات رفع متعدد الأجزاء قابلة للاستئناف تتتبّعها service-storage",
fields: {
id: {
label: "معرّف جلسة الرفع"
},
file_id: {
label: "معرّف الملف"
},
key: {
label: "مفتاح التخزين"
},
filename: {
label: "اسم الملف"
},
mime_type: {
label: "نوع MIME"
},
total_size: {
label: "الحجم الإجمالي (بايت)"
},
chunk_size: {
label: "حجم الجزء (بايت)"
},
total_chunks: {
label: "إجمالي الأجزاء"
},
uploaded_chunks: {
label: "الأجزاء المرفوعة"
},
uploaded_size: {
label: "الحجم المرفوع (بايت)"
},
parts: {
label: "الأجزاء المرفوعة (JSON)"
},
resume_token: {
label: "رمز الاستئناف"
},
backend_upload_id: {
label: "معرّف الرفع في الخلفية"
},
scope: {
label: "النطاق"
},
bucket: {
label: "الحاوية"
},
metadata: {
label: "البيانات الوصفية (JSON)"
},
status: {
label: "الحالة",
options: {
in_progress: "قيد التنفيذ",
completing: "جارٍ الإكمال",
completed: "مكتمل",
failed: "فشل",
expired: "منتهي الصلاحية"
}
},
started_at: {
label: "وقت البدء"
},
expires_at: {
label: "وقت الانتهاء"
},
updated_at: {
label: "تاريخ التحديث"
}
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license.

/**
* Auto-generated by 'os i18n extract' for locale 'ar'. Do not hand-edit.
*
* Each entry is the digest of the SOURCE REVISION that this locale's leaf at
* that path is still a byte copy of — provenance for the generated half of the
* bundles (commit 09b4f4e4e): a leaf whose digest no longer matches its source is stale and serves the source text instead.
*
* An entry exists only while the leaf IS such a copy. Re-translate the leaf in
* `<locale>.objects.generated.ts` and the next extract drops its entry by
* itself — the table makes no claim about text a translator wrote. A path with
* no entry is LEGACY-TRUSTED and never reported stale.
*
* ⚠️ Do not "fix" a staleness report by editing this file. Refreshing a digest
* records that the current text was copied from the current source, which is
* the false claim the mechanism exists to detect. Fix the TRANSLATION.
*/

export const arGeneratedSourceHashes: Readonly<Record<string, string>> = {
"objects.sys_file.fields.etag.label": "a62e7fe0bac46fcb",
};
Loading
Loading