Skip to content

Commit e4e8d3f

Browse files
os-zhuangclaude
andauthored
feat(access): localize capability picker group headers (#2600 B5, objectui side) (#2653)
The System Capabilities picker rendered its scope group headers ("PLATFORM" / "ORGANIZATION" / "OTHER") as hardcoded English strings, even in a Chinese UI. Route them through the field translation bundle (`capability.group.<scope>`) and add the strings to every locale (zh: 平台 / 组织 / 其他; others translated, all falling back to en). The capability *labels themselves* (Manage Metadata, Studio Access, …) come from the sys_capability registry and stay as-is — their per-locale localization is a registry concern tracked separately (framework). Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4d6fb92 commit e4e8d3f

12 files changed

Lines changed: 96 additions & 8 deletions

File tree

packages/fields/src/widgets/CapabilityMultiSelectField.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Badge, EmptyValue, cn } from '@object-ui/components';
33
import { SchemaRendererContext } from '@object-ui/react';
44
import type { DataSource, QueryParams } from '@object-ui/types';
55
import { FieldWidgetProps } from './types';
6+
import { useFieldTranslation } from './useFieldTranslation';
67

78
/**
89
* CapabilityMultiSelectField — structured picker for a permission set's
@@ -54,13 +55,13 @@ export function parseCapabilityNames(value: unknown): string[] {
5455
return [];
5556
}
5657

57-
/** Scope → group header. Order is intentional (platform powers first). */
58+
/**
59+
* Scope → group header order (platform powers first). The visible header is
60+
* localized via `capability.group.<scope>` (objectui#2600 B5) — the capability
61+
* *labels themselves* still come from the sys_capability registry, whose
62+
* per-locale localization is tracked separately (framework).
63+
*/
5864
const SCOPE_ORDER = ['platform', 'org', 'other'] as const;
59-
const SCOPE_LABEL: Record<string, string> = {
60-
platform: 'Platform',
61-
org: 'Organization',
62-
other: 'Other',
63-
};
6465

6566
export function CapabilityMultiSelectField({
6667
value,
@@ -69,6 +70,7 @@ export function CapabilityMultiSelectField({
6970
className,
7071
...props
7172
}: FieldWidgetProps<string | string[]>) {
73+
const { t } = useFieldTranslation();
7274
const ctx = React.useContext(SchemaRendererContext);
7375
const dataSource: DataSource | null =
7476
(props as any).dataSource ?? (ctx as any)?.dataSource ?? null;
@@ -135,12 +137,12 @@ export function CapabilityMultiSelectField({
135137
}
136138
return SCOPE_ORDER.filter((s) => buckets.has(s)).map((s) => ({
137139
scope: s,
138-
label: SCOPE_LABEL[s] ?? s,
140+
label: t(`capability.group.${s}`),
139141
items: (buckets.get(s) ?? []).sort((a, b) =>
140142
(a.label || a.name).localeCompare(b.label || b.name),
141143
),
142144
}));
143-
}, [byName]);
145+
}, [byName, t]);
144146

145147
if (readonly) {
146148
if (selected.length === 0) return <EmptyValue />;

packages/fields/src/widgets/useFieldTranslation.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const FIELD_DEFAULTS: Record<string, string> = {
3939
'lookup.nextPage': 'Next page',
4040
'lookup.jumpToPage': 'Jump to page',
4141
'lookup.retry': 'Retry',
42+
// objectui#2600 B5 — capability picker scope group headers.
43+
'capability.group.platform': 'Platform',
44+
'capability.group.org': 'Organization',
45+
'capability.group.other': 'Other',
4246
};
4347

4448
export const useFieldTranslation = createSafeTranslation(

packages/i18n/src/locales/ar.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const ar = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'منصة',
6+
org: 'منظمة',
7+
other: 'أخرى',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: 'المستخدمة مؤخرًا',
412
allResults: 'كل النتائج',

packages/i18n/src/locales/de.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const de = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'Plattform',
6+
org: 'Organisation',
7+
other: 'Andere',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: 'Zuletzt verwendet',
412
allResults: 'Alle Ergebnisse',

packages/i18n/src/locales/en.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
* English (en) - Default language pack for Object UI
33
*/
44
const en = {
5+
// objectui#2600 B5 — capability picker scope group headers (labels come from
6+
// the sys_capability registry; only these group titles are UI strings).
7+
capability: {
8+
group: {
9+
platform: 'Platform',
10+
org: 'Organization',
11+
other: 'Other',
12+
},
13+
},
514
lookup: {
615
recentlyUsed: 'Recently used',
716
allResults: 'All results',

packages/i18n/src/locales/es.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const es = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'Plataforma',
6+
org: 'Organización',
7+
other: 'Otro',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: 'Usados recientemente',
412
allResults: 'Todos los resultados',

packages/i18n/src/locales/fr.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const fr = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'Plateforme',
6+
org: 'Organisation',
7+
other: 'Autre',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: 'Récemment utilisés',
412
allResults: 'Tous les résultats',

packages/i18n/src/locales/ja.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const ja = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'プラットフォーム',
6+
org: '組織',
7+
other: 'その他',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: '最近使用したもの',
412
allResults: 'すべての結果',

packages/i18n/src/locales/ko.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const ko = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: '플랫폼',
6+
org: '조직',
7+
other: '기타',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: '최근 사용',
412
allResults: '모든 결과',

packages/i18n/src/locales/pt.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
const pt = {
2+
// objectui#2600 B5 — capability picker scope group headers (labels come from the sys_capability registry).
3+
capability: {
4+
group: {
5+
platform: 'Plataforma',
6+
org: 'Organização',
7+
other: 'Outro',
8+
},
9+
},
210
lookup: {
311
recentlyUsed: 'Usados recentemente',
412
allResults: 'Todos os resultados',

0 commit comments

Comments
 (0)