improved the accessibility labels for the view

also added copies for the section headers, and fixes an issue where the move action voice over was not reading the option
This commit is contained in:
Mauro Romito
2025-06-13 18:38:06 +02:00
committed by Mauro
parent 93cd1401cf
commit 670bb3a2f3
12 changed files with 127 additions and 19 deletions
@@ -12,6 +12,7 @@
"a11y_pin_field" = "PIN field"; "a11y_pin_field" = "PIN field";
"a11y_play" = "Play"; "a11y_play" = "Play";
"a11y_poll_end" = "Ended poll"; "a11y_poll_end" = "Ended poll";
"a11y_polls_winning_answer" = "This is the winning answer";
"a11y_react_with" = "React with %1$@"; "a11y_react_with" = "React with %1$@";
"a11y_react_with_other_emojis" = "React with other emojis"; "a11y_react_with_other_emojis" = "React with other emojis";
"a11y_read_receipts_multiple" = "Read by %1$@ and %2$@"; "a11y_read_receipts_multiple" = "Read by %1$@ and %2$@";
@@ -135,10 +136,12 @@
"banner_migrate_to_native_sliding_sync_title" = "Upgrade available"; "banner_migrate_to_native_sliding_sync_title" = "Upgrade available";
"banner_set_up_recovery_content" = "Recover your cryptographic identity and message history with a recovery key if you have lost all your existing devices."; "banner_set_up_recovery_content" = "Recover your cryptographic identity and message history with a recovery key if you have lost all your existing devices.";
"banner_set_up_recovery_title" = "Set up recovery to protect your account"; "banner_set_up_recovery_title" = "Set up recovery to protect your account";
"call_invalid_audio_device_bluetooth_devices_disabled" = "Element Call does not support using Bluetooth audio devices in this Android version. Please select a different audio device.";
"common_about" = "About"; "common_about" = "About";
"common_acceptable_use_policy" = "Acceptable use policy"; "common_acceptable_use_policy" = "Acceptable use policy";
"common_adding_caption" = "Adding caption"; "common_adding_caption" = "Adding caption";
"common_advanced_settings" = "Advanced settings"; "common_advanced_settings" = "Advanced settings";
"common_an_image" = "an image";
"common_analytics" = "Analytics"; "common_analytics" = "Analytics";
"common_appearance" = "Appearance"; "common_appearance" = "Appearance";
"common_audio" = "Audio"; "common_audio" = "Audio";
@@ -242,6 +245,7 @@
"common_sending" = "Sending…"; "common_sending" = "Sending…";
"common_sending_failed" = "Sending failed"; "common_sending_failed" = "Sending failed";
"common_sent" = "Sent"; "common_sent" = "Sent";
"common_sentence_delimiter" = ". ";
"common_server_not_supported" = "Server not supported"; "common_server_not_supported" = "Server not supported";
"common_server_url" = "Server URL"; "common_server_url" = "Server URL";
"common_settings" = "Settings"; "common_settings" = "Settings";
@@ -432,6 +436,10 @@
"screen_bottom_sheet_manage_room_member_unban_member_confirmation_description" = "They would be able to join the room again if invited"; "screen_bottom_sheet_manage_room_member_unban_member_confirmation_description" = "They would be able to join the room again if invited";
"screen_bottom_sheet_manage_room_member_unban_member_confirmation_title" = "Are you sure you want to unban this member?"; "screen_bottom_sheet_manage_room_member_unban_member_confirmation_title" = "Are you sure you want to unban this member?";
"screen_bottom_sheet_manage_room_member_unbanning_user" = "Unbanning %1$@"; "screen_bottom_sheet_manage_room_member_unbanning_user" = "Unbanning %1$@";
"screen_create_poll_option_accessibility_label" = "%1$@: %2$@";
"screen_create_poll_options_section_title" = "Options";
"screen_create_poll_remove_accessibility_label" = "Remove %1$@";
"screen_create_poll_settings_section_title" = "Settings";
"screen_create_room_room_access_section_anyone_option_description" = "Anyone can join this room"; "screen_create_room_room_access_section_anyone_option_description" = "Anyone can join this room";
"screen_create_room_room_access_section_anyone_option_title" = "Anyone"; "screen_create_room_room_access_section_anyone_option_title" = "Anyone";
"screen_create_room_room_access_section_header" = "Room Access"; "screen_create_room_room_access_section_header" = "Room Access";
@@ -658,6 +666,7 @@
"screen_create_poll_anonymous_headline" = "Hide votes"; "screen_create_poll_anonymous_headline" = "Hide votes";
"screen_create_poll_answer_hint" = "Option %1$d"; "screen_create_poll_answer_hint" = "Option %1$d";
"screen_create_poll_cancel_confirmation_title_ios" = "Cancel Poll"; "screen_create_poll_cancel_confirmation_title_ios" = "Cancel Poll";
"screen_create_poll_delete_option_a11y" = "Delete option %1$@";
"screen_create_poll_question_desc" = "Question or topic"; "screen_create_poll_question_desc" = "Question or topic";
"screen_create_poll_question_hint" = "What is the poll about?"; "screen_create_poll_question_hint" = "What is the poll about?";
"screen_create_poll_title" = "Create Poll"; "screen_create_poll_title" = "Create Poll";
@@ -967,13 +976,14 @@
"screen_room_roles_and_permissions_roles_header" = "Roles"; "screen_room_roles_and_permissions_roles_header" = "Roles";
"screen_room_roles_and_permissions_room_details" = "Room details"; "screen_room_roles_and_permissions_room_details" = "Room details";
"screen_room_roles_and_permissions_title" = "Roles and permissions"; "screen_room_roles_and_permissions_title" = "Roles and permissions";
"screen_room_timeline_add_reaction" = "Add emoji"; "screen_room_timeline_add_reaction" = "Add a reaction";
"screen_room_timeline_beginning_of_room" = "This is the beginning of %1$@."; "screen_room_timeline_beginning_of_room" = "This is the beginning of %1$@.";
"screen_room_timeline_beginning_of_room_no_name" = "This is the beginning of this conversation."; "screen_room_timeline_beginning_of_room_no_name" = "This is the beginning of this conversation.";
"screen_room_timeline_legacy_call" = "Unsupported call. Ask if the caller can use the new Element X app."; "screen_room_timeline_legacy_call" = "Unsupported call. Ask if the caller can use the new Element X app.";
"screen_room_timeline_less_reactions" = "Show less"; "screen_room_timeline_less_reactions" = "Show less";
"screen_room_timeline_message_copied" = "Message copied"; "screen_room_timeline_message_copied" = "Message copied";
"screen_room_timeline_no_permission_to_post" = "You do not have permission to post to this room"; "screen_room_timeline_no_permission_to_post" = "You do not have permission to post to this room";
"screen_room_timeline_reaction_you_a11y" = "You reacted with %1$@";
"screen_room_timeline_reactions_show_more" = "Show more"; "screen_room_timeline_reactions_show_more" = "Show more";
"screen_room_timeline_read_marker_title" = "New"; "screen_room_timeline_read_marker_title" = "New";
"screen_room_title" = "Chat"; "screen_room_title" = "Chat";
@@ -18,6 +18,22 @@
<string>%1$d digits entered</string> <string>%1$d digits entered</string>
</dict> </dict>
</dict> </dict>
<key>a11y_polls_percent_of_total</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@COUNT@</string>
<key>COUNT</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%1$d percent of total votes</string>
<key>other</key>
<string>%1$d percents of total votes</string>
</dict>
</dict>
<key>a11y_read_receipts_multiple_with_others</key> <key>a11y_read_receipts_multiple_with_others</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
@@ -258,6 +274,38 @@
<string>%1$@ +%2$d others want to join this room</string> <string>%1$@ +%2$d others want to join this room</string>
</dict> </dict>
</dict> </dict>
<key>screen_room_timeline_reaction_a11y</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@COUNT@</string>
<key>COUNT</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>%1$d member reacted with %2$@</string>
<key>other</key>
<string>%1$d members reacted with %2$@</string>
</dict>
</dict>
<key>screen_room_timeline_reaction_including_you_a11y</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@COUNT@</string>
<key>COUNT</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>You and %1$d member reacted with %2$@</string>
<key>other</key>
<string>You and %1$d members reacted with %2$@</string>
</dict>
</dict>
<key>screen_room_timeline_state_changes</key> <key>screen_room_timeline_state_changes</key>
<dict> <dict>
<key>NSStringLocalizedFormatKey</key> <key>NSStringLocalizedFormatKey</key>
+41 -1
View File
@@ -46,6 +46,12 @@ internal enum L10n {
internal static var a11yPoll: String { return L10n.tr("Localizable", "a11y_poll") } internal static var a11yPoll: String { return L10n.tr("Localizable", "a11y_poll") }
/// Ended poll /// Ended poll
internal static var a11yPollEnd: String { return L10n.tr("Localizable", "a11y_poll_end") } internal static var a11yPollEnd: String { return L10n.tr("Localizable", "a11y_poll_end") }
/// Plural format key: "%#@COUNT@"
internal static func a11yPollsPercentOfTotal(_ p1: Int) -> String {
return L10n.tr("Localizable", "a11y_polls_percent_of_total", p1)
}
/// This is the winning answer
internal static var a11yPollsWinningAnswer: String { return L10n.tr("Localizable", "a11y_polls_winning_answer") }
/// React with %1$@ /// React with %1$@
internal static func a11yReactWith(_ p1: Any) -> String { internal static func a11yReactWith(_ p1: Any) -> String {
return L10n.tr("Localizable", "a11y_react_with", String(describing: p1)) return L10n.tr("Localizable", "a11y_react_with", String(describing: p1))
@@ -314,6 +320,8 @@ internal enum L10n {
internal static var bannerSetUpRecoverySubmit: String { return L10n.tr("Localizable", "banner_set_up_recovery_submit") } internal static var bannerSetUpRecoverySubmit: String { return L10n.tr("Localizable", "banner_set_up_recovery_submit") }
/// Set up recovery to protect your account /// Set up recovery to protect your account
internal static var bannerSetUpRecoveryTitle: String { return L10n.tr("Localizable", "banner_set_up_recovery_title") } internal static var bannerSetUpRecoveryTitle: String { return L10n.tr("Localizable", "banner_set_up_recovery_title") }
/// Element Call does not support using Bluetooth audio devices in this Android version. Please select a different audio device.
internal static var callInvalidAudioDeviceBluetoothDevicesDisabled: String { return L10n.tr("Localizable", "call_invalid_audio_device_bluetooth_devices_disabled") }
/// About /// About
internal static var commonAbout: String { return L10n.tr("Localizable", "common_about") } internal static var commonAbout: String { return L10n.tr("Localizable", "common_about") }
/// Acceptable use policy /// Acceptable use policy
@@ -322,6 +330,8 @@ internal enum L10n {
internal static var commonAddingCaption: String { return L10n.tr("Localizable", "common_adding_caption") } internal static var commonAddingCaption: String { return L10n.tr("Localizable", "common_adding_caption") }
/// Advanced settings /// Advanced settings
internal static var commonAdvancedSettings: String { return L10n.tr("Localizable", "common_advanced_settings") } internal static var commonAdvancedSettings: String { return L10n.tr("Localizable", "common_advanced_settings") }
/// an image
internal static var commonAnImage: String { return L10n.tr("Localizable", "common_an_image") }
/// Analytics /// Analytics
internal static var commonAnalytics: String { return L10n.tr("Localizable", "common_analytics") } internal static var commonAnalytics: String { return L10n.tr("Localizable", "common_analytics") }
/// Appearance /// Appearance
@@ -556,6 +566,8 @@ internal enum L10n {
internal static var commonSendingFailed: String { return L10n.tr("Localizable", "common_sending_failed") } internal static var commonSendingFailed: String { return L10n.tr("Localizable", "common_sending_failed") }
/// Sent /// Sent
internal static var commonSent: String { return L10n.tr("Localizable", "common_sent") } internal static var commonSent: String { return L10n.tr("Localizable", "common_sent") }
/// .
internal static var commonSentenceDelimiter: String { return L10n.tr("Localizable", "common_sentence_delimiter") }
/// Server not supported /// Server not supported
internal static var commonServerNotSupported: String { return L10n.tr("Localizable", "common_server_not_supported") } internal static var commonServerNotSupported: String { return L10n.tr("Localizable", "common_server_not_supported") }
/// Server URL /// Server URL
@@ -1315,10 +1327,26 @@ internal enum L10n {
internal static var screenCreatePollCancelConfirmationContentIos: String { return L10n.tr("Localizable", "screen_create_poll_cancel_confirmation_content_ios") } internal static var screenCreatePollCancelConfirmationContentIos: String { return L10n.tr("Localizable", "screen_create_poll_cancel_confirmation_content_ios") }
/// Cancel Poll /// Cancel Poll
internal static var screenCreatePollCancelConfirmationTitleIos: String { return L10n.tr("Localizable", "screen_create_poll_cancel_confirmation_title_ios") } internal static var screenCreatePollCancelConfirmationTitleIos: String { return L10n.tr("Localizable", "screen_create_poll_cancel_confirmation_title_ios") }
/// Delete option %1$@
internal static func screenCreatePollDeleteOptionA11y(_ p1: Any) -> String {
return L10n.tr("Localizable", "screen_create_poll_delete_option_a11y", String(describing: p1))
}
/// %1$@: %2$@
internal static func screenCreatePollOptionAccessibilityLabel(_ p1: Any, _ p2: Any) -> String {
return L10n.tr("Localizable", "screen_create_poll_option_accessibility_label", String(describing: p1), String(describing: p2))
}
/// Options
internal static var screenCreatePollOptionsSectionTitle: String { return L10n.tr("Localizable", "screen_create_poll_options_section_title") }
/// Question or topic /// Question or topic
internal static var screenCreatePollQuestionDesc: String { return L10n.tr("Localizable", "screen_create_poll_question_desc") } internal static var screenCreatePollQuestionDesc: String { return L10n.tr("Localizable", "screen_create_poll_question_desc") }
/// What is the poll about? /// What is the poll about?
internal static var screenCreatePollQuestionHint: String { return L10n.tr("Localizable", "screen_create_poll_question_hint") } internal static var screenCreatePollQuestionHint: String { return L10n.tr("Localizable", "screen_create_poll_question_hint") }
/// Remove %1$@
internal static func screenCreatePollRemoveAccessibilityLabel(_ p1: Any) -> String {
return L10n.tr("Localizable", "screen_create_poll_remove_accessibility_label", String(describing: p1))
}
/// Settings
internal static var screenCreatePollSettingsSectionTitle: String { return L10n.tr("Localizable", "screen_create_poll_settings_section_title") }
/// Create Poll /// Create Poll
internal static var screenCreatePollTitle: String { return L10n.tr("Localizable", "screen_create_poll_title") } internal static var screenCreatePollTitle: String { return L10n.tr("Localizable", "screen_create_poll_title") }
/// New room /// New room
@@ -2302,7 +2330,7 @@ internal enum L10n {
} }
/// View /// View
internal static var screenRoomSingleKnockRequestViewButtonTitle: String { return L10n.tr("Localizable", "screen_room_single_knock_request_view_button_title") } internal static var screenRoomSingleKnockRequestViewButtonTitle: String { return L10n.tr("Localizable", "screen_room_single_knock_request_view_button_title") }
/// Add emoji /// Add a reaction
internal static var screenRoomTimelineAddReaction: String { return L10n.tr("Localizable", "screen_room_timeline_add_reaction") } internal static var screenRoomTimelineAddReaction: String { return L10n.tr("Localizable", "screen_room_timeline_add_reaction") }
/// This is the beginning of %1$@. /// This is the beginning of %1$@.
internal static func screenRoomTimelineBeginningOfRoom(_ p1: Any) -> String { internal static func screenRoomTimelineBeginningOfRoom(_ p1: Any) -> String {
@@ -2318,6 +2346,18 @@ internal enum L10n {
internal static var screenRoomTimelineMessageCopied: String { return L10n.tr("Localizable", "screen_room_timeline_message_copied") } internal static var screenRoomTimelineMessageCopied: String { return L10n.tr("Localizable", "screen_room_timeline_message_copied") }
/// You do not have permission to post to this room /// You do not have permission to post to this room
internal static var screenRoomTimelineNoPermissionToPost: String { return L10n.tr("Localizable", "screen_room_timeline_no_permission_to_post") } internal static var screenRoomTimelineNoPermissionToPost: String { return L10n.tr("Localizable", "screen_room_timeline_no_permission_to_post") }
/// Plural format key: "%#@COUNT@"
internal static func screenRoomTimelineReactionA11y(_ p1: Int) -> String {
return L10n.tr("Localizable", "screen_room_timeline_reaction_a11y", p1)
}
/// Plural format key: "%#@COUNT@"
internal static func screenRoomTimelineReactionIncludingYouA11y(_ p1: Int) -> String {
return L10n.tr("Localizable", "screen_room_timeline_reaction_including_you_a11y", p1)
}
/// You reacted with %1$@
internal static func screenRoomTimelineReactionYouA11y(_ p1: Any) -> String {
return L10n.tr("Localizable", "screen_room_timeline_reaction_you_a11y", String(describing: p1))
}
/// Show less /// Show less
internal static var screenRoomTimelineReactionsShowLess: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_less") } internal static var screenRoomTimelineReactionsShowLess: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_less") }
/// Show more /// Show more
@@ -91,6 +91,9 @@ struct PollFormScreen: View {
}) })
.accessibilityIdentifier(A11yIdentifiers.pollFormScreen.addOption) .accessibilityIdentifier(A11yIdentifiers.pollFormScreen.addOption)
} }
} header: {
Text(L10n.screenCreatePollOptionsSectionTitle)
.compoundListSectionHeader()
} }
// Disables animations when the text view resizes for multiline // Disables animations when the text view resizes for multiline
.animation(.noAnimation, value: UUID()) .animation(.noAnimation, value: UUID())
@@ -106,6 +109,9 @@ struct PollFormScreen: View {
ListRow(label: .plain(title: L10n.screenCreatePollAnonymousDesc), ListRow(label: .plain(title: L10n.screenCreatePollAnonymousDesc),
kind: .toggle($context.isUndisclosed)) kind: .toggle($context.isUndisclosed))
.accessibilityIdentifier(A11yIdentifiers.pollFormScreen.pollKind) .accessibilityIdentifier(A11yIdentifiers.pollFormScreen.pollKind)
} header: {
Text(L10n.screenCreatePollSettingsSectionTitle)
.compoundListSectionHeader()
} }
} }
@@ -168,13 +174,17 @@ private struct PollFormOptionRow: View {
} }
.disabled(!canDeleteItem) .disabled(!canDeleteItem)
.buttonStyle(.compound(.textLink)) .buttonStyle(.compound(.textLink))
.accessibilityLabel(L10n.actionRemove) .accessibilityLabel(L10n.screenCreatePollRemoveAccessibilityLabel(L10n.screenCreatePollOptionAccessibilityLabel(placeholder, text)))
} }
TextField(text: $text, axis: .vertical) { TextField(text: $text, axis: .vertical) {
Text(placeholder) Text(placeholder)
.compoundTextFieldPlaceholder() .compoundTextFieldPlaceholder()
} }
// For some reason the placeholder is always read by voice over even if I disable or override the label, so if the text is empty we use an empy accessibility label
.accessibilityLabel(text.isEmpty ? "" : L10n.screenCreatePollOptionAccessibilityLabel(placeholder, text))
// Allows the move action voice over to give priority to this field over the remove button
.accessibilitySortPriority(1)
.tint(.compound.iconAccentTertiary) .tint(.compound.iconAccentTertiary)
.alignmentGuide(.listRowSeparatorLeading) { _ in 0 } .alignmentGuide(.listRowSeparatorLeading) { _ in 0 }
} }
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ccafda1521bc9a2620fb3698b0f743fa90c91b7b83b8fb6559f5862e1acbf46e oid sha256:a8b3c7bef372d17793e3418e76af0b4532079cbf2ddb405abfcb9861a4a943f6
size 121014 size 126606
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:1e6b25c989524f3a1e89f2c85e8e0038c26cff7861b5f7858b7d76adbcf92a07 oid sha256:cb9d706b66b2c63784e434b86f93e60e005e27965a4caff8ff1bbae1dcbe0e14
size 126701 size 132825
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5f0daee86253e12e036200de2891879f544e36910ebea901618d56bbe7149cc5 oid sha256:75edde867bdf7993b76f0d42527c30bbee6e860752ccc3cc6eb697658105c7db
size 73283 size 76334
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:a3f72d6f9c708cc71a40ed5018f6648e9215966148881f9b38412b3d63f4dfb5 oid sha256:b336a45136ad087539f5cd48160fc73f5ba2bdd8ec32893d2ba0eabac22052f9
size 83465 size 88052
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4491fd198f3b9bd21cbb07f466ada9cba753975eef4db7c4e0f229484f0eb038 oid sha256:5cad299415956ed436e1640bc4483c9c68df7e4896cc6504c7da900b6e36692f
size 122633 size 128852
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:39bc16d2356c9c28d54a7f221ff31caefb6d7d1c51f8b1243421a7d0f5754f6c oid sha256:a861bddb7bb7ff66e915c81d264f12c708a967426f72867afe6902d7c4456ead
size 133043 size 139457
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ad3439570aa4cb816db2a33b4a9726fb22a910d0eef4ab6124a2e307f169db56 oid sha256:21b97b5d0852b1dbe372304b5375fbcb0e036c8c5f8279464919248498899621
size 72046 size 77230
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:d3c166c83623fbda8e11afa3009601ee0decaa2fa80f514b84a38c619ee0fa05 oid sha256:d2f11cdd4e134b5450d4afd34257b4c55ab10a39620e35caa8530f927393b1aa
size 88135 size 93688