diff --git a/.changeset/30512-service-mailbox-locales.md b/.changeset/30512-service-mailbox-locales.md new file mode 100644 index 00000000000..25a89ac8b6f --- /dev/null +++ b/.changeset/30512-service-mailbox-locales.md @@ -0,0 +1,10 @@ +--- +'@objectstack/service-mailbox': patch +--- + +i18n(service-mailbox): the mailbox objects' labels, help, options and views ship in all eleven platform languages + +Clause-②: no +Metadata-protocol: none + +The mailbox objects (`sys_mailbox`, `sys_mail_message` and `sys_mail_association`) 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 user reading the app in one of those languages sees the mailbox screens in their own language instead of English. RFC 5322 header names (`Message-ID`, `In-Reply-To`, `Reply-To`, …) and the IMAP `UIDVALIDITY` term stay as written, as they already do in `zh-CN`. 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. Part of #30512. diff --git a/packages/services/service-mailbox/scripts/i18n-extract.config.ts b/packages/services/service-mailbox/scripts/i18n-extract.config.ts index 08692178301..59e79a8b607 100644 --- a/packages/services/service-mailbox/scripts/i18n-extract.config.ts +++ b/packages/services/service-mailbox/scripts/i18n-extract.config.ts @@ -7,7 +7,7 @@ * `--merge` preserves every hand-translated string. * * os i18n extract packages/services/service-mailbox/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-mailbox/src/translations * @@ -41,6 +41,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` @@ -63,6 +70,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 } }, ], }); diff --git a/packages/services/service-mailbox/src/translations/ar.objects.generated.ts b/packages/services/service-mailbox/src/translations/ar.objects.generated.ts new file mode 100644 index 00000000000..8c5672bab3b --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ar.objects.generated.ts @@ -0,0 +1,177 @@ +// 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 = { + sys_mailbox: { + label: "صندوق البريد", + pluralLabel: "صناديق البريد", + description: "صندوق بريد وارد تنسخ المنصّة رسائله: عنوانه ومالكه", + fields: { + id: { + label: "معرّف صندوق البريد" + }, + name: { + label: "الاسم", + help: "الاسم المعروض لصندوق البريد (مثل \"بريد المبيعات\")" + }, + address: { + label: "العنوان", + help: "عنوان صندوق البريد. لا يُطابَق أبدًا كمشارك: فالرسالة المرسلة إلى هذا الصندوق لا تخصّ الصندوق نفسه." + }, + owner_user_id: { + label: "المالك", + help: "المستخدم الذي يملك صندوق البريد هذا. تُعرَض على المالك كل رسالة وصلت إليه، بما فيها غير المرتبطة." + }, + imap_folder: { + label: "المجلد المتزامن", + help: "مجلد IMAP الذي يتبع له مؤشر المزامنة. عند مزامنة صندوق البريد من مجلد آخر، يبدأ المؤشر من جديد." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "قيمة UIDVALIDITY للمجلد التي أُخذ المؤشر بموجبها. عندما يُبلغ الخادم قيمة أخرى، تشير معرّفات UID فيه إلى رسائل أخرى ويبدأ المؤشر من جديد." + }, + imap_last_uid: { + label: "آخر UID متزامن", + help: "أعلى UID في المجلد سُلِّم بالفعل إلى الاستيعاب (خُزِّن، أو وُجد مخزَّنًا، أو حُجب، أو تُخطّي). تجلب المزامنة التالية معرّفات UID الأعلى منه." + }, + imap_synced_at: { + label: "وقت آخر مزامنة", + help: "وقت انتهاء المزامنة آخر مرة من المرور على المجلد." + } + } + }, + sys_mail_message: { + label: "رسالة بريد", + pluralLabel: "رسائل البريد", + description: "رسالة بريد واردة منسوخة من صندوق بريد", + fields: { + id: { + label: "معرّف الرسالة" + }, + mailbox_id: { + label: "صندوق البريد", + help: "صندوق البريد الذي وصلت إليه الرسالة" + }, + message_id: { + label: "Message-ID", + help: "ترويسة Message-ID بعد إزالة الأقواس الزاوية" + }, + in_reply_to: { + label: "In-Reply-To", + help: "ترويسة In-Reply-To: معرّفات الرسائل التي تردّ عليها هذه الرسالة، مفصولة بمسافات" + }, + reference_ids: { + label: "References", + help: "ترويسة References: معرّفات رسائل سلسلة المحادثة، مفصولة بمسافات" + }, + from_address: { + label: "المرسِل", + help: "أول عنوان في From. تُنسخ الرسالة التي لا تحتوي عليه أيضًا ولا تُسقط أبدًا." + }, + from_name: { + label: "اسم المرسِل", + help: "الاسم المعروض لأول عنوان في From" + }, + sender_address: { + label: "Sender", + help: "ترويسة Sender، عندما تحملها الرسالة" + }, + reply_to: { + label: "Reply-To", + help: "عناوين Reply-To مفصولة بفواصل" + }, + to_addresses: { + label: "إلى", + help: "عناوين To مفصولة بفواصل" + }, + cc_addresses: { + label: "نسخة إلى", + help: "عناوين Cc مفصولة بفواصل" + }, + sent_at: { + label: "وقت الإرسال", + help: "ترويسة Date: الوقت الذي يقول المرسِل إن الرسالة كُتبت فيه" + }, + received_at: { + label: "وقت الاستلام", + help: "وقت استلام صندوق البريد للرسالة" + }, + subject: { + label: "الموضوع" + }, + body_text: { + label: "النص (نص عادي)" + }, + body_html: { + label: "النص (HTML)", + help: "جزء HTML كما كتبه المرسِل، يُخزَّن حرفيًا ولا يُعرض أبدًا دون تعقيم" + }, + match_addresses: { + label: "عناوين المطابقة", + help: "عناوين المشاركين التي طوبقت معها السجلات، باستثناء عنوان صندوق البريد نفسه؛ تعيد إعادة المطابقة تشغيل هذه العناوين نفسها تمامًا" + }, + association_state: { + label: "الارتباط", + help: "ما إذا كان أي سجل قد طابق الرسالة. تنتظر الرسالة غير المرتبطة في المجموعة المقيّدة.", + options: { + associated: "مرتبطة", + unassociated: "غير مرتبطة" + } + }, + dedupe_key: { + label: "مفتاح إزالة التكرار", + help: "تجزئة Message-ID بعد التطبيع (أو تجزئة كتلة الترويسات إن لم يوجد)؛ صف واحد لكل رسالة في كل صندوق بريد" + } + } + }, + sys_mail_association: { + label: "ارتباط البريد", + pluralLabel: "ارتباطات البريد", + description: "يربط رسالة واردة منسوخة بالسجل الذي تنتمي إليه", + fields: { + id: { + label: "معرّف الارتباط" + }, + mail_message_id: { + label: "الرسالة" + }, + object_name: { + label: "الكائن", + help: "الاسم البرمجي للكائن الذي ينتمي إليه السجل المرتبط" + }, + record_id: { + label: "معرّف السجل", + help: "معرّف السجل المرتبط، في الكائن المحدد في \"الكائن\"" + }, + matched_address: { + label: "العنوان المطابق", + help: "عنوان المشارك الذي طابق السجل" + }, + matched_field: { + label: "الحقل المطابق", + help: "حقل البريد الإلكتروني في السجل الذي ساوت قيمته العنوان المطابق" + }, + matched_by: { + label: "طريقة المطابقة", + help: "ما إذا كان الربط قد سُجّل عند وصول الرسالة أم أُضيف بإعادة مطابقة لاحقة", + options: { + ingest: "الاستيعاب", + rematch: "إعادة المطابقة" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/ar.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/ar.source-hashes.generated.ts new file mode 100644 index 00000000000..d82be859680 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ar.source-hashes.generated.ts @@ -0,0 +1,27 @@ +// 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 + * `.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> = { + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +}; diff --git a/packages/services/service-mailbox/src/translations/de.objects.generated.ts b/packages/services/service-mailbox/src/translations/de.objects.generated.ts new file mode 100644 index 00000000000..b05c08a12d4 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/de.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'de'. + * 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 deObjects: NonNullable = { + sys_mailbox: { + label: "Postfach", + pluralLabel: "Postfächer", + description: "Ein eingehendes Postfach, dessen E-Mails die Plattform spiegelt: seine Adresse und sein Eigentümer", + fields: { + id: { + label: "Postfach-ID" + }, + name: { + label: "Name", + help: "Anzeigename des Postfachs (zum Beispiel „Vertriebs-Posteingang“)" + }, + address: { + label: "Adresse", + help: "Die Adresse des Postfachs. Wird nie als Teilnehmer abgeglichen: Eine Nachricht an dieses Postfach betrifft nicht das Postfach selbst." + }, + owner_user_id: { + label: "Eigentümer", + help: "Der Benutzer, dem dieses Postfach gehört. Dem Eigentümer wird jede eingegangene Nachricht bereitgestellt, auch nicht zugeordnete." + }, + imap_folder: { + label: "Synchronisierter Ordner", + help: "Der IMAP-Ordner, zu dem der Synchronisierungscursor gehört. Wird das Postfach aus einem anderen Ordner synchronisiert, beginnt der Cursor von vorn." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "Die UIDVALIDITY des Ordners, unter der der Cursor gesetzt wurde. Meldet der Server einen anderen Wert, bezeichnen seine UIDs andere Nachrichten und der Cursor beginnt von vorn." + }, + imap_last_uid: { + label: "Zuletzt synchronisierte UID", + help: "Die höchste UID des Ordners, die bereits an die Aufnahme übergeben wurde (gespeichert, bereits vorhanden, unterdrückt oder übersprungen). Die nächste Synchronisierung holt die UIDs darüber." + }, + imap_synced_at: { + label: "Zuletzt synchronisiert am", + help: "Wann die Synchronisierung zuletzt einen Durchlauf über den Ordner abgeschlossen hat." + } + } + }, + sys_mail_message: { + label: "E-Mail-Nachricht", + pluralLabel: "E-Mail-Nachrichten", + description: "Eingehende Nachricht, aus einem Postfach gespiegelt", + fields: { + id: { + label: "Nachrichten-ID" + }, + mailbox_id: { + label: "Postfach", + help: "Das Postfach, in dem die Nachricht eingegangen ist" + }, + message_id: { + label: "Message-ID", + help: "Der Message-ID-Header, ohne spitze Klammern" + }, + in_reply_to: { + label: "In-Reply-To", + help: "Der In-Reply-To-Header: die Nachrichten-IDs, auf die diese Nachricht antwortet, durch Leerzeichen getrennt" + }, + reference_ids: { + label: "References", + help: "Der References-Header: die Nachrichten-IDs des Threads, durch Leerzeichen getrennt" + }, + from_address: { + label: "Von", + help: "Die erste From-Adresse. Eine Nachricht ohne sie wird trotzdem gespiegelt, nie verworfen." + }, + from_name: { + label: "Absendername", + help: "Der Anzeigename der ersten From-Adresse" + }, + sender_address: { + label: "Sender", + help: "Der Sender-Header, sofern die Nachricht einen trägt" + }, + reply_to: { + label: "Reply-To", + help: "Durch Kommas getrennte Reply-To-Adressen" + }, + to_addresses: { + label: "An", + help: "Durch Kommas getrennte To-Adressen" + }, + cc_addresses: { + label: "Cc", + help: "Durch Kommas getrennte Cc-Adressen" + }, + sent_at: { + label: "Gesendet am", + help: "Der Date-Header: wann die Nachricht laut Absender geschrieben wurde" + }, + received_at: { + label: "Empfangen am", + help: "Wann das Postfach die Nachricht empfangen hat" + }, + subject: { + label: "Betreff" + }, + body_text: { + label: "Inhalt (Text)" + }, + body_html: { + label: "Inhalt (HTML)", + help: "Der HTML-Teil, wie der Absender ihn geschrieben hat, unverändert gespeichert und nie unbereinigt dargestellt" + }, + match_addresses: { + label: "Abgleichadressen", + help: "Die Teilnehmeradressen, mit denen Datensätze abgeglichen wurden, ohne die eigene Adresse des Postfachs; ein erneuter Abgleich verwendet genau diese" + }, + association_state: { + label: "Zuordnung", + help: "Ob ein Datensatz zur Nachricht passte. Eine nicht zugeordnete Nachricht wartet im eingeschränkten Pool.", + options: { + associated: "Zugeordnet", + unassociated: "Nicht zugeordnet" + } + }, + dedupe_key: { + label: "Deduplizierungsschlüssel", + help: "Hash der normalisierten Message-ID (oder des Header-Blocks, wenn keine vorhanden ist); eine Zeile pro Nachricht und Postfach" + } + } + }, + sys_mail_association: { + label: "E-Mail-Zuordnung", + pluralLabel: "E-Mail-Zuordnungen", + description: "Verknüpft eine gespiegelte eingehende Nachricht mit dem Datensatz, zu dem sie gehört", + fields: { + id: { + label: "Zuordnungs-ID" + }, + mail_message_id: { + label: "Nachricht" + }, + object_name: { + label: "Objekt", + help: "Technischer Name des Objekts, zu dem der zugeordnete Datensatz gehört" + }, + record_id: { + label: "Datensatz-ID", + help: "ID des zugeordneten Datensatzes im unter „Objekt“ genannten Objekt" + }, + matched_address: { + label: "Abgeglichene Adresse", + help: "Die Teilnehmeradresse, die zum Datensatz passte" + }, + matched_field: { + label: "Abgeglichenes Feld", + help: "Das E-Mail-Feld des Datensatzes, dessen Wert der abgeglichenen Adresse entsprach" + }, + matched_by: { + label: "Abgeglichen durch", + help: "Ob die Verknüpfung beim Eingang der Nachricht gesetzt oder durch einen späteren erneuten Abgleich hinzugefügt wurde", + options: { + ingest: "Aufnahme", + rematch: "Erneuter Abgleich" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/de.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/de.source-hashes.generated.ts new file mode 100644 index 00000000000..fe46e954da3 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/de.source-hashes.generated.ts @@ -0,0 +1,29 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'de'. 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 + * `.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 deGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_message.fields.cc_addresses.label": "02946d952cf15623", + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", + "objects.sys_mailbox.fields.name.label": "5274417ff1ccaf01", +}; diff --git a/packages/services/service-mailbox/src/translations/fr.objects.generated.ts b/packages/services/service-mailbox/src/translations/fr.objects.generated.ts new file mode 100644 index 00000000000..8c3234f12e5 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/fr.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'fr'. + * 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 frObjects: NonNullable = { + sys_mailbox: { + label: "Boîte aux lettres", + pluralLabel: "Boîtes aux lettres", + description: "Une boîte de réception dont la plateforme reflète le courrier : son adresse et son propriétaire", + fields: { + id: { + label: "ID de la boîte aux lettres" + }, + name: { + label: "Nom", + help: "Nom affiché de la boîte aux lettres (par exemple « Boîte des ventes »)" + }, + address: { + label: "Adresse", + help: "L’adresse de la boîte aux lettres. Jamais rapprochée comme participant : un message adressé à cette boîte ne concerne pas la boîte elle-même." + }, + owner_user_id: { + label: "Propriétaire", + help: "L’utilisateur propriétaire de cette boîte aux lettres. Le propriétaire reçoit chaque message arrivé dans la boîte, y compris ceux non associés." + }, + imap_folder: { + label: "Dossier synchronisé", + help: "Le dossier IMAP auquel appartient le curseur de synchronisation. Si la boîte est synchronisée depuis un autre dossier, le curseur repart de zéro." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "L’UIDVALIDITY du dossier sous lequel le curseur a été pris. Si le serveur annonce une autre valeur, ses UID désignent d’autres messages et le curseur repart de zéro." + }, + imap_last_uid: { + label: "Dernier UID synchronisé", + help: "Le plus grand UID du dossier déjà transmis à l’ingestion (stocké, déjà présent, supprimé ou ignoré). La synchronisation suivante récupère les UID supérieurs." + }, + imap_synced_at: { + label: "Dernière synchronisation", + help: "Moment où la synchronisation a terminé son dernier passage sur le dossier." + } + } + }, + sys_mail_message: { + label: "Message", + pluralLabel: "Messages", + description: "Message entrant reflété depuis une boîte aux lettres", + fields: { + id: { + label: "ID du message" + }, + mailbox_id: { + label: "Boîte aux lettres", + help: "La boîte aux lettres où le message est arrivé" + }, + message_id: { + label: "Message-ID", + help: "L’en-tête Message-ID, chevrons retirés" + }, + in_reply_to: { + label: "In-Reply-To", + help: "L’en-tête In-Reply-To : les identifiants des messages auxquels celui-ci répond, séparés par des espaces" + }, + reference_ids: { + label: "References", + help: "L’en-tête References : les identifiants des messages du fil, séparés par des espaces" + }, + from_address: { + label: "De", + help: "La première adresse From. Un message sans adresse est tout de même reflété, jamais écarté." + }, + from_name: { + label: "Nom de l’expéditeur", + help: "Le nom affiché de la première adresse From" + }, + sender_address: { + label: "Sender", + help: "L’en-tête Sender, lorsque le message en porte un" + }, + reply_to: { + label: "Reply-To", + help: "Adresses Reply-To séparées par des virgules" + }, + to_addresses: { + label: "À", + help: "Adresses To séparées par des virgules" + }, + cc_addresses: { + label: "Cc", + help: "Adresses Cc séparées par des virgules" + }, + sent_at: { + label: "Envoyé le", + help: "L’en-tête Date : le moment où l’expéditeur dit avoir écrit le message" + }, + received_at: { + label: "Reçu le", + help: "Moment où la boîte aux lettres a reçu le message" + }, + subject: { + label: "Objet" + }, + body_text: { + label: "Corps (texte)" + }, + body_html: { + label: "Corps (HTML)", + help: "La partie HTML telle que l’expéditeur l’a écrite, stockée telle quelle et jamais affichée sans assainissement" + }, + match_addresses: { + label: "Adresses de rapprochement", + help: "Les adresses des participants avec lesquelles les enregistrements ont été rapprochés, hors l’adresse de la boîte elle-même ; un nouveau rapprochement rejoue exactement celles-ci" + }, + association_state: { + label: "Association", + help: "Indique si un enregistrement correspond au message. Un message non associé attend dans le pool restreint.", + options: { + associated: "Associé", + unassociated: "Non associé" + } + }, + dedupe_key: { + label: "Clé de dédoublonnage", + help: "Hachage du Message-ID normalisé (ou du bloc d’en-têtes s’il n’y en a pas) ; une ligne par message et par boîte aux lettres" + } + } + }, + sys_mail_association: { + label: "Association de courrier", + pluralLabel: "Associations de courrier", + description: "Relie un message entrant reflété à l’enregistrement auquel il appartient", + fields: { + id: { + label: "ID de l’association" + }, + mail_message_id: { + label: "Message" + }, + object_name: { + label: "Objet", + help: "Nom technique de l’objet auquel appartient l’enregistrement associé" + }, + record_id: { + label: "ID de l’enregistrement", + help: "Identifiant de l’enregistrement associé, dans l’objet indiqué par Objet" + }, + matched_address: { + label: "Adresse rapprochée", + help: "L’adresse du participant qui correspond à l’enregistrement" + }, + matched_field: { + label: "Champ rapproché", + help: "Le champ e-mail de l’enregistrement dont la valeur est égale à l’adresse rapprochée" + }, + matched_by: { + label: "Rapproché par", + help: "Indique si le lien a été posé à l’arrivée du message ou ajouté par un rapprochement ultérieur", + options: { + ingest: "Ingestion", + rematch: "Nouveau rapprochement" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/fr.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/fr.source-hashes.generated.ts new file mode 100644 index 00000000000..558868c0221 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/fr.source-hashes.generated.ts @@ -0,0 +1,30 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'fr'. 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 + * `.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 frGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_association.fields.mail_message_id.label": "2af15199795c25b9", + "objects.sys_mail_message.fields.association_state.label": "84538af43219262a", + "objects.sys_mail_message.fields.cc_addresses.label": "02946d952cf15623", + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +}; diff --git a/packages/services/service-mailbox/src/translations/index.ts b/packages/services/service-mailbox/src/translations/index.ts index 838d1fd20c9..456365f2eca 100644 --- a/packages/services/service-mailbox/src/translations/index.ts +++ b/packages/services/service-mailbox/src/translations/index.ts @@ -17,9 +17,23 @@ import { enObjects } from './en.objects.generated.js'; import { zhCNObjects } from './zh-CN.objects.generated.js'; import { jaJPObjects } from './ja-JP.objects.generated.js'; import { esESObjects } from './es-ES.objects.generated.js'; +import { zhHantObjects } from './zh-Hant.objects.generated.js'; +import { arObjects } from './ar.objects.generated.js'; +import { frObjects } from './fr.objects.generated.js'; +import { ptBRObjects } from './pt-BR.objects.generated.js'; +import { ruObjects } from './ru.objects.generated.js'; +import { deObjects } from './de.objects.generated.js'; +import { koObjects } from './ko.objects.generated.js'; import { zhCNGeneratedSourceHashes } from './zh-CN.source-hashes.generated.js'; import { jaJPGeneratedSourceHashes } from './ja-JP.source-hashes.generated.js'; import { esESGeneratedSourceHashes } from './es-ES.source-hashes.generated.js'; +import { zhHantGeneratedSourceHashes } from './zh-Hant.source-hashes.generated.js'; +import { arGeneratedSourceHashes } from './ar.source-hashes.generated.js'; +import { frGeneratedSourceHashes } from './fr.source-hashes.generated.js'; +import { ptBRGeneratedSourceHashes } from './pt-BR.source-hashes.generated.js'; +import { ruGeneratedSourceHashes } from './ru.source-hashes.generated.js'; +import { deGeneratedSourceHashes } from './de.source-hashes.generated.js'; +import { koGeneratedSourceHashes } from './ko.source-hashes.generated.js'; /** * ## The provenance companions are READ here, not merely recorded @@ -55,4 +69,11 @@ export const MailboxTranslations: TranslationBundle = { 'zh-CN': withSourceFallback({ objects: zhCNObjects }, enSource, undefined, zhCNGeneratedSourceHashes), 'ja-JP': withSourceFallback({ objects: jaJPObjects }, enSource, undefined, jaJPGeneratedSourceHashes), 'es-ES': withSourceFallback({ objects: esESObjects }, enSource, undefined, esESGeneratedSourceHashes), + 'zh-Hant': withSourceFallback({ objects: zhHantObjects }, enSource, undefined, zhHantGeneratedSourceHashes), + 'ar': withSourceFallback({ objects: arObjects }, enSource, undefined, arGeneratedSourceHashes), + 'fr': withSourceFallback({ objects: frObjects }, enSource, undefined, frGeneratedSourceHashes), + 'pt-BR': withSourceFallback({ objects: ptBRObjects }, enSource, undefined, ptBRGeneratedSourceHashes), + 'ru': withSourceFallback({ objects: ruObjects }, enSource, undefined, ruGeneratedSourceHashes), + 'de': withSourceFallback({ objects: deObjects }, enSource, undefined, deGeneratedSourceHashes), + 'ko': withSourceFallback({ objects: koObjects }, enSource, undefined, koGeneratedSourceHashes), }; diff --git a/packages/services/service-mailbox/src/translations/ko.objects.generated.ts b/packages/services/service-mailbox/src/translations/ko.objects.generated.ts new file mode 100644 index 00000000000..5fd324e0883 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ko.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'ko'. + * 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 koObjects: NonNullable = { + sys_mailbox: { + label: "메일함", + pluralLabel: "메일함", + description: "플랫폼이 메일을 미러링하는 수신 메일함: 주소와 소유자", + fields: { + id: { + label: "메일함 ID" + }, + name: { + label: "이름", + help: "메일함의 표시 이름(예: \"영업 받은편지함\")" + }, + address: { + label: "주소", + help: "메일함 주소입니다. 참여자로 매칭되지 않습니다. 이 메일함으로 온 메시지는 메일함 자체에 관한 것이 아니기 때문입니다." + }, + owner_user_id: { + label: "소유자", + help: "이 메일함을 소유한 사용자입니다. 소유자는 연결되지 않은 메시지를 포함해 이 메일함에 도착한 모든 메시지를 받습니다." + }, + imap_folder: { + label: "동기화 폴더", + help: "동기화 커서가 속한 IMAP 폴더입니다. 메일함을 다른 폴더에서 동기화하면 커서가 처음부터 다시 시작합니다." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "커서를 기록할 때의 폴더 UIDVALIDITY입니다. 서버가 다른 값을 보고하면 UID가 다른 메시지를 가리키므로 커서가 처음부터 다시 시작합니다." + }, + imap_last_uid: { + label: "마지막 동기화 UID", + help: "이미 수집 처리로 넘긴 폴더의 최대 UID(저장됨, 이미 저장되어 있음, 억제됨 또는 건너뜀)입니다. 다음 동기화는 그보다 큰 UID를 가져옵니다." + }, + imap_synced_at: { + label: "마지막 동기화 일시", + help: "동기화가 폴더를 마지막으로 한 차례 끝낸 시각입니다." + } + } + }, + sys_mail_message: { + label: "메일 메시지", + pluralLabel: "메일 메시지", + description: "메일함에서 미러링한 수신 메일 메시지", + fields: { + id: { + label: "메시지 ID" + }, + mailbox_id: { + label: "메일함", + help: "메시지가 도착한 메일함" + }, + message_id: { + label: "Message-ID", + help: "꺾쇠괄호를 제거한 Message-ID 헤더" + }, + in_reply_to: { + label: "In-Reply-To", + help: "In-Reply-To 헤더: 이 메시지가 회신하는 메시지 ID(공백으로 구분)" + }, + reference_ids: { + label: "References", + help: "References 헤더: 스레드의 메시지 ID(공백으로 구분)" + }, + from_address: { + label: "보낸 사람", + help: "첫 번째 From 주소입니다. 주소가 없는 메시지도 버리지 않고 미러링합니다." + }, + from_name: { + label: "보낸 사람 이름", + help: "첫 번째 From 주소의 표시 이름" + }, + sender_address: { + label: "Sender", + help: "메시지에 있는 경우 Sender 헤더" + }, + reply_to: { + label: "Reply-To", + help: "쉼표로 구분한 Reply-To 주소" + }, + to_addresses: { + label: "받는 사람", + help: "쉼표로 구분한 To 주소" + }, + cc_addresses: { + label: "참조", + help: "쉼표로 구분한 Cc 주소" + }, + sent_at: { + label: "보낸 일시", + help: "Date 헤더: 보낸 사람이 밝힌 메시지 작성 시각" + }, + received_at: { + label: "받은 일시", + help: "메일함이 메시지를 받은 시각" + }, + subject: { + label: "제목" + }, + body_text: { + label: "본문(텍스트)" + }, + body_html: { + label: "본문(HTML)", + help: "보낸 사람이 작성한 그대로의 HTML 부분으로, 원문 그대로 저장되며 정제하지 않은 채로는 렌더링되지 않습니다" + }, + match_addresses: { + label: "매칭 주소", + help: "레코드 매칭에 사용한 참여자 주소(메일함 자체 주소 제외)이며, 다시 매칭할 때 정확히 이 주소들을 재사용합니다" + }, + association_state: { + label: "연결", + help: "메시지와 매칭된 레코드가 있는지 여부입니다. 연결되지 않은 메시지는 제한된 풀에서 대기합니다.", + options: { + associated: "연결됨", + unassociated: "연결 안 됨" + } + }, + dedupe_key: { + label: "중복 제거 키", + help: "정규화한 Message-ID의 해시(없으면 헤더 블록의 해시)이며, 메일함별로 메시지당 한 행입니다" + } + } + }, + sys_mail_association: { + label: "메일 연결", + pluralLabel: "메일 연결", + description: "미러링된 수신 메시지를 해당 레코드에 연결합니다", + fields: { + id: { + label: "연결 ID" + }, + mail_message_id: { + label: "메시지" + }, + object_name: { + label: "개체", + help: "연결된 레코드가 속한 개체의 시스템 이름" + }, + record_id: { + label: "레코드 ID", + help: "\"개체\"가 가리키는 개체 안에 있는 연결된 레코드의 ID" + }, + matched_address: { + label: "매칭된 주소", + help: "레코드와 매칭된 참여자 주소" + }, + matched_field: { + label: "매칭된 필드", + help: "값이 매칭된 주소와 같은 레코드의 이메일 필드" + }, + matched_by: { + label: "매칭 방식", + help: "메시지가 도착할 때 연결이 기록되었는지, 이후 다시 매칭하여 추가되었는지 여부", + options: { + ingest: "수집", + rematch: "다시 매칭" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/ko.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/ko.source-hashes.generated.ts new file mode 100644 index 00000000000..f3ce68d81ba --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ko.source-hashes.generated.ts @@ -0,0 +1,27 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'ko'. 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 + * `.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 koGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +}; diff --git a/packages/services/service-mailbox/src/translations/pt-BR.objects.generated.ts b/packages/services/service-mailbox/src/translations/pt-BR.objects.generated.ts new file mode 100644 index 00000000000..11c9a259715 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/pt-BR.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'pt-BR'. + * 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 ptBRObjects: NonNullable = { + sys_mailbox: { + label: "Caixa de correio", + pluralLabel: "Caixas de correio", + description: "Uma caixa de entrada cujos e-mails a plataforma espelha: o endereço e o proprietário", + fields: { + id: { + label: "ID da caixa de correio" + }, + name: { + label: "Nome", + help: "Nome de exibição da caixa de correio (por exemplo, \"Caixa de vendas\")" + }, + address: { + label: "Endereço", + help: "O endereço da caixa de correio. Nunca é comparado como participante: uma mensagem para esta caixa não trata da própria caixa." + }, + owner_user_id: { + label: "Proprietário", + help: "O usuário proprietário desta caixa de correio. O proprietário vê todas as mensagens que chegaram a ela, inclusive as não associadas." + }, + imap_folder: { + label: "Pasta sincronizada", + help: "A pasta IMAP à qual pertence o cursor de sincronização. Quando a caixa é sincronizada a partir de outra pasta, o cursor recomeça." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "O UIDVALIDITY da pasta sob o qual o cursor foi obtido. Quando o servidor informa outro valor, seus UIDs indicam outras mensagens e o cursor recomeça." + }, + imap_last_uid: { + label: "Último UID sincronizado", + help: "O maior UID da pasta já entregue à ingestão (armazenado, já encontrado, suprimido ou ignorado). A próxima sincronização busca os UIDs acima dele." + }, + imap_synced_at: { + label: "Última sincronização", + help: "Quando a sincronização terminou a última passagem pela pasta." + } + } + }, + sys_mail_message: { + label: "Mensagem", + pluralLabel: "Mensagens", + description: "Mensagem de entrada espelhada de uma caixa de correio", + fields: { + id: { + label: "ID da mensagem" + }, + mailbox_id: { + label: "Caixa de correio", + help: "A caixa de correio onde a mensagem chegou" + }, + message_id: { + label: "Message-ID", + help: "O cabeçalho Message-ID, sem os sinais de menor e maior" + }, + in_reply_to: { + label: "In-Reply-To", + help: "O cabeçalho In-Reply-To: os IDs das mensagens a que esta responde, separados por espaços" + }, + reference_ids: { + label: "References", + help: "O cabeçalho References: os IDs das mensagens da conversa, separados por espaços" + }, + from_address: { + label: "De", + help: "O primeiro endereço From. Uma mensagem sem ele ainda é espelhada, nunca descartada." + }, + from_name: { + label: "Nome do remetente", + help: "O nome de exibição do primeiro endereço From" + }, + sender_address: { + label: "Sender", + help: "O cabeçalho Sender, quando a mensagem o tem" + }, + reply_to: { + label: "Reply-To", + help: "Endereços Reply-To separados por vírgulas" + }, + to_addresses: { + label: "Para", + help: "Endereços To separados por vírgulas" + }, + cc_addresses: { + label: "Cc", + help: "Endereços Cc separados por vírgulas" + }, + sent_at: { + label: "Enviado em", + help: "O cabeçalho Date: quando o remetente diz que a mensagem foi escrita" + }, + received_at: { + label: "Recebido em", + help: "Quando a caixa de correio recebeu a mensagem" + }, + subject: { + label: "Assunto" + }, + body_text: { + label: "Corpo (texto)" + }, + body_html: { + label: "Corpo (HTML)", + help: "A parte HTML como o remetente a escreveu, armazenada literalmente e nunca exibida sem sanitização" + }, + match_addresses: { + label: "Endereços de correspondência", + help: "Os endereços dos participantes usados para corresponder registros, exceto o endereço da própria caixa; uma nova correspondência repete exatamente estes" + }, + association_state: { + label: "Associação", + help: "Se algum registro correspondeu à mensagem. Uma mensagem não associada aguarda no grupo restrito.", + options: { + associated: "Associada", + unassociated: "Não associada" + } + }, + dedupe_key: { + label: "Chave de desduplicação", + help: "Hash do Message-ID normalizado (ou do bloco de cabeçalhos quando não houver); uma linha por mensagem por caixa de correio" + } + } + }, + sys_mail_association: { + label: "Associação de e-mail", + pluralLabel: "Associações de e-mail", + description: "Vincula uma mensagem de entrada espelhada ao registro a que pertence", + fields: { + id: { + label: "ID da associação" + }, + mail_message_id: { + label: "Mensagem" + }, + object_name: { + label: "Objeto", + help: "Nome técnico do objeto ao qual pertence o registro associado" + }, + record_id: { + label: "ID do registro", + help: "ID do registro associado, no objeto indicado em Objeto" + }, + matched_address: { + label: "Endereço correspondente", + help: "O endereço do participante que correspondeu ao registro" + }, + matched_field: { + label: "Campo correspondente", + help: "O campo de e-mail do registro cujo valor é igual ao endereço correspondente" + }, + matched_by: { + label: "Correspondido por", + help: "Se o vínculo foi registrado quando a mensagem chegou ou adicionado por uma nova correspondência posterior", + options: { + ingest: "Ingestão", + rematch: "Nova correspondência" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/pt-BR.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/pt-BR.source-hashes.generated.ts new file mode 100644 index 00000000000..840436b8fbb --- /dev/null +++ b/packages/services/service-mailbox/src/translations/pt-BR.source-hashes.generated.ts @@ -0,0 +1,28 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'pt-BR'. 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 + * `.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 ptBRGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_message.fields.cc_addresses.label": "02946d952cf15623", + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +}; diff --git a/packages/services/service-mailbox/src/translations/ru.objects.generated.ts b/packages/services/service-mailbox/src/translations/ru.objects.generated.ts new file mode 100644 index 00000000000..c7b02e9a6d2 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ru.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'ru'. + * 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 ruObjects: NonNullable = { + sys_mailbox: { + label: "Почтовый ящик", + pluralLabel: "Почтовые ящики", + description: "Входящий почтовый ящик, письма из которого зеркалирует платформа: его адрес и владелец", + fields: { + id: { + label: "ID почтового ящика" + }, + name: { + label: "Имя", + help: "Отображаемое имя почтового ящика (например, «Входящие отдела продаж»)" + }, + address: { + label: "Адрес", + help: "Адрес почтового ящика. Никогда не сопоставляется как участник: письмо в этот ящик не относится к самому ящику." + }, + owner_user_id: { + label: "Владелец", + help: "Пользователь, которому принадлежит этот почтовый ящик. Владельцу доступно каждое письмо, поступившее в ящик, включая несвязанные." + }, + imap_folder: { + label: "Синхронизируемая папка", + help: "Папка IMAP, к которой относится курсор синхронизации. Если ящик синхронизируется из другой папки, курсор начинается заново." + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "UIDVALIDITY папки, при котором был получен курсор. Если сервер сообщает другое значение, его UID обозначают другие письма, и курсор начинается заново." + }, + imap_last_uid: { + label: "Последний синхронизированный UID", + help: "Наибольший UID папки, уже переданный на приём (сохранён, уже был сохранён, подавлен или пропущен). Следующая синхронизация получит UID выше него." + }, + imap_synced_at: { + label: "Время последней синхронизации", + help: "Когда синхронизация в последний раз завершила проход по папке." + } + } + }, + sys_mail_message: { + label: "Письмо", + pluralLabel: "Письма", + description: "Входящее письмо, зеркалированное из почтового ящика", + fields: { + id: { + label: "ID письма" + }, + mailbox_id: { + label: "Почтовый ящик", + help: "Почтовый ящик, в который пришло письмо" + }, + message_id: { + label: "Message-ID", + help: "Заголовок Message-ID без угловых скобок" + }, + in_reply_to: { + label: "In-Reply-To", + help: "Заголовок In-Reply-To: идентификаторы писем, на которые отвечает это письмо, через пробел" + }, + reference_ids: { + label: "References", + help: "Заголовок References: идентификаторы писем цепочки через пробел" + }, + from_address: { + label: "От", + help: "Первый адрес From. Письмо без него всё равно зеркалируется и никогда не отбрасывается." + }, + from_name: { + label: "Имя отправителя", + help: "Отображаемое имя первого адреса From" + }, + sender_address: { + label: "Sender", + help: "Заголовок Sender, если он есть в письме" + }, + reply_to: { + label: "Reply-To", + help: "Адреса Reply-To через запятую" + }, + to_addresses: { + label: "Кому", + help: "Адреса To через запятую" + }, + cc_addresses: { + label: "Копия", + help: "Адреса Cc через запятую" + }, + sent_at: { + label: "Отправлено", + help: "Заголовок Date: когда, по словам отправителя, письмо было написано" + }, + received_at: { + label: "Получено", + help: "Когда почтовый ящик получил письмо" + }, + subject: { + label: "Тема" + }, + body_text: { + label: "Текст (обычный)" + }, + body_html: { + label: "Текст (HTML)", + help: "HTML-часть в том виде, в каком её написал отправитель; хранится дословно и никогда не отображается без очистки" + }, + match_addresses: { + label: "Адреса для сопоставления", + help: "Адреса участников, с которыми сопоставлялись записи, без собственного адреса ящика; повторное сопоставление воспроизводит именно их" + }, + association_state: { + label: "Связь", + help: "Сопоставилась ли с письмом хотя бы одна запись. Несвязанное письмо ожидает в ограниченном пуле.", + options: { + associated: "Связано", + unassociated: "Не связано" + } + }, + dedupe_key: { + label: "Ключ дедупликации", + help: "Хеш нормализованного Message-ID (или блока заголовков, если его нет); одна строка на письмо в каждом почтовом ящике" + } + } + }, + sys_mail_association: { + label: "Связь письма", + pluralLabel: "Связи писем", + description: "Связывает зеркалированное входящее письмо с записью, к которой оно относится", + fields: { + id: { + label: "ID связи" + }, + mail_message_id: { + label: "Письмо" + }, + object_name: { + label: "Объект", + help: "Системное имя объекта, к которому относится связанная запись" + }, + record_id: { + label: "ID записи", + help: "ID связанной записи в объекте, указанном в поле «Объект»" + }, + matched_address: { + label: "Совпавший адрес", + help: "Адрес участника, совпавший с записью" + }, + matched_field: { + label: "Совпавшее поле", + help: "Поле электронной почты записи, значение которого совпало с адресом" + }, + matched_by: { + label: "Способ сопоставления", + help: "Была ли связь проставлена при поступлении письма или добавлена позднейшим повторным сопоставлением", + options: { + ingest: "Приём", + rematch: "Повторное сопоставление" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/ru.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/ru.source-hashes.generated.ts new file mode 100644 index 00000000000..ea9b7eff09e --- /dev/null +++ b/packages/services/service-mailbox/src/translations/ru.source-hashes.generated.ts @@ -0,0 +1,27 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'ru'. 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 + * `.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 ruGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +}; diff --git a/packages/services/service-mailbox/src/translations/zh-Hant.objects.generated.ts b/packages/services/service-mailbox/src/translations/zh-Hant.objects.generated.ts new file mode 100644 index 00000000000..2314f5a47f4 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/zh-Hant.objects.generated.ts @@ -0,0 +1,177 @@ +// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'zh-Hant'. + * 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 zhHantObjects: NonNullable = { + sys_mailbox: { + label: "郵件信箱", + pluralLabel: "郵件信箱", + description: "平台從中鏡像入站郵件的信箱:其地址與擁有者", + fields: { + id: { + label: "信箱 ID" + }, + name: { + label: "名稱", + help: "信箱的顯示名稱(例如「業務收件匣」)" + }, + address: { + label: "地址", + help: "信箱地址。它從不作為參與者進行比對:寄到此信箱的郵件與信箱本身無關。" + }, + owner_user_id: { + label: "擁有者", + help: "擁有此信箱的使用者。擁有者可讀取到達此信箱的每一封郵件,包括未關聯的郵件。" + }, + imap_folder: { + label: "同步資料夾", + help: "同步游標所屬的 IMAP 資料夾。信箱改從其他資料夾同步時,游標會從頭開始。" + }, + imap_uid_validity: { + label: "UIDVALIDITY", + help: "游標所依據的資料夾 UIDVALIDITY。伺服器回報其他值時,其 UID 指向其他郵件,游標會從頭開始。" + }, + imap_last_uid: { + label: "最後同步的 UID", + help: "已交給接收處理的資料夾最高 UID(已儲存、已存在、已抑制或已略過)。下次同步會擷取高於它的 UID。" + }, + imap_synced_at: { + label: "最後同步時間", + help: "同步最近一次完成整個資料夾讀取的時間。" + } + } + }, + sys_mail_message: { + label: "郵件", + pluralLabel: "郵件", + description: "從信箱鏡像的入站郵件", + fields: { + id: { + label: "郵件 ID" + }, + mailbox_id: { + label: "信箱", + help: "郵件到達的信箱" + }, + message_id: { + label: "Message-ID", + help: "Message-ID 郵件標頭,已去除角括號" + }, + in_reply_to: { + label: "In-Reply-To", + help: "In-Reply-To 郵件標頭:本郵件所回覆郵件的 ID,以空格分隔" + }, + reference_ids: { + label: "References", + help: "References 郵件標頭:對話中各郵件的 ID,以空格分隔" + }, + from_address: { + label: "寄件者", + help: "第一個寄件者地址。沒有寄件者的郵件仍會被鏡像,絕不捨棄。" + }, + from_name: { + label: "寄件者名稱", + help: "第一個寄件者地址的顯示名稱" + }, + sender_address: { + label: "Sender", + help: "Sender 郵件標頭(若郵件帶有)" + }, + reply_to: { + label: "Reply-To", + help: "以逗號分隔的 Reply-To 地址" + }, + to_addresses: { + label: "收件者", + help: "以逗號分隔的收件者地址" + }, + cc_addresses: { + label: "副本", + help: "以逗號分隔的副本地址" + }, + sent_at: { + label: "寄送時間", + help: "Date 郵件標頭:寄件者聲明的郵件撰寫時間" + }, + received_at: { + label: "接收時間", + help: "信箱收到郵件的時間" + }, + subject: { + label: "主旨" + }, + body_text: { + label: "內文(文字)" + }, + body_html: { + label: "內文(HTML)", + help: "寄件者撰寫的 HTML 部分,依原樣儲存,絕不在未淨化的情況下呈現" + }, + match_addresses: { + label: "比對地址", + help: "用於比對記錄的參與者地址(不含信箱本身的地址);重新比對時依原樣重播這些地址" + }, + association_state: { + label: "關聯", + help: "是否有記錄與該郵件比對成功。未關聯的郵件會在受限池中等待。", + options: { + associated: "已關聯", + unassociated: "未關聯" + } + }, + dedupe_key: { + label: "去重鍵", + help: "正規化 Message-ID 的雜湊(若無,則為郵件標頭區塊的雜湊);每個信箱中每封郵件一列" + } + } + }, + sys_mail_association: { + label: "郵件關聯", + pluralLabel: "郵件關聯", + description: "將鏡像的入站郵件連結到其所屬的記錄", + fields: { + id: { + label: "關聯 ID" + }, + mail_message_id: { + label: "郵件" + }, + object_name: { + label: "物件", + help: "關聯記錄所屬物件的機器名稱" + }, + record_id: { + label: "記錄 ID", + help: "關聯記錄的 ID,位於「物件」所指的物件中" + }, + matched_address: { + label: "比對到的地址", + help: "與該記錄比對成功的參與者地址" + }, + matched_field: { + label: "比對到的欄位", + help: "記錄中其值等於比對地址的電子郵件欄位" + }, + matched_by: { + label: "比對方式", + help: "此連結是在郵件到達時寫入,還是由之後的重新比對新增", + options: { + ingest: "接收", + rematch: "重新比對" + } + } + } + } +}; diff --git a/packages/services/service-mailbox/src/translations/zh-Hant.source-hashes.generated.ts b/packages/services/service-mailbox/src/translations/zh-Hant.source-hashes.generated.ts new file mode 100644 index 00000000000..4c061886604 --- /dev/null +++ b/packages/services/service-mailbox/src/translations/zh-Hant.source-hashes.generated.ts @@ -0,0 +1,27 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +/** + * Auto-generated by 'os i18n extract' for locale 'zh-Hant'. 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 + * `.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 zhHantGeneratedSourceHashes: Readonly> = { + "objects.sys_mail_message.fields.in_reply_to.label": "71bb10a36255d815", + "objects.sys_mail_message.fields.message_id.label": "14cd089a4062f4b1", + "objects.sys_mail_message.fields.reference_ids.label": "5102fd1664d35c0b", + "objects.sys_mail_message.fields.reply_to.label": "90ad8f2ca791a95a", + "objects.sys_mail_message.fields.sender_address.label": "89db06253eee9632", + "objects.sys_mailbox.fields.imap_uid_validity.label": "5a2ec2b384b73bb0", +};