diff --git a/src/AutomationPeers/TableViewAutomationPeer.cs b/src/AutomationPeers/TableViewAutomationPeer.cs
index 84e46213..7bd5b0c9 100644
--- a/src/AutomationPeers/TableViewAutomationPeer.cs
+++ b/src/AutomationPeers/TableViewAutomationPeer.cs
@@ -37,7 +37,7 @@ protected override AutomationControlType GetAutomationControlTypeCore()
///
protected override string GetLocalizedControlTypeCore()
{
- return "table view";
+ return TableViewLocalizedStrings.TableViewControlType;
}
///
diff --git a/src/AutomationPeers/TableViewCellAutomationPeer.cs b/src/AutomationPeers/TableViewCellAutomationPeer.cs
index b4e2b7f6..5beae9fc 100644
--- a/src/AutomationPeers/TableViewCellAutomationPeer.cs
+++ b/src/AutomationPeers/TableViewCellAutomationPeer.cs
@@ -42,7 +42,7 @@ protected override AutomationControlType GetAutomationControlTypeCore()
///
protected override string GetLocalizedControlTypeCore()
{
- return "cell";
+ return TableViewLocalizedStrings.CellControlType;
}
///
@@ -71,7 +71,7 @@ protected override string GetNameCore()
: string.Empty;
var rowIndex = _owner.Row?.Index ?? -1;
- var rowDisplay = rowIndex >= 0 ? $"Row {rowIndex + 1}" : string.Empty;
+ var rowDisplay = rowIndex >= 0 ? TableViewLocalizedStrings.FormatRowNumber(rowIndex + 1) : string.Empty;
var cellValue = _owner.Column is TableViewTemplateColumn
? string.Empty
diff --git a/src/AutomationPeers/TableViewColumnHeaderAutomationPeer.cs b/src/AutomationPeers/TableViewColumnHeaderAutomationPeer.cs
index 4b13c231..0ec8fe6e 100644
--- a/src/AutomationPeers/TableViewColumnHeaderAutomationPeer.cs
+++ b/src/AutomationPeers/TableViewColumnHeaderAutomationPeer.cs
@@ -38,7 +38,7 @@ protected override AutomationControlType GetAutomationControlTypeCore()
///
protected override string GetLocalizedControlTypeCore()
{
- return "column header";
+ return TableViewLocalizedStrings.ColumnHeaderControlType;
}
///
diff --git a/src/AutomationPeers/TableViewRowAutomationPeer.cs b/src/AutomationPeers/TableViewRowAutomationPeer.cs
index 6a0b95f5..9662aa62 100644
--- a/src/AutomationPeers/TableViewRowAutomationPeer.cs
+++ b/src/AutomationPeers/TableViewRowAutomationPeer.cs
@@ -44,7 +44,7 @@ protected override string GetNameCore()
}
var index = _owner.Index;
- return index >= 0 ? $"Row {index + 1}" : "Row";
+ return index >= 0 ? TableViewLocalizedStrings.FormatRowNumber(index + 1) : TableViewLocalizedStrings.Row;
}
///
diff --git a/src/AutomationPeers/TableViewRowHeaderAutomationPeer.cs b/src/AutomationPeers/TableViewRowHeaderAutomationPeer.cs
index aed2b94f..6e13188c 100644
--- a/src/AutomationPeers/TableViewRowHeaderAutomationPeer.cs
+++ b/src/AutomationPeers/TableViewRowHeaderAutomationPeer.cs
@@ -35,7 +35,7 @@ protected override AutomationControlType GetAutomationControlTypeCore()
///
protected override string GetLocalizedControlTypeCore()
{
- return "row header";
+ return TableViewLocalizedStrings.RowHeaderControlType;
}
///
@@ -77,6 +77,6 @@ protected override string GetNameCore()
// Fall back to the row index
var rowIndex = _owner.TableViewRow?.Index ?? -1;
- return rowIndex >= 0 ? $"Row {rowIndex + 1}" : base.GetNameCore();
+ return rowIndex >= 0 ? TableViewLocalizedStrings.FormatRowNumber(rowIndex + 1) : base.GetNameCore();
}
}
diff --git a/src/Strings/de-DE/WinUI.TableView.resw b/src/Strings/de-DE/WinUI.TableView.resw
index d868a18a..c3a87287 100644
--- a/src/Strings/de-DE/WinUI.TableView.resw
+++ b/src/Strings/de-DE/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Gruppen nach Wert sortieren
+
+ Tabellenansicht
+ UI Automation localized control type of the TableView.
+
+
+ Spaltenkopf
+ UI Automation localized control type of a column header.
+
+
+ Zeilenkopf
+ UI Automation localized control type of a row header.
+
+
+ Zelle
+ UI Automation localized control type of a cell.
+
+
+ Zeile {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Zeile
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/en-US/WinUI.TableView.resw b/src/Strings/en-US/WinUI.TableView.resw
index aee6f2e4..9434ffd5 100644
--- a/src/Strings/en-US/WinUI.TableView.resw
+++ b/src/Strings/en-US/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Sort Groups by Value
+
+ table view
+ UI Automation localized control type of the TableView.
+
+
+ column header
+ UI Automation localized control type of a column header.
+
+
+ row header
+ UI Automation localized control type of a row header.
+
+
+ cell
+ UI Automation localized control type of a cell.
+
+
+ Row {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Row
+ UI Automation name of a row whose index is not known.
+
\ No newline at end of file
diff --git a/src/Strings/es-ES/WinUI.TableView.resw b/src/Strings/es-ES/WinUI.TableView.resw
index 01fc0e8b..68708bf3 100644
--- a/src/Strings/es-ES/WinUI.TableView.resw
+++ b/src/Strings/es-ES/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Ordenar grupos por valor
+
+ vista de tabla
+ UI Automation localized control type of the TableView.
+
+
+ encabezado de columna
+ UI Automation localized control type of a column header.
+
+
+ encabezado de fila
+ UI Automation localized control type of a row header.
+
+
+ celda
+ UI Automation localized control type of a cell.
+
+
+ Fila {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Fila
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/fa-IR/WinUI.TableView.resw b/src/Strings/fa-IR/WinUI.TableView.resw
index 47a5b9d2..eeced4ce 100644
--- a/src/Strings/fa-IR/WinUI.TableView.resw
+++ b/src/Strings/fa-IR/WinUI.TableView.resw
@@ -204,4 +204,28 @@
مرتب سازی گروه ها بر اساس مقدار
+
+ نمای جدول
+ UI Automation localized control type of the TableView.
+
+
+ سرستون
+ UI Automation localized control type of a column header.
+
+
+ سرسطر
+ UI Automation localized control type of a row header.
+
+
+ خانه
+ UI Automation localized control type of a cell.
+
+
+ سطر {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ سطر
+ UI Automation name of a row whose index is not known.
+
\ No newline at end of file
diff --git a/src/Strings/ja-JP/WinUI.TableView.resw b/src/Strings/ja-JP/WinUI.TableView.resw
index d3d55d16..2d73c1e1 100644
--- a/src/Strings/ja-JP/WinUI.TableView.resw
+++ b/src/Strings/ja-JP/WinUI.TableView.resw
@@ -214,4 +214,28 @@
グループを値で並べ替え
+
+ テーブル ビュー
+ UI Automation localized control type of the TableView.
+
+
+ 列ヘッダー
+ UI Automation localized control type of a column header.
+
+
+ 行ヘッダー
+ UI Automation localized control type of a row header.
+
+
+ セル
+ UI Automation localized control type of a cell.
+
+
+ 行 {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ 行
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/pl-PL/WinUI.TableView.resw b/src/Strings/pl-PL/WinUI.TableView.resw
index 4b5e09cd..98c899fe 100644
--- a/src/Strings/pl-PL/WinUI.TableView.resw
+++ b/src/Strings/pl-PL/WinUI.TableView.resw
@@ -204,5 +204,29 @@
Sortuj grupy według wartości
+
+ widok tabeli
+ UI Automation localized control type of the TableView.
+
+
+ nagłówek kolumny
+ UI Automation localized control type of a column header.
+
+
+ nagłówek wiersza
+ UI Automation localized control type of a row header.
+
+
+ komórka
+ UI Automation localized control type of a cell.
+
+
+ Wiersz {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Wiersz
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/pt-BR/WinUI.TableView.resw b/src/Strings/pt-BR/WinUI.TableView.resw
index eb574cd7..f318d064 100644
--- a/src/Strings/pt-BR/WinUI.TableView.resw
+++ b/src/Strings/pt-BR/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Ordenar grupos por valor
+
+ exibição de tabela
+ UI Automation localized control type of the TableView.
+
+
+ cabeçalho de coluna
+ UI Automation localized control type of a column header.
+
+
+ cabeçalho de linha
+ UI Automation localized control type of a row header.
+
+
+ célula
+ UI Automation localized control type of a cell.
+
+
+ Linha {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Linha
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/ru-RU/WinUI.TableView.resw b/src/Strings/ru-RU/WinUI.TableView.resw
index 545c0450..55bc1056 100644
--- a/src/Strings/ru-RU/WinUI.TableView.resw
+++ b/src/Strings/ru-RU/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Сортировать группы по значению
+
+ представление таблицы
+ UI Automation localized control type of the TableView.
+
+
+ заголовок столбца
+ UI Automation localized control type of a column header.
+
+
+ заголовок строки
+ UI Automation localized control type of a row header.
+
+
+ ячейка
+ UI Automation localized control type of a cell.
+
+
+ Строка {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Строка
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/sk-SK/WinUI.TableView.resw b/src/Strings/sk-SK/WinUI.TableView.resw
index b4623e9b..2104ab4c 100644
--- a/src/Strings/sk-SK/WinUI.TableView.resw
+++ b/src/Strings/sk-SK/WinUI.TableView.resw
@@ -204,4 +204,28 @@
Zoradiť Skupiny Podľa Hodnoty
+
+ zobrazenie tabuľky
+ UI Automation localized control type of the TableView.
+
+
+ hlavička stĺpca
+ UI Automation localized control type of a column header.
+
+
+ hlavička riadka
+ UI Automation localized control type of a row header.
+
+
+ bunka
+ UI Automation localized control type of a cell.
+
+
+ Riadok {0}
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ Riadok
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/zh-CN/WinUI.TableView.resw b/src/Strings/zh-CN/WinUI.TableView.resw
index 80cc95a9..d21158c8 100644
--- a/src/Strings/zh-CN/WinUI.TableView.resw
+++ b/src/Strings/zh-CN/WinUI.TableView.resw
@@ -204,4 +204,28 @@
按值排序分组
+
+ 表格视图
+ UI Automation localized control type of the TableView.
+
+
+ 列标题
+ UI Automation localized control type of a column header.
+
+
+ 行标题
+ UI Automation localized control type of a row header.
+
+
+ 单元格
+ UI Automation localized control type of a cell.
+
+
+ 第 {0} 行
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ 行
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/Strings/zh-TW/WinUI.TableView.resw b/src/Strings/zh-TW/WinUI.TableView.resw
index 591cbf65..25269a14 100644
--- a/src/Strings/zh-TW/WinUI.TableView.resw
+++ b/src/Strings/zh-TW/WinUI.TableView.resw
@@ -204,4 +204,28 @@
依值排序群組
+
+ 表格檢視
+ UI Automation localized control type of the TableView.
+
+
+ 欄標題
+ UI Automation localized control type of a column header.
+
+
+ 列標題
+ UI Automation localized control type of a row header.
+
+
+ 儲存格
+ UI Automation localized control type of a cell.
+
+
+ 第 {0} 列
+ UI Automation name of a row; {0} is the one-based row number.
+
+
+ 列
+ UI Automation name of a row whose index is not known.
+
diff --git a/src/TableViewLocalizedStrings.cs b/src/TableViewLocalizedStrings.cs
index a4925678..133423e6 100644
--- a/src/TableViewLocalizedStrings.cs
+++ b/src/TableViewLocalizedStrings.cs
@@ -1,5 +1,6 @@
using Microsoft.Windows.ApplicationModel.Resources;
using System;
+using System.Globalization;
namespace WinUI.TableView;
@@ -47,6 +48,12 @@ static TableViewLocalizedStrings()
UngroupAll = GetValue(nameof(UngroupAll));
SortGroupsByCount = GetValue(nameof(SortGroupsByCount));
SortGroupsByValue = GetValue(nameof(SortGroupsByValue));
+ TableViewControlType = GetValue(nameof(TableViewControlType));
+ ColumnHeaderControlType = GetValue(nameof(ColumnHeaderControlType));
+ RowHeaderControlType = GetValue(nameof(RowHeaderControlType));
+ CellControlType = GetValue(nameof(CellControlType));
+ RowNumber = GetValue(nameof(RowNumber));
+ Row = GetValue(nameof(Row));
}
private static string GetValue(string name)
@@ -101,4 +108,18 @@ private static string GetValue(string name)
public static string UngroupAll { get; set; }
public static string SortGroupsByCount { get; set; }
public static string SortGroupsByValue { get; set; }
+ public static string TableViewControlType { get; set; }
+ public static string ColumnHeaderControlType { get; set; }
+ public static string RowHeaderControlType { get; set; }
+ public static string CellControlType { get; set; }
+ public static string RowNumber { get; set; }
+ public static string Row { get; set; }
+
+ ///
+ /// Formats the UI Automation name of a row from its one-based number, e.g. "Row 3".
+ ///
+ public static string FormatRowNumber(int oneBasedRowNumber)
+ {
+ return string.Format(CultureInfo.CurrentCulture, RowNumber, oneBasedRowNumber);
+ }
}
diff --git a/tests/TableViewAutomationPeerTests.cs b/tests/TableViewAutomationPeerTests.cs
index 150185b0..59fc938f 100644
--- a/tests/TableViewAutomationPeerTests.cs
+++ b/tests/TableViewAutomationPeerTests.cs
@@ -1,9 +1,12 @@
+using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Automation.Peers;
using Microsoft.UI.Xaml.Automation.Provider;
using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
+using System.Threading.Tasks;
using WinUI.TableView.AutomationPeers;
namespace WinUI.TableView.Tests;
@@ -423,4 +426,168 @@ public void TableViewRowHeader_OnCreateAutomationPeer_ReturnsTableViewRowHeaderA
Assert.IsInstanceOfType(peer, typeof(TableViewRowHeaderAutomationPeer));
}
+
+ // ─── Localized automation text ──────────────────────────────────────────
+ // Each test swaps the resource value for a sentinel, so it fails on a peer that returns an
+ // English literal even when the test runs under en-US, where the literal and the resource agree.
+
+ [UITestMethod]
+ public void TableViewAutomationPeer_LocalizedControlType_ComesFromResources()
+ {
+ AssertUsesResource(v => TableViewLocalizedStrings.TableViewControlType = v, () => TableViewLocalizedStrings.TableViewControlType,
+ () => new TableViewAutomationPeer(new TableView()).GetLocalizedControlType());
+ }
+
+ [UITestMethod]
+ public void TableViewColumnHeaderAutomationPeer_LocalizedControlType_ComesFromResources()
+ {
+ AssertUsesResource(v => TableViewLocalizedStrings.ColumnHeaderControlType = v, () => TableViewLocalizedStrings.ColumnHeaderControlType,
+ () => new TableViewColumnHeaderAutomationPeer(new TableViewColumnHeader()).GetLocalizedControlType());
+ }
+
+ [UITestMethod]
+ public void TableViewRowHeaderAutomationPeer_LocalizedControlType_ComesFromResources()
+ {
+ AssertUsesResource(v => TableViewLocalizedStrings.RowHeaderControlType = v, () => TableViewLocalizedStrings.RowHeaderControlType,
+ () => new TableViewRowHeaderAutomationPeer(new TableViewRowHeader()).GetLocalizedControlType());
+ }
+
+ [UITestMethod]
+ public void TableViewCellAutomationPeer_LocalizedControlType_ComesFromResources()
+ {
+ AssertUsesResource(v => TableViewLocalizedStrings.CellControlType = v, () => TableViewLocalizedStrings.CellControlType,
+ () => new TableViewCellAutomationPeer(new TableViewCell()).GetLocalizedControlType());
+ }
+
+ [UITestMethod]
+ public void TableViewRowAutomationPeer_NameWithoutIndex_ComesFromResources()
+ {
+ // Row.Index returns -1 when not in a list, so the name is the bare "Row" resource.
+ AssertUsesResource(v => TableViewLocalizedStrings.Row = v, () => TableViewLocalizedStrings.Row,
+ () => new TableViewRowAutomationPeer(new TableViewRow()).GetName());
+ }
+
+ [UITestMethod]
+ public void FormatRowNumber_UsesTheRowNumberResource()
+ {
+ var original = TableViewLocalizedStrings.RowNumber;
+ try
+ {
+ TableViewLocalizedStrings.RowNumber = "R#{0}";
+ Assert.AreEqual("R#3", TableViewLocalizedStrings.FormatRowNumber(3));
+ }
+ finally
+ {
+ TableViewLocalizedStrings.RowNumber = original;
+ }
+
+ StringAssert.Contains(TableViewLocalizedStrings.FormatRowNumber(3), "3");
+ }
+
+ [UITestMethod]
+ public void AutomationResources_AreNotEmpty()
+ {
+ Assert.IsFalse(string.IsNullOrEmpty(TableViewLocalizedStrings.TableViewControlType));
+ Assert.IsFalse(string.IsNullOrEmpty(TableViewLocalizedStrings.ColumnHeaderControlType));
+ Assert.IsFalse(string.IsNullOrEmpty(TableViewLocalizedStrings.RowHeaderControlType));
+ Assert.IsFalse(string.IsNullOrEmpty(TableViewLocalizedStrings.CellControlType));
+ Assert.IsFalse(string.IsNullOrEmpty(TableViewLocalizedStrings.Row));
+ StringAssert.Contains(TableViewLocalizedStrings.RowNumber, "{0}");
+ }
+
+ // The indexed names ("Row {n}") are only composed for a row that has an index, i.e. one realized in a
+ // loaded TableView. Each test swaps RowNumber for a sentinel and reads the peer, so it fails on a peer
+ // that composes the name from an English literal instead of FormatRowNumber.
+
+ [UITestMethod]
+ public async Task TableViewRowAutomationPeer_IndexedName_ComesFromResources()
+ {
+ var row = await RealizeSecondRowAsync();
+
+ AssertUsesRowNumberResource(() => new TableViewRowAutomationPeer(row).GetName(), expected: "R#2");
+ }
+
+ [UITestMethod]
+ public async Task TableViewRowHeaderAutomationPeer_IndexedName_ComesFromResources()
+ {
+ var row = await RealizeSecondRowAsync();
+ var rowHeader = new TableViewRowHeader { TableViewRow = row };
+
+ AssertUsesRowNumberResource(() => new TableViewRowHeaderAutomationPeer(rowHeader).GetName(), expected: "R#2");
+ }
+
+ [UITestMethod]
+ public async Task TableViewCellAutomationPeer_IndexedName_ComesFromResources()
+ {
+ var row = await RealizeSecondRowAsync();
+ Assert.IsTrue(row.Cells.Count > 0, "the realized row has no cells");
+ var cell = row.Cells[0];
+
+ // The cell's name also carries the column header and the value; only its row part is under test.
+ AssertUsesRowNumberResource(() => new TableViewCellAutomationPeer(cell).GetName(), expected: "R#2", whole: false);
+ }
+
+ private static void AssertUsesRowNumberResource(Func read, string expected, bool whole = true)
+ {
+ var original = TableViewLocalizedStrings.RowNumber;
+ try
+ {
+ TableViewLocalizedStrings.RowNumber = "R#{0}";
+ var name = read();
+ if (whole)
+ {
+ Assert.AreEqual(expected, name);
+ }
+ else
+ {
+ StringAssert.Contains(name, expected);
+ }
+ }
+ finally
+ {
+ TableViewLocalizedStrings.RowNumber = original;
+ }
+ }
+
+ private static async Task RealizeSecondRowAsync()
+ {
+ var tableView = new TableView { AutoGenerateColumns = false };
+ tableView.Columns.Add(new TableViewTextColumn
+ {
+ Header = "Name",
+ Binding = new Binding { Path = new PropertyPath(nameof(IndexedNameItem.Name)) }
+ });
+ tableView.ItemsSource = new[]
+ {
+ new IndexedNameItem { Name = "A" },
+ new IndexedNameItem { Name = "B" },
+ };
+
+ await UnitTestApp.Current.MainWindow.LoadTestContentAsync(tableView);
+
+ var row = tableView.ContainerFromIndex(1) as TableViewRow;
+ Assert.IsNotNull(row, "the second row was not realized");
+ Assert.AreEqual(1, row.Index, "the realized row reports no index, so no indexed name would be composed");
+ return row;
+ }
+
+ private sealed class IndexedNameItem
+ {
+ public string Name { get; set; } = string.Empty;
+ }
+
+ private static void AssertUsesResource(Action set, Func get, Func read)
+ {
+ const string sentinel = "localized-sentinel";
+ var original = get();
+ try
+ {
+ set(sentinel);
+ Assert.AreEqual(sentinel, read());
+ }
+ finally
+ {
+ set(original);
+ }
+ }
}