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
12 changes: 12 additions & 0 deletions .changeset/19955-view-repeater-row-i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@objectstack/spec': patch
'@objectstack/platform-objects': patch
---

Studio's view property panel names the columns of its Columns, Sort and Tabs tables in the author's language, not only in English

Clause-②: no

`view.form.ts` now enumerates the row properties of the `columns`, `sort` and `tabs` repeaters, each with a `label` equal to its item schema's own `.meta({ title })`, so `os i18n extract` emits a `metadataForms.view.fields` key for each row property. The `en`, `zh-CN`, `ja-JP` and `es-ES` platform catalogs carry those keys. The translated catalogs reuse the word they already use for the same concept where they have one (`Label` → 显示名称 / 表示名 / Etiqueta, `Direction` → 排序方向 / 並び方向 / Dirección).

The row children declare no `type`, so each row input's widget is still derived from the schema. The view schema itself is unchanged.
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,48 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
label: "Columns",
helpText: "Columns to display (field names from selected object)"
},
"columns.field": {
label: "Field"
},
"columns.label": {
label: "Label"
},
"columns.width": {
label: "Width (px)"
},
"columns.align": {
label: "Alignment"
},
"columns.hidden": {
label: "Hidden"
},
"columns.sortable": {
label: "Sortable"
},
"columns.resizable": {
label: "Resizable"
},
"columns.wrap": {
label: "Wrap Text"
},
"columns.type": {
label: "Renderer Type"
},
"columns.pinned": {
label: "Pinned"
},
"columns.summary": {
label: "Summary"
},
"columns.prefix": {
label: "Prefix"
},
"columns.link": {
label: "Primary Link"
},
"columns.action": {
label: "Click Action"
},
filter: {
label: "Filter",
helpText: "Filter conditions — same visual builder as the list toolbar, with field-type-aware operators and value inputs"
Expand All @@ -798,6 +840,12 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
label: "Sort",
helpText: "Default sort order"
},
"sort.field": {
label: "Field"
},
"sort.order": {
label: "Direction"
},
searchableFields: {
label: "Searchable Fields",
helpText: "Field names available for quick search"
Expand Down Expand Up @@ -847,6 +895,33 @@ export const enMetadataForms: NonNullable<TranslationData['metadataForms']> = {
label: "Tabs",
helpText: "In-view filter tabs — each tab applies its own filter rules"
},
"tabs.name": {
label: "Name"
},
"tabs.label": {
label: "Label"
},
"tabs.icon": {
label: "Icon"
},
"tabs.view": {
label: "List View"
},
"tabs.filter": {
label: "Filter"
},
"tabs.order": {
label: "Display Order"
},
"tabs.pinned": {
label: "Pinned"
},
"tabs.isDefault": {
label: "Default Tab"
},
"tabs.visible": {
label: "Visible"
},
appearance: {
label: "Appearance",
helpText: "allowedVisualizations: which renderers users may switch between"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,48 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "Columnas",
helpText: "Columnas que mostrar (nombres de campo del objeto seleccionado)"
},
"columns.field": {
label: "Campo"
},
"columns.label": {
label: "Etiqueta"
},
"columns.width": {
label: "Ancho (px)"
},
"columns.align": {
label: "Alineación"
},
"columns.hidden": {
label: "Oculta"
},
"columns.sortable": {
label: "Ordenable"
},
"columns.resizable": {
label: "Redimensionable"
},
"columns.wrap": {
label: "Ajustar texto"
},
"columns.type": {
label: "Tipo de renderizador"
},
"columns.pinned": {
label: "Fijada"
},
"columns.summary": {
label: "Resumen"
},
"columns.prefix": {
label: "Prefijo"
},
"columns.link": {
label: "Enlace principal"
},
"columns.action": {
label: "Acción al hacer clic"
},
filter: {
label: "Filtro",
helpText: "Condiciones de filtro — el mismo constructor visual que la barra de herramientas de la lista, con operadores y entradas de valor según el tipo de campo"
Expand All @@ -798,6 +840,12 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "Orden",
helpText: "Orden predeterminado"
},
"sort.field": {
label: "Campo"
},
"sort.order": {
label: "Dirección"
},
searchableFields: {
label: "Campos buscables",
helpText: "Nombres de campo disponibles para búsqueda rápida"
Expand Down Expand Up @@ -847,6 +895,33 @@ export const esESMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "Pestañas",
helpText: "Pestañas de filtro en la vista: cada pestaña aplica sus propias reglas de filtro"
},
"tabs.name": {
label: "Nombre"
},
"tabs.label": {
label: "Etiqueta"
},
"tabs.icon": {
label: "Icono"
},
"tabs.view": {
label: "Vista de lista"
},
"tabs.filter": {
label: "Filtro"
},
"tabs.order": {
label: "Orden de visualización"
},
"tabs.pinned": {
label: "Fijada"
},
"tabs.isDefault": {
label: "Pestaña predeterminada"
},
"tabs.visible": {
label: "Visibilidad"
},
appearance: {
label: "Apariencia",
helpText: "allowedVisualizations: qué renderizadores pueden alternar los usuarios"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,48 @@ export const jaJPMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "列",
helpText: "表示する列(選択オブジェクトのフィールド名)"
},
"columns.field": {
label: "フィールド"
},
"columns.label": {
label: "表示名"
},
"columns.width": {
label: "幅(ピクセル)"
},
"columns.align": {
label: "配置"
},
"columns.hidden": {
label: "非表示"
},
"columns.sortable": {
label: "並び替え可能"
},
"columns.resizable": {
label: "サイズ変更可"
},
"columns.wrap": {
label: "テキストの折り返し"
},
"columns.type": {
label: "レンダラータイプ"
},
"columns.pinned": {
label: "固定"
},
"columns.summary": {
label: "集計"
},
"columns.prefix": {
label: "プレフィックス"
},
"columns.link": {
label: "主リンク"
},
"columns.action": {
label: "クリック時のアクション"
},
filter: {
label: "フィルター",
helpText: "フィルター条件 — リストツールバーと同じビジュアルビルダー。演算子と値入力はフィールドタイプに応じて変わります"
Expand All @@ -798,6 +840,12 @@ export const jaJPMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "並び替え",
helpText: "既定の並び順"
},
"sort.field": {
label: "フィールド"
},
"sort.order": {
label: "並び方向"
},
searchableFields: {
label: "検索対象フィールド",
helpText: "クイック検索で使用可能なフィールド名"
Expand Down Expand Up @@ -847,6 +895,33 @@ export const jaJPMetadataForms: NonNullable<TranslationData['metadataForms']> =
label: "タブ",
helpText: "ビュー内フィルタータブ——各タブが独自のフィルタールールを適用"
},
"tabs.name": {
label: "名前"
},
"tabs.label": {
label: "表示名"
},
"tabs.icon": {
label: "アイコン"
},
"tabs.view": {
label: "リストビュー"
},
"tabs.filter": {
label: "フィルター"
},
"tabs.order": {
label: "表示順"
},
"tabs.pinned": {
label: "固定"
},
"tabs.isDefault": {
label: "既定のタブ"
},
"tabs.visible": {
label: "表示"
},
appearance: {
label: "外観",
helpText: "allowedVisualizations:ユーザーが切り替え可能なレンダラー"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,10 @@ describe('#19403 round 10 — the verdicts, on the live bundles', () => {
// control moves by exactly the number of rows that landed, in every
// locale, which is the reading a per-locale count is for. 584 since
// #19814: the view form's new `pagination` section, its label authored
// in all three locales.
expect(translated.length, `${locale} positive control`).toBe(584);
// in all three locales. 609 since #19955: the 25 row labels of the view
// form's `columns` / `sort` / `tabs` repeaters, authored in all three
// locales.
expect(translated.length, `${locale} positive control`).toBe(609);
}
// ⭐ DARK — the blindness, executable. On a synthetic two-locale catalog the
// all-three predicate returns 0 while the per-locale one returns 1, so the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
//
// The population is DERIVED from the forms, not listed here, so a repeater
// enumerated tomorrow is red on the day it lands rather than a month later.
// `view.columns` / `view.sort` / `view.tabs` enumerate no children and are
// therefore outside it — their titles are #17507's.
// `view.columns` / `view.sort` / `view.tabs` joined it with #19955: #17507
// titled their item schemas, and `view.form.ts` now enumerates their children.

import { describe, it, expect } from 'vitest';

Expand Down Expand Up @@ -136,17 +136,20 @@ describe('#17508 — the enumerated-repeater survey itself (controls before verd
expect(CARRIERS).toContain('dashboard:header.actions');

const carrying = new Set(ROW_PROPERTIES.map((p) => p.type));
for (const type of ['action', 'app', 'dashboard', 'dataset', 'field', 'flow', 'page', 'report', 'skill']) {
for (const type of ['action', 'app', 'dashboard', 'dataset', 'field', 'flow', 'page', 'report', 'skill', 'view']) {
expect(carrying.has(type), `${type} enumerates a repeater's row properties`).toBe(true);
}
// Lit — the three `view` repeaters are inside the population (#19955).
// `view.columns` is the union case: a string-array arm beside the
// object-array arm whose properties these are.
for (const carrier of ['view:columns', 'view:sort', 'view:tabs']) {
expect(CARRIERS, `${carrier} enumerates its row properties`).toContain(carrier);
}
// Dark — forms that enumerate none contribute none. A walk that matched
// everything, or nothing, cannot pass both halves.
for (const type of ['agent', 'tool', 'hook', 'position']) {
expect(carrying.has(type), `${type} enumerates no repeater row properties`).toBe(false);
}
// Dark — `view.columns` / `view.sort` / `view.tabs` enumerate no children
// (their titles are #17507's), so `view` is outside this population.
expect(carrying.has('view'), 'view enumerates no repeater row properties yet').toBe(false);
});

it('every enumerated row child declares a `label` — an omitted one silently becomes the English source', () => {
Expand Down
Loading
Loading