Skip to content

Commit 561d532

Browse files
i18n(plugin-sharing): ship the sharing and queue objects in all eleven platform languages (#30767)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D7v5H7BaFmL7sUCoN7tSxhm)_ domain:server#1 · os-elon-musk · session_016WV4cya5ej5GQV86RPbRPK Part of #30512 — package 8 of 11 (`@objectstack/plugin-sharing`). The card stays open: approvals, settings and platform-objects follow, and the last PR of the series makes the bundle check read the platform locale table. Clause-②: no Metadata-protocol: none ## 维护者速读 - **改了什么:** 共享插件的 5 个对象(记录共享、共享规则、共享链接、队列、队列成员)的名称、字段、选项、帮助和视图名,补上繁中、阿语、法语、巴葡、俄语、德语、韩语 7 种,与平台语言表的 11 种一致。队列和队列成员也在内;队列记录页的标题也补了这 7 种(与各语言队列对象名同词)。 - **为什么改:** 平台语言表要求每个界面带齐 11 种语言;这是第 3 期按包补齐的第 8 个包(每种语言 151 条)。用这 7 种语言的管理员打开「设置 → 共享规则 / 队列」不再看到英文。 - **风险与回滚:** 只加翻译数据和注册行,不动逻辑、schema、接口;原有 4 种语言一字未改。唯一的测试改动是「收件人类型在各对象上叫法一致」的测试多扫 7 种语言(覆盖变宽,没有放宽任何断言)。回滚即撤 PR。 - **先看:** `src/translations/index.ts`(按表标签注册,zh-CN 在 zh-Hant 前,每种语言带上页面标题)、`src/translations/pages.ts`(手写的队列页标题表),再看 `recipient-vocabulary-consistency.test.ts`,最后抽看任一语言的 `sys_queue` 段。 - **两分钟验证:** `node scripts/check-i18n-bundles.mjs --filter=sharing` 输出 `plugins/plugin-sharing in sync`;`pnpm --filter @objectstack/plugin-sharing test` 全绿。 - **需要你做的:** 无,席位落地。 ## What changes - Seven new locales for the sharing package under the platform locale table's tags (`zh-Hant`, `ar`, `fr`, `pt-BR`, `ru`, `de`, `ko`): each a `TAG.objects.generated.ts` with all 151 object leaves of `sys_record_share`, `sys_sharing_rule`, `sys_share_link`, `sys_queue` and `sys_queue_member`, plus its `TAG.source-hashes.generated.ts`, written by the repo's own `os i18n extract --fill=default --source-hashes` and served through `withSourceFallback` like the existing three. `zh-CN` stays ahead of `zh-Hant` in `index.ts`. - The hand-written page table `src/translations/pages.ts` (the queue record page `sys_queue_detail`, from #30728) gains an entry per new locale. Each value is the locale's own `sys_queue` object label, so the page title and the object read the same word, and each records the same `en` digest the existing three carry. `index.ts` passes each new locale's `pages` entry and its recorded digest to `withSourceFallback`, like the existing three. - The extract command in `scripts/i18n-extract.config.ts` lists the seven tags and its merge baseline imports the seven bundles with their page entries, so `check:i18n` covers them from this PR on. ## Tests - `recipient-vocabulary-consistency.test.ts` (each recipient option reads the same on every object that offers it, within a locale) adds the seven new bundles to its list. Coverage widens; no assertion changed. - `sys-queue-page.test.ts` already iterates every locale of `SharingTranslations` and checks the served page label equals the table's, so the seven new page labels are held to it with no test edit. ## Acceptance notes - **Quality bar (#17508 / PR #19345):** every leaf written for the reader; placeholders, code spans and identifiers byte-identical, checked mechanically per leaf against `en` (key set, `{{holes}}`, `{holes}`, backtick spans, angle tokens: all seven locales OK, zero diffs). Arabic is RTL prose with identifiers left in Latin script. `zh-Hant` was checked character by character against OpenCC's Traditional (Taiwan) conversion: no Simplified-only character remains. - **Leaves equal to English, on purpose, each recorded by the extractor as a source copy:** `fr` `Source`, `Description` (x2), `Audience`, `Public (indexable)`; `pt-BR` `Token`; `de` `Name` (x2), `Team` (x2), `Position` (x3), `Token`. All are the native words. - No cross-locale coincidence: `check:i18n-stale-fill` passes with the baseline untouched. - **Observation, not changed here:** the queue page's members list title in `src/sys-queue.page.ts` is an inline locale map with four entries (`en`, `zh-CN`, `ja-JP`, `es-ES`), none for the seven new locales. It is page prose outside this PR's surface. - **Deviation from the handover commit:** carried from the released handover commit `ec0e96dc` (session `session_01Utp6Cai5CRdAs4u9gTipWU`), with one addition: main gained the queue record page and its hand-written four-locale `pages` section (#30728) after that commit was written, so the commit's `index.ts` and extract-config hunks conflicted. The resolution keeps #30728's wiring and adds the seven locales through it, which needed the seven page labels in `pages.ts`. The 14 generated bundle and source-hash files and the test change are byte-identical to the handover commit (blob ids compared); the changeset gains one sentence for the page title. The serial row "after #30208 lands" was cleared by the seat (6672288503): #30208 row 7, which first put `sys_queue` / `sys_queue_member` into this package's extract, landed in PR #30551. ## Verification <details><summary>Package suite, typecheck, build (verify lock)</summary> ``` turbo run build --filter=!@objectstack/docs: 118/118 tasks successful, exit 0 pnpm --filter @objectstack/plugin-sharing test && typecheck (at head dc12d9d, on main e00bcc6) Test Files 67 passed (67) Tests 1424 passed (1424) check:test-typecheck: OK (tsconfig.test.json) os-verify-lock: VERDICT command-exit 0 same suite at cb13b51f (the same patch on main e8dc483): 67 files, 1424 passed, VERDICT command-exit 0 ``` </details> <details><summary>i18n gates and the derived families</summary> ``` node scripts/check-i18n-bundles.mjs --filter=sharing (at dc12d9d) plugins/plugin-sharing in sync (21 bundle(s)) EXIT 0 node scripts/check-i18n-stale-fill.mjs (at dc12d9d) check-i18n-stale-fill: OK (11 bundle set(s) — no new stale fills, 1 baselined). EXIT 0 dispatch-gates --commands (at cb13b51f): 61 families, each run and recorded with its exit code: 61 x exit 0 dispatch-gates --ran: 61 derived, 61 run, 0 NOT-MEASURED (a derived zero) re-derived at dc12d9d's tree: the identical 61-command list pnpm lint (repo-wide, at cb13b51f): exit 0 eslint --no-inline-config on the changed .ts files: exit 0 changed lines 2694 (+2691 / -3), 19 files: under the 3000-line human-merge threshold ``` </details> The branch is one commit on `main` `e00bcc6a` (after #30744 landed). Its diff has the same patch id (`3f616c44`) as `cb13b51f`, where the derived families ran on main `e8dc4833`; none of the five main commits in between touches `plugin-sharing` (they are #30744 itself, #30734 in service-settings, plugin-auth, plugin-email and service-sms, and three in cloud-connection, the dispatch skill and the UI packages). The package suite and both i18n checks were re-run on this head's tree. Dogfood: not run — content-only package PR, no `!` in the title and no `(narrowing)` arm. --- _Generated by [Claude Code](https://claude.ai/code/session_016WV4cya5ej5GQV86RPbRPK)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1371b9d commit 561d532

19 files changed

Lines changed: 2691 additions & 3 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/plugin-sharing': patch
3+
---
4+
5+
i18n(plugin-sharing): the sharing and queue objects ship in all eleven platform languages
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The sharing objects (`sys_record_share`, `sys_sharing_rule`, `sys_share_link`) and the queue objects (`sys_queue`, `sys_queue_member`) now carry `zh-Hant`, `ar`, `fr`, `pt-BR`, `ru`, `de` and `ko` beside the existing `en`, `zh-CN`, `ja-JP` and `es-ES`, so an administrator in one of those languages reads the sharing and queue screens in their own language instead of English. Each recipient option reads the same on every object within a locale. The queue record page (`sys_queue_detail`) carries its title in the seven languages too, the same word as the queue object's own label. Each new locale is registered under its platform-table tag with its source-hash companion, and the package's extract command lists the tags, so the existing `check:i18n` bundle check covers them. Package 8 of #30512.

‎packages/plugins/plugin-sharing/scripts/i18n-extract.config.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* strings were seeded from @objectstack/platform-objects.)
99
*
1010
* os i18n extract packages/plugins/plugin-sharing/scripts/i18n-extract.config.ts \
11-
* --locales=zh-CN,ja-JP,es-ES --fill=default --objects-only --no-metadata-forms \
11+
* --locales=zh-CN,ja-JP,es-ES,zh-Hant,ar,fr,pt-BR,ru,de,ko --fill=default --objects-only --no-metadata-forms \
1212
* --source-hashes \
1313
* --out=packages/plugins/plugin-sharing/src/translations
1414
*
@@ -48,6 +48,13 @@ import { enObjects } from '../src/translations/en.objects.generated.js';
4848
import { zhCNObjects } from '../src/translations/zh-CN.objects.generated.js';
4949
import { jaJPObjects } from '../src/translations/ja-JP.objects.generated.js';
5050
import { esESObjects } from '../src/translations/es-ES.objects.generated.js';
51+
import { zhHantObjects } from '../src/translations/zh-Hant.objects.generated.js';
52+
import { arObjects } from '../src/translations/ar.objects.generated.js';
53+
import { frObjects } from '../src/translations/fr.objects.generated.js';
54+
import { ptBRObjects } from '../src/translations/pt-BR.objects.generated.js';
55+
import { ruObjects } from '../src/translations/ru.objects.generated.js';
56+
import { deObjects } from '../src/translations/de.objects.generated.js';
57+
import { koObjects } from '../src/translations/ko.objects.generated.js';
5158
import { SysQueueDetailPage } from '../src/sys-queue.page.js';
5259
import { sharingPageTranslations } from '../src/translations/pages.js';
5360

