From 44828f6fa14c4cb06c661df34b22c19a213c991c Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Sun, 2 Aug 2026 01:06:58 +0530 Subject: [PATCH 1/2] Add image-preview accessibility labels and localize Mac save prompt. Fullscreen preview controls lacked accessibility labels, and NSSavePanel.prompt used a raw English string that bypasses the catalog. --- bitchat/Localizable.xcstrings | 561 ++++++++++++++++++ .../Image Viewers/ImagePreviewView.swift | 9 +- 2 files changed, 569 insertions(+), 1 deletion(-) diff --git a/bitchat/Localizable.xcstrings b/bitchat/Localizable.xcstrings index f869ab85..9e6dbbf8 100644 --- a/bitchat/Localizable.xcstrings +++ b/bitchat/Localizable.xcstrings @@ -66798,6 +66798,567 @@ } } }, + "image_preview.accessibility.image" : { + "comment" : "Accessibility label for the fullscreen image in the media preview viewer", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "bn" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bildvorschau" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vista previa de imagen" + } + }, + "fa" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "fil" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Aperçu de l'image" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "hi" : { + "stringUnit" : { + "state" : "translated", + "value" : "छवि पूर्वावलोकन" + } + }, + "id" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Anteprima immagine" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "画像プレビュー" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "이미지 미리보기" + } + }, + "ms" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "ne" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Afbeeldingsvoorbeeld" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Podgląd obrazu" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Prévia da imagem" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Просмотр изображения" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bildförhandsvisning" + } + }, + "ta" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "th" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Görsel önizleme" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "ur" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Image preview" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "图片预览" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "圖片預覽" + } + } + } + }, + + "image_preview.accessibility.close" : { + "comment" : "Accessibility label for the button that dismisses the fullscreen media preview", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "bn" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Vorschau schließen" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cerrar vista previa" + } + }, + "fa" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "fil" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fermer l'aperçu" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "hi" : { + "stringUnit" : { + "state" : "translated", + "value" : "पूर्वावलोकन बंद करें" + } + }, + "id" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Chiudi anteprima" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "プレビューを閉じる" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "미리보기 닫기" + } + }, + "ms" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "ne" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Voorbeeld sluiten" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zamknij podgląd" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fechar prévia" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Закрыть просмотр" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Stäng förhandsvisning" + } + }, + "ta" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "th" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Önizlemeyi kapat" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "ur" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close preview" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "关闭预览" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "關閉預覽" + } + } + } + }, + + "image_preview.accessibility.save" : { + "comment" : "Accessibility label for the button that saves the previewed media to disk", + "extractionState" : "manual", + "localizations" : { + "ar" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "bn" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "de" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bild speichern" + } + }, + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "es" : { + "stringUnit" : { + "state" : "translated", + "value" : "Guardar imagen" + } + }, + "fa" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "fil" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "fr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enregistrer l'image" + } + }, + "he" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "hi" : { + "stringUnit" : { + "state" : "translated", + "value" : "छवि सहेजें" + } + }, + "id" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "it" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salva immagine" + } + }, + "ja" : { + "stringUnit" : { + "state" : "translated", + "value" : "画像を保存" + } + }, + "ko" : { + "stringUnit" : { + "state" : "translated", + "value" : "이미지 저장" + } + }, + "ms" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "ne" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "nl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Afbeelding bewaren" + } + }, + "pl" : { + "stringUnit" : { + "state" : "translated", + "value" : "Zapisz obraz" + } + }, + "pt" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "pt-BR" : { + "stringUnit" : { + "state" : "translated", + "value" : "Salvar imagem" + } + }, + "ru" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сохранить изображение" + } + }, + "sv" : { + "stringUnit" : { + "state" : "translated", + "value" : "Spara bild" + } + }, + "ta" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "th" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "tr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Görseli kaydet" + } + }, + "uk" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "ur" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "vi" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save image" + } + }, + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "保存图片" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "儲存圖片" + } + } + } + }, + "save" : { "comment" : "Button to save media to device", "localizations" : { diff --git a/bitchat/Views/Image Viewers/ImagePreviewView.swift b/bitchat/Views/Image Viewers/ImagePreviewView.swift index c7b4fb92..0e2eb3b6 100644 --- a/bitchat/Views/Image Viewers/ImagePreviewView.swift +++ b/bitchat/Views/Image Viewers/ImagePreviewView.swift @@ -33,16 +33,19 @@ struct ImagePreviewView: View { .resizable() .aspectRatio(contentMode: .fit) .padding() + .accessibilityLabel(Text("image_preview.accessibility.image")) #else Image(nsImage: image) .resizable() .aspectRatio(contentMode: .fit) .padding() + .accessibilityLabel(Text("image_preview.accessibility.image")) #endif } else { ProgressView() .progressViewStyle(.circular) .tint(.white) + .accessibilityLabel(Text("image_preview.accessibility.image")) } Spacer() HStack { @@ -54,6 +57,7 @@ struct ImagePreviewView: View { .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 12).stroke(Color.white.opacity(0.5), lineWidth: 1)) } + .accessibilityLabel(Text("image_preview.accessibility.close")) Spacer() Button(action: saveCopy) { Text("save", comment: "Button to save media to device") @@ -63,6 +67,7 @@ struct ImagePreviewView: View { .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 12).fill(Color.blue.opacity(0.6))) } + .accessibilityLabel(Text("image_preview.accessibility.save")) } .padding([.horizontal, .bottom], 24) } @@ -96,7 +101,9 @@ struct ImagePreviewView: View { let panel = NSSavePanel() panel.canCreateDirectories = true panel.nameFieldStringValue = url.lastPathComponent - panel.prompt = "save" + // SwiftUI Text("save") resolves via the catalog; NSSavePanel.prompt + // is a plain String and must be localized explicitly. + panel.prompt = String(localized: "save", defaultValue: "save", comment: "Button to save media to device") if panel.runModal() == .OK, let destination = panel.url { do { if FileManager.default.fileExists(atPath: destination.path) { From c35728c1de5c53b4dcc9a11b666299a7aaa12ade Mon Sep 17 00:00:00 2001 From: Ayush7614 Date: Mon, 10 Aug 2026 17:01:46 +0530 Subject: [PATCH 2/2] Fix image-preview a11y labels and drop redundant button overrides. Let Close/Save VoiceOver use the already-localized visible button titles, remove duplicate English-only accessibility keys, and translate image_preview.accessibility.image for locales that still had English placeholders. --- bitchat/Localizable.xcstrings | 400 +----------------- .../Image Viewers/ImagePreviewView.swift | 2 - 2 files changed, 14 insertions(+), 388 deletions(-) diff --git a/bitchat/Localizable.xcstrings b/bitchat/Localizable.xcstrings index 9e6dbbf8..da980e09 100644 --- a/bitchat/Localizable.xcstrings +++ b/bitchat/Localizable.xcstrings @@ -66805,13 +66805,13 @@ "ar" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "معاينة الصورة" } }, "bn" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "ছবির প্রিভিউ" } }, "de" : { @@ -66835,13 +66835,13 @@ "fa" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "پیش‌نمایش تصویر" } }, "fil" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Preview ng larawan" } }, "fr" : { @@ -66853,7 +66853,7 @@ "he" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "תצוגה מקדימה של תמונה" } }, "hi" : { @@ -66865,7 +66865,7 @@ "id" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Pratinjau gambar" } }, "it" : { @@ -66889,13 +66889,13 @@ "ms" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Pratonton imej" } }, "ne" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "छवि पूर्वावलोकन" } }, "nl" : { @@ -66913,7 +66913,7 @@ "pt" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Pré-visualização da imagem" } }, "pt-BR" : { @@ -66937,13 +66937,13 @@ "ta" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "பட முன்நோக்கு" } }, "th" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "ดูตัวอย่างรูปภาพ" } }, "tr" : { @@ -66955,19 +66955,19 @@ "uk" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Попередній перегляд зображення" } }, "ur" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "تصویر کا پیش نظارہ" } }, "vi" : { "stringUnit" : { "state" : "translated", - "value" : "Image preview" + "value" : "Xem trước hình ảnh" } }, "zh-Hans" : { @@ -66985,379 +66985,7 @@ } }, - "image_preview.accessibility.close" : { - "comment" : "Accessibility label for the button that dismisses the fullscreen media preview", - "extractionState" : "manual", - "localizations" : { - "ar" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "bn" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Vorschau schließen" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Cerrar vista previa" - } - }, - "fa" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "fil" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Fermer l'aperçu" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "hi" : { - "stringUnit" : { - "state" : "translated", - "value" : "पूर्वावलोकन बंद करें" - } - }, - "id" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Chiudi anteprima" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "プレビューを閉じる" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "미리보기 닫기" - } - }, - "ms" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "ne" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Voorbeeld sluiten" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Zamknij podgląd" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Fechar prévia" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Закрыть просмотр" - } - }, - "sv" : { - "stringUnit" : { - "state" : "translated", - "value" : "Stäng förhandsvisning" - } - }, - "ta" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "th" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Önizlemeyi kapat" - } - }, - "uk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "ur" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "vi" : { - "stringUnit" : { - "state" : "translated", - "value" : "Close preview" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "关闭预览" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "關閉預覽" - } - } - } - }, - "image_preview.accessibility.save" : { - "comment" : "Accessibility label for the button that saves the previewed media to disk", - "extractionState" : "manual", - "localizations" : { - "ar" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "bn" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "de" : { - "stringUnit" : { - "state" : "translated", - "value" : "Bild speichern" - } - }, - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Guardar imagen" - } - }, - "fa" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "fil" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "fr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enregistrer l'image" - } - }, - "he" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "hi" : { - "stringUnit" : { - "state" : "translated", - "value" : "छवि सहेजें" - } - }, - "id" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "it" : { - "stringUnit" : { - "state" : "translated", - "value" : "Salva immagine" - } - }, - "ja" : { - "stringUnit" : { - "state" : "translated", - "value" : "画像を保存" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "이미지 저장" - } - }, - "ms" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "ne" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "nl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Afbeelding bewaren" - } - }, - "pl" : { - "stringUnit" : { - "state" : "translated", - "value" : "Zapisz obraz" - } - }, - "pt" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "pt-BR" : { - "stringUnit" : { - "state" : "translated", - "value" : "Salvar imagem" - } - }, - "ru" : { - "stringUnit" : { - "state" : "translated", - "value" : "Сохранить изображение" - } - }, - "sv" : { - "stringUnit" : { - "state" : "translated", - "value" : "Spara bild" - } - }, - "ta" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "th" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "tr" : { - "stringUnit" : { - "state" : "translated", - "value" : "Görseli kaydet" - } - }, - "uk" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "ur" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "vi" : { - "stringUnit" : { - "state" : "translated", - "value" : "Save image" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "保存图片" - } - }, - "zh-Hant" : { - "stringUnit" : { - "state" : "translated", - "value" : "儲存圖片" - } - } - } - }, "save" : { "comment" : "Button to save media to device", diff --git a/bitchat/Views/Image Viewers/ImagePreviewView.swift b/bitchat/Views/Image Viewers/ImagePreviewView.swift index 0e2eb3b6..08200ed3 100644 --- a/bitchat/Views/Image Viewers/ImagePreviewView.swift +++ b/bitchat/Views/Image Viewers/ImagePreviewView.swift @@ -57,7 +57,6 @@ struct ImagePreviewView: View { .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 12).stroke(Color.white.opacity(0.5), lineWidth: 1)) } - .accessibilityLabel(Text("image_preview.accessibility.close")) Spacer() Button(action: saveCopy) { Text("save", comment: "Button to save media to device") @@ -67,7 +66,6 @@ struct ImagePreviewView: View { .padding(.vertical, 8) .background(RoundedRectangle(cornerRadius: 12).fill(Color.blue.opacity(0.6))) } - .accessibilityLabel(Text("image_preview.accessibility.save")) } .padding([.horizontal, .bottom], 24) }