diff --git a/src/components/SidebarDrawer.tsx b/src/components/SidebarDrawer.tsx
index 1f8e5f1f..84db85dc 100644
--- a/src/components/SidebarDrawer.tsx
+++ b/src/components/SidebarDrawer.tsx
@@ -49,6 +49,7 @@ import {
import { serverSupportsEmailPush } from '../lib/push-notifications';
import { mailboxIconKind, type MailboxIconKind } from '../lib/mailbox-icon';
import { useSheetBottomInset } from '../lib/sheet-bottom-inset';
+import { unreadRowLabel } from '../lib/unread-row-label';
const CHEVRON_SLOT = 20;
const INDENT_STEP = 12;
@@ -171,9 +172,7 @@ function SidebarRow({
const leftPad = ROW_PX_BASE + depth * INDENT_STEP;
// Which folder is open, and the unread count with the folder's name
// ("Inbox, 3 unread"), for screen readers (webmail 7c282f1f4).
- const accessibleName = unread > 0 && !isAccountHeader
- ? t('shell.name_unread', '{name}, {count} unread', { name: label, count: unread })
- : label;
+ const accessibleName = isAccountHeader ? label : unreadRowLabel(label, unread, t);
return (
m.isShared && m.role === 'inbox');
+ const unifiedInboxLabel = unifiedCrossAccount && accounts.length > 1
+ ? t('sidebar.all_accounts', 'All accounts')
+ : t('sidebar.unified_inbox', 'All inboxes');
const showUnified = showUnifiedSection({
accountCount: accounts.length, unifiedCrossAccount, includeGroupInUnified, hasSharedInbox,
});
@@ -1047,13 +1049,13 @@ export default function SidebarDrawer({ visible, onClose, docked = false }: Side
[styles.quickRow, pressed && styles.rowPressed]}
onPress={() => { onClose(); navigation.navigate('UnifiedInbox', { role: 'inbox' }); }}
+ // A name of its own, like a folder row: else TalkBack read its
+ // texts one by one ("All inboxes, /, 9").
+ accessibilityRole="button"
+ accessibilityLabel={unreadRowLabel(unifiedInboxLabel, unifiedCounts.inbox.unread, t)}
>
-
- {unifiedCrossAccount && accounts.length > 1
- ? t('sidebar.all_accounts', 'All accounts')
- : t('sidebar.unified_inbox', 'All inboxes')}
-
+ {unifiedInboxLabel}
diff --git a/src/lib/__tests__/unread-row-label.test.ts b/src/lib/__tests__/unread-row-label.test.ts
new file mode 100644
index 00000000..7d8ca7be
--- /dev/null
+++ b/src/lib/__tests__/unread-row-label.test.ts
@@ -0,0 +1,30 @@
+import { describe, expect, it, vi } from 'vitest';
+import fs from 'node:fs';
+import path from 'node:path';
+
+vi.mock('expo-localization', () => ({ getLocales: () => [] }));
+
+import { translate } from '../../i18n';
+import { unreadRowLabel } from '../unread-row-label';
+
+const tEn = (key: string, fallback?: string, params?: Record) => translate('en', key, fallback, params);
+
+describe('unreadRowLabel', () => {
+ it('says the unread count after the name', () => {
+ expect(unreadRowLabel('All inboxes', 9, tEn)).toBe('All inboxes, 9 unread');
+ expect(unreadRowLabel('All inboxes', 0, tEn)).toBe('All inboxes');
+ });
+});
+
+describe('the sidebar Unified Inbox row', () => {
+ // TalkBack read it as "All inboxes, /, 9": no label, so the row's texts
+ // (the name and RowCounts' unread / total) one by one.
+ it('is a button named by its label and unread count', () => {
+ const source = fs.readFileSync(path.resolve(__dirname, '../../components/SidebarDrawer.tsx'), 'utf8');
+ const start = source.indexOf('{showUnified && (');
+ const row = source.slice(start, source.indexOf('', start));
+ expect(row).toContain("navigation.navigate('UnifiedInbox', { role: 'inbox' })");
+ expect(row).toMatch(/accessibilityRole="button"/);
+ expect(row).toMatch(/accessibilityLabel=\{unreadRowLabel\(unifiedInboxLabel, unifiedCounts\.inbox\.unread, t\)\}/);
+ });
+});
diff --git a/src/lib/unread-row-label.ts b/src/lib/unread-row-label.ts
new file mode 100644
index 00000000..11496e84
--- /dev/null
+++ b/src/lib/unread-row-label.ts
@@ -0,0 +1,11 @@
+type Translate = (key: string, fallback?: string, params?: Record) => string;
+
+/**
+ * What a screen reader calls a folder or view row: its name, with the unread
+ * count when there is unread mail ("Inbox, 3 unread"; webmail 7c282f1f4).
+ * Without a label of its own a row reads its texts one by one, so the
+ * Unified Inbox row came out as "All inboxes, /, 9".
+ */
+export function unreadRowLabel(name: string, unread: number, t: Translate): string {
+ return unread > 0 ? t('shell.name_unread', '{name}, {count} unread', { name, count: unread }) : name;
+}