@@ -73,6 +80,13 @@ const config: ObjectStackDefinition = defineStack({
7380
{ 'zh-CN': { objects: zhCNObjects, pages: sharingPageTranslations['zh-CN'] } },
7481
{ 'ja-JP': { objects: jaJPObjects, pages: sharingPageTranslations['ja-JP'] } },
7582
{ 'es-ES': { objects: esESObjects, pages: sharingPageTranslations['es-ES'] } },
83+
{ 'zh-Hant': { objects: zhHantObjects, pages: sharingPageTranslations['zh-Hant'] } },
84+
{ 'ar': { objects: arObjects, pages: sharingPageTranslations['ar'] } },
85+
{ 'fr': { objects: frObjects, pages: sharingPageTranslations['fr'] } },
86+
{ 'pt-BR': { objects: ptBRObjects, pages: sharingPageTranslations['pt-BR'] } },
87+
{ 'ru': { objects: ruObjects, pages: sharingPageTranslations['ru'] } },
88+
{ 'de': { objects: deObjects, pages: sharingPageTranslations['de'] } },
89+
{ 'ko': { objects: koObjects, pages: sharingPageTranslations['ko'] } },
7690
],
7791
});
7892

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
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_record_share: {
19+
label: "مشاركة السجل",
20+
pluralLabel: "مشاركات السجلات",
21+
description: "سجلات مُشارَكة مع غير مالكها، صف واحد لكل منح.",
22+
fields: {
23+
id: {
24+
label: "معرّف المشاركة"
25+
},
26+
object_name: {
27+
label: "الكائن",
28+
help: "الاسم المختصر لكائن السجل المُشارَك"
29+
},
30+
record_id: {
31+
label: "السجل",
32+
help: "المفتاح الأساسي للسجل المُشارَك ضمن object_name"
33+
},
34+
recipient_type: {
35+
label: "نوع المستلِم",
36+
help: "نوع الجهة التي تحمل المنح",
37+
options: {
38+
user: "المستخدم",
39+
group: "المجموعة",
40+
position: "المنصب",
41+
unit_and_subordinates: "وحدة الأعمال والوحدات التابعة لها"
42+
}
43+
},
44+
recipient_id: {
45+
label: "المستلِم",
46+
help: "معرّف المستخدم أو المجموعة أو المنصب الذي يحصل على الوصول"
47+
},
48+
access_level: {
49+
label: "مستوى الوصول",
50+
help: "ما يمكن للمستلِم فعله — القراءة، أو القراءة والتحرير",
51+
options: {
52+
read: "قراءة",
53+
edit: "قراءة وتحرير"
54+
}
55+
},
56+
source: {
57+
label: "المصدر",
58+
help: "سبب وجود هذا المنح — يستخدمه مقيِّم القواعد للمطابقة",
59+
options: {
60+
manual: "يدوي",
61+
rule: "قاعدة",
62+
team: "الفريق",
63+
inherited: "موروث"
64+
}
65+
},
66+
source_id: {
67+
label: "معرّف المصدر",
68+
help: "اسم القاعدة أو معرّف الفريق عندما يكون source != manual"
69+
},
70+
granted_by: {
71+
label: "مَن منحه",
72+
help: "المستخدم الذي أنشأ المنح (يدويًا فقط)"
73+
},
74+
reason: {
75+
label: "السبب",
76+
help: "شرح نصي حر اختياري يُعرض للمستلِم"
77+
},
78+
created_at: {
79+
label: "تاريخ الإنشاء"
80+
},
81+
updated_at: {
82+
label: "تاريخ التحديث"
83+
}
84+
},
85+
_views: {
86+
all_shares: {
87+
label: "الكل"
88+
},
89+
granted_to_me: {
90+
label: "الممنوحة لي"
91+
},
92+
granted_by_me: {
93+
label: "التي منحتُها"
94+
},
95+
by_object: {
96+
label: "حسب الكائن"
97+
},
98+
manual_grants: {
99+
label: "منح يدوية"
100+
},
101+
rule_grants: {
102+
label: "منح بالقواعد"
103+
}
104+
}
105+
},
106+
sys_sharing_rule: {
107+
label: "قاعدة المشاركة",
108+
pluralLabel: "قواعد المشاركة",
109+
description: "يمنح مجموعة من الأشخاص الوصول إلى السجلات المطابقة لشرط.",
110+
fields: {
111+
id: {
112+
label: "معرّف القاعدة"
113+
},
114+
organization_id: {
115+
label: "المؤسسة",
116+
help: "المؤسسة التي تنتمي إليها هذه القاعدة."
117+
},
118+
name: {
119+
label: "الاسم",
120+
help: "يعرّف القاعدة. أحرف لاتينية صغيرة وأرقام وشرطات سفلية فقط."
121+
},
122+
label: {
123+
label: "التسمية المعروضة"
124+
},
125+
description: {
126+
label: "الوصف"
127+
},
128+
object_name: {
129+
label: "الكائن",
130+
help: "الكائن الذي تشارك هذه القاعدة سجلاته."
131+
},
132+
criteria_json: {
133+
label: "المعايير",
134+
help: "أي السجلات تُشارَك. مطلوب — يجب أن تضيّق القاعدة السجلات التي تشاركها، لذا لا يوجد إعداد «مشاركة كل السجلات»."
135+
},
136+
recipient_type: {
137+
label: "نوع المستلِم",
138+
help: "مَن يحصل على الوصول. اختيار فريق أو وحدة أعمال أو منصب أو قائمة انتظار يمنح الوصول لكل من فيها. ويشمل «وحدة الأعمال والوحدات التابعة لها» أيضًا كل وحدة أدنى من الوحدة المختارة. أما «الحقل» فيشارك كل سجل مع المستخدم أو المستخدمين المحفوظين في أحد حقوله — اذكر ذلك الحقل بوصفه المستلِم.",
139+
options: {
140+
user: "المستخدم",
141+
team: "الفريق",
142+
business_unit: "وحدة الأعمال",
143+
position: "المنصب",
144+
unit_and_subordinates: "وحدة الأعمال والوحدات التابعة لها",
145+
queue: "قائمة الانتظار",
146+
field: "الحقل"
147+
}
148+
},
149+
recipient_id: {
150+
label: "المستلِم",
151+
help: "المستخدم أو الفريق أو وحدة الأعمال أو المنصب أو قائمة الانتظار المحدَّد الذي يحصل على الوصول — أو، لنوع المستلِم «الحقل»، اسم حقل السجل الذي يحفظ المستخدم أو المستخدمين المُشارَك معهم."
152+
},
153+
access_level: {
154+
label: "مستوى الوصول",
155+
help: "ما يمكن للمستلمين فعله بالسجلات المطابقة — قراءتها، أو قراءتها وتحريرها.",
156+
options: {
157+
read: "قراءة",
158+
edit: "قراءة وتحرير"
159+
}
160+
},
161+
active: {
162+
label: "نشِط",
163+
help: "أوقفه لسحب الوصول الذي منحته هذه القاعدة دون حذفها."
164+
},
165+
managed_by: {
166+
label: "مصدر الإدارة",
167+
help: "مصدر هذه القاعدة: مدمجة في المنصة، أو مثبّتة مع تطبيق، أو أُنشئت هنا في الإعداد.",
168+
options: {
169+
platform: "المنصة",
170+
package: "الحزمة",
171+
admin: "المسؤول"
172+
}
173+
},
174+
customized: {
175+
label: "مخصَّصة",
176+
help: "يُضبط عند تحريرك قاعدة جاءت مع تطبيق، فتُحفظ تغييراتك عند تحديث التطبيق."
177+
},
178+
created_at: {
179+
label: "تاريخ الإنشاء"
180+
},
181+
updated_at: {
182+
label: "تاريخ التحديث"
183+
}
184+
},
185+
_views: {
186+
active: {
187+
label: "نشِط"
188+
},
189+
inactive: {
190+
label: "غير نشِط"
191+
},
192+
by_object: {
193+
label: "حسب الكائن"
194+
},
195+
all_rules: {
196+
label: "الكل"
197+
}
198+
}
199+
},
200+
sys_share_link: {
201+
label: "رابط المشاركة",
202+
pluralLabel: "روابط المشاركة",
203+
description: "رمز قدرة مُبهم يمنح الوصول إلى سجل واحد. مشاركة عبر رابط عام على طريقة Notion/Figma.",
204+
fields: {
205+
id: {
206+
label: "معرّف الرابط"
207+
},
208+
token: {
209+
label: "الرمز",
210+
help: "رمز عشوائي مُبهم آمن للاستخدام في URL (≥ 22 حرفًا). السر الوحيد في هذا الصف."
211+
},
212+
object_name: {
213+
label: "الكائن",
214+
help: "الاسم المختصر لكائن السجل المُشارَك (مثل ai_conversation و contracts_contract)"
215+
},
216+
record_id: {
217+
label: "السجل",
218+
help: "المفتاح الأساسي للسجل المُشارَك ضمن object_name"
219+
},
220+
permission: {
221+
label: "الإذن",
222+
help: "ما يمكن لحامل الرابط فعله بالسجل",
223+
options: {
224+
view: "عرض",
225+
comment: "تعليق",
226+
edit: "تحرير"
227+
}
228+
},
229+
audience: {
230+
label: "الجمهور",
231+
help: "طبقة تقييد تُطبَّق فوق التحقق من الرمز",
232+
options: {
233+
public: "عام (قابل للفهرسة)",
234+
link_only: "أي شخص لديه الرابط",
235+
signed_in: "المستخدمون المسجّلون الدخول",
236+
email: "عناوين بريد محددة"
237+
}
238+
},
239+
expires_at: {
240+
label: "تاريخ الانتهاء",
241+
help: "عند ضبطه، يعيد resolveToken القيمة null بعد هذا الطابع الزمني"
242+
},
243+
email_allowlist: {
244+
label: "قائمة البريد المسموح",
245+
help: "عناوين بأحرف صغيرة يُتحقق منها عندما audience=email"
246+
},
247+
password_hash: {
248+
label: "تجزئة كلمة المرور",
249+
help: "تجزئة Argon2/bcrypt. عند ضبطها، تطلب الواجهة كلمة مرور قبل العرض."
250+
},
251+
redact_fields: {
252+
label: "الحقول المحجوبة لكل رابط",
253+
help: "حقول إضافية تُزال من الاستجابة، فوق المجموعة الافتراضية للكائن"
254+
},
255+
label: {
256+
label: "التسمية",
257+
help: "نص حر يظهر في نافذة المشاركة (مثل «عقد ACME Q3»)"
258+
},
259+
revoked_at: {
260+
label: "تاريخ الإلغاء",
261+
help: "عند ضبطه، يُعطَّل الرابط نهائيًا"
262+
},
263+
created_by: {
264+
label: "المُنشئ",
265+
help: "مُصدِر الرابط"
266+
},
267+
created_at: {
268+
label: "تاريخ الإنشاء"
269+
},
270+
last_used_at: {
271+
label: "آخر استخدام",
272+
help: "يختمه resolveToken؛ وتستخدمه لوحة المعلومات لإبراز الروابط النشطة"
273+
},
274+
use_count: {
275+
label: "عدد مرات الاستخدام",
276+
help: "يزيده resolveToken عند كل تحليل ناجح"
277+
}
278+
},
279+
_views: {
280+
active_links: {
281+
label: "نشطة"
282+
},
283+
by_me: {
284+
label: "أنشأتُها"
285+
},
286+
revoked: {
287+
label: "ملغاة"
288+
},
289+
all_links: {
290+
label: "الكل"
291+
}
292+
}
293+
},
294+
sys_queue: {
295+
label: "قائمة الانتظار",
296+
pluralLabel: "قوائم الانتظار",
297+
description: "مجموعة مسمّاة من الأشخاص تنتظر فيها السجلات غير المسندة حتى يتولاها أحدهم.",
298+
fields: {
299+
name: {
300+
label: "الاسم",
301+
help: "يعرّف قائمة الانتظار أينما استُخدمت — في السجلات وقواعد الإسناد والموافقات وقواعد المشاركة. أحرف لاتينية صغيرة وأرقام وشرطات سفلية فقط."
302+
},
303+
label: {
304+
label: "الاسم المعروض"
305+
},
306+
description: {
307+
label: "الوصف"
308+
}
309+
},
310+
_views: {
311+
all_queues: {
312+
label: "الكل"
313+
}
314+
}
315+
},
316+
sys_queue_member: {
317+
label: "عضو قائمة الانتظار",
318+
pluralLabel: "أعضاء قائمة الانتظار",
319+
description: "مَن ينتمي إلى قائمة الانتظار: مستخدم أو فريق أو منصب أو وحدة أعمال.",
320+
fields: {
321+
queue: {
322+
label: "قائمة الانتظار",
323+
help: "اسم قائمة الانتظار التي ينتمي إليها هذا العضو."
324+
},
325+
recipient_type: {
326+
label: "نوع العضو",
327+
help: "نوع هذا العضو. الفريق أو المنصب أو وحدة الأعمال يجعل كل من فيه عضوًا. ويشمل «وحدة الأعمال والوحدات التابعة لها» أيضًا كل وحدة أدنى من الوحدة المختارة.",
328+
options: {
329+
user: "المستخدم",
330+
team: "الفريق",
331+
position: "المنصب",
332+
business_unit: "وحدة الأعمال",
333+
unit_and_subordinates: "وحدة الأعمال والوحدات التابعة لها"
334+
}
335+
},
336+
recipient_id: {
337+
label: "العضو",
338+
help: "المستخدم أو الفريق أو المنصب أو وحدة الأعمال المحدَّد."
339+
}
340+
},
341+
_views: {
342+
by_queue: {
343+
label: "حسب قائمة الانتظار"
344+
}
345+
}
346+
}
347+
};

0 commit comments

Comments
 (0)