diff --git a/ScreenTextGrab/AutomationSupport.swift b/ScreenTextGrab/AutomationSupport.swift index e8ec7b5..60381f5 100644 --- a/ScreenTextGrab/AutomationSupport.swift +++ b/ScreenTextGrab/AutomationSupport.swift @@ -515,6 +515,8 @@ private extension OCRLanguagePreference { return .italian case "pt", "pt-br", "portuguese", "portugues": return .portuguese + case "zh", "zh-hans", "zh-cn", "chinese", "简体中文": + return .chinese default: return nil } @@ -536,6 +538,8 @@ private extension OCRLanguagePreference { return "it" case .portuguese: return "pt" + case .chinese: + return "zh" } } } diff --git a/ScreenTextGrab/Localization.swift b/ScreenTextGrab/Localization.swift index a0686c1..aa004ec 100644 --- a/ScreenTextGrab/Localization.swift +++ b/ScreenTextGrab/Localization.swift @@ -34,8 +34,18 @@ enum L10n { languageIdentifier.hasPrefix("en") } + static var usesChinese: Bool { + languageIdentifier.hasPrefix("zh") + } + static func pair(_ tr: String, _ en: String) -> String { - usesEnglish ? en : tr + if usesChinese { return en } + return usesEnglish ? en : tr + } + + static func triple(_ tr: String, _ en: String, _ zh: String) -> String { + if usesChinese { return zh } + return usesEnglish ? en : tr } static func format(_ tr: String, _ en: String, _ arguments: CVarArg...) -> String { @@ -43,44 +53,44 @@ enum L10n { return String(format: format, locale: Locale.current, arguments: arguments) } - static var controlsTitle: String { pair("Kontroller", "Controls") } - static var settingsTitle: String { pair("ScreenTextGrab Ayarları", "ScreenTextGrab Settings") } - static var settingsSubtitle: String { pair("Kısayol, izinler, OCR dili ve geçmiş yönetimini buradan düzenle.", "Manage shortcuts, permissions, OCR language, and history here.") } + static var controlsTitle: String { triple("Kontroller", "Controls", "控制") } + static var settingsTitle: String { triple("ScreenTextGrab Ayarları", "ScreenTextGrab Settings", "ScreenTextGrab 设置") } + static var settingsSubtitle: String { triple("Kısayol, izinler, OCR dili ve geçmiş yönetimini buradan düzenle.", "Manage shortcuts, permissions, OCR language, and history here.", "在此管理快捷键、权限、OCR 语言和历史记录。") } - static var settingsTabGeneral: String { pair("Genel", "General") } + static var settingsTabGeneral: String { triple("Genel", "General", "通用") } static var settingsTabOCR: String { "OCR" } - static var settingsTabDiagnostics: String { pair("Tanı", "Diagnostics") } - static var settingsTabHistory: String { pair("Geçmiş", "History") } + static var settingsTabDiagnostics: String { triple("Tanı", "Diagnostics", "诊断") } + static var settingsTabHistory: String { triple("Geçmiş", "History", "历史记录") } - static var actionSettings: String { pair("Ayarlar", "Settings") } - static var actionRefresh: String { pair("Yenile", "Refresh") } - static var actionClipboardImage: String { pair("Panodaki Görseli Oku", "Read Clipboard Image") } - static var actionImageFile: String { pair("Görsel Dosyası Oku", "Read Image File") } - static var actionPDFFile: String { pair("PDF Oku", "Read PDF") } + static var actionSettings: String { triple("Ayarlar", "Settings", "设置") } + static var actionRefresh: String { triple("Yenile", "Refresh", "刷新") } + static var actionClipboardImage: String { triple("Panodaki Görseli Oku", "Read Clipboard Image", "读取剪贴板图片") } + static var actionImageFile: String { triple("Görsel Dosyası Oku", "Read Image File", "读取图片文件") } + static var actionPDFFile: String { triple("PDF Oku", "Read PDF", "读取 PDF") } static var actionSearchablePDF: String { "Searchable PDF" } - static var actionCheckForUpdates: String { pair("Güncellemeleri Kontrol Et", "Check for Updates") } - static var actionCheckingForUpdates: String { pair("Kontrol Ediliyor...", "Checking...") } - static var actionDownloadingUpdate: String { pair("İndiriliyor...", "Downloading...") } - static var actionRestartToUpdate: String { pair("Yeniden Başlat ve Güncelle", "Restart & Update") } - static var actionRetryUpdate: String { pair("Tekrar Dene", "Try Again") } - static var actionUpToDate: String { pair("Güncel", "Up to Date") } - static var actionAllow: String { pair("İzin Ver", "Allow Access") } - static var actionSystemSettings: String { pair("Sistem Ayarları", "System Settings") } - static var actionRequestPermission: String { pair("İzin İste", "Request Access") } - static var actionDiagnostics: String { pair("Tanı", "Diagnostics") } - static var actionCopy: String { pair("Kopyala", "Copy") } - static var actionDelete: String { pair("Sil", "Delete") } - static var actionExport: String { pair("Dışa Aktar", "Export") } - static var actionClear: String { pair("Temizle", "Clear") } - static var actionSupportBundle: String { pair("Support Paketi", "Support Bundle") } - static var actionCopyDiagnostics: String { pair("Tanıyı Kopyala", "Copy Diagnostics") } - static var actionLoginItems: String { pair("Giriş Öğeleri", "Login Items") } - static var actionDefault: String { pair("Varsayılan", "Default") } - static var actionChange: String { pair("Değiştir", "Change") } - static var actionCancel: String { pair("İptal", "Cancel") } - static var actionOpenApplicationsFolder: String { pair("Applications Klasörünü Aç", "Open Applications Folder") } - static var actionContinue: String { pair("Devam Et", "Continue") } - static var ocrAutomaticLanguage: String { pair("Dili otomatik algıla", "Automatically detect language") } + static var actionCheckForUpdates: String { triple("Güncellemeleri Kontrol Et", "Check for Updates", "检查更新") } + static var actionCheckingForUpdates: String { triple("Kontrol Ediliyor...", "Checking...", "检查中...") } + static var actionDownloadingUpdate: String { triple("İndiriliyor...", "Downloading...", "下载中...") } + static var actionRestartToUpdate: String { triple("Yeniden Başlat ve Güncelle", "Restart & Update", "重启并更新") } + static var actionRetryUpdate: String { triple("Tekrar Dene", "Try Again", "重试") } + static var actionUpToDate: String { triple("Güncel", "Up to Date", "已是最新") } + static var actionAllow: String { triple("İzin Ver", "Allow Access", "允许访问") } + static var actionSystemSettings: String { triple("Sistem Ayarları", "System Settings", "系统设置") } + static var actionRequestPermission: String { triple("İzin İste", "Request Access", "请求权限") } + static var actionDiagnostics: String { triple("Tanı", "Diagnostics", "诊断") } + static var actionCopy: String { triple("Kopyala", "Copy", "复制") } + static var actionDelete: String { triple("Sil", "Delete", "删除") } + static var actionExport: String { triple("Dışa Aktar", "Export", "导出") } + static var actionClear: String { triple("Temizle", "Clear", "清除") } + static var actionSupportBundle: String { triple("Support Paketi", "Support Bundle", "支持包") } + static var actionCopyDiagnostics: String { triple("Tanıyı Kopyala", "Copy Diagnostics", "复制诊断信息") } + static var actionLoginItems: String { triple("Giriş Öğeleri", "Login Items", "登录项") } + static var actionDefault: String { triple("Varsayılan", "Default", "默认") } + static var actionChange: String { triple("Değiştir", "Change", "更改") } + static var actionCancel: String { triple("İptal", "Cancel", "取消") } + static var actionOpenApplicationsFolder: String { triple("Applications Klasörünü Aç", "Open Applications Folder", "打开应用程序文件夹") } + static var actionContinue: String { triple("Devam Et", "Continue", "继续") } + static var ocrAutomaticLanguage: String { triple("Dili otomatik algıla", "Automatically detect language", "自动检测语言") } static var installRootUnavailable: String { pair("Applications klasöründe yazılabilir bir hedef bulunamadı.", "No writable install destination was found in Applications.") } static var installCopyFailedPrefix: String { pair("Uygulama Applications klasörüne taşınamadı:", "The app could not be moved to Applications:") } @@ -90,12 +100,12 @@ enum L10n { static var installAlertTitle: String { pair("Uygulamayı Applications klasöründen aç", "Open the app from Applications") } static var installAlertBody: String { pair("ScreenTextGrab izinleri ve Spotlight kaydını stabil tutmak için Applications klasöründen çalışmalıdır.", "ScreenTextGrab should run from Applications so permissions and Spotlight registration stay stable.") } - static var accessibilityQuitApp: String { pair("Uygulamadan çık", "Quit app") } - static var accessibilityCheckForUpdates: String { pair("Güncellemeleri kontrol et", "Check for updates") } - static var accessibilityResetHotkey: String { pair("Kısayolu varsayılana döndür", "Reset shortcut to default") } - static var accessibilityLaunchAtLoginToggle: String { pair("Açılışta başlat", "Launch at login") } - static var accessibilityCaptureMode: String { pair("Yakalama modu", "Capture mode") } - static var accessibilityOCRLanguage: String { pair("OCR dili", "OCR language") } - static var accessibilityAutomaticLanguage: String { pair("Dili otomatik algıla", "Automatically detect language") } - static var accessibilityInterfaceLanguage: String { pair("Arayüz dili", "Interface language") } + static var accessibilityQuitApp: String { triple("Uygulamadan çık", "Quit app", "退出应用") } + static var accessibilityCheckForUpdates: String { triple("Güncellemeleri kontrol et", "Check for updates", "检查更新") } + static var accessibilityResetHotkey: String { triple("Kısayolu varsayılana döndür", "Reset shortcut to default", "重置快捷键为默认") } + static var accessibilityLaunchAtLoginToggle: String { triple("Açılışta başlat", "Launch at login", "开机启动") } + static var accessibilityCaptureMode: String { triple("Yakalama modu", "Capture mode", "捕获模式") } + static var accessibilityOCRLanguage: String { triple("OCR dili", "OCR language", "OCR 语言") } + static var accessibilityAutomaticLanguage: String { triple("Dili otomatik algıla", "Automatically detect language", "自动检测语言") } + static var accessibilityInterfaceLanguage: String { triple("Arayüz dili", "Interface language", "界面语言") } } diff --git a/ScreenTextGrab/Models/AppModels.swift b/ScreenTextGrab/Models/AppModels.swift index 2b2638e..b7edd52 100644 --- a/ScreenTextGrab/Models/AppModels.swift +++ b/ScreenTextGrab/Models/AppModels.swift @@ -112,26 +112,26 @@ enum CaptureMode: String, CaseIterable, Codable, Equatable, Sendable, Identifiab var title: String { switch self { case .standard: - return L10n.pair("Standart", "Standard") + return L10n.triple("Standart", "Standard", "标准") case .subtitle: - return L10n.pair("Altyazı", "Subtitle") + return L10n.triple("Altyazı", "Subtitle", "字幕") case .code: - return L10n.pair("Kod", "Code") + return L10n.triple("Kod", "Code", "代码") case .table: - return L10n.pair("Tablo", "Table") + return L10n.triple("Tablo", "Table", "表格") } } var shortTitle: String { switch self { case .standard: - return L10n.pair("Standart", "Standard") + return L10n.triple("Standart", "Standard", "标准") case .subtitle: - return L10n.pair("Altyazı", "Subtitle") + return L10n.triple("Altyazı", "Subtitle", "字幕") case .code: - return L10n.pair("Kod", "Code") + return L10n.triple("Kod", "Code", "代码") case .table: - return L10n.pair("Tablo", "Table") + return L10n.triple("Tablo", "Table", "表格") } } @@ -239,11 +239,11 @@ enum CaptureOutputPreset: String, CaseIterable, Codable, Equatable, Sendable, Id var title: String { switch self { case .smart: - return L10n.pair("Akıllı", "Smart") + return L10n.triple("Akıllı", "Smart", "智能") case .plainText: - return L10n.pair("Düz Metin", "Plain Text") + return L10n.triple("Düz Metin", "Plain Text", "纯文本") case .cleaned: - return L10n.pair("Temizlenmiş", "Cleaned") + return L10n.triple("Temizlenmiş", "Cleaned", "已清理") case .office: return "Office" case .markdown: @@ -256,7 +256,7 @@ enum CaptureOutputPreset: String, CaseIterable, Codable, Equatable, Sendable, Id var shortTitle: String { switch self { case .smart: - return L10n.pair("Akıllı", "Smart") + return L10n.triple("Akıllı", "Smart", "智能") case .plainText: return L10n.pair("Düz", "Plain") case .cleaned: @@ -273,11 +273,11 @@ enum CaptureOutputPreset: String, CaseIterable, Codable, Equatable, Sendable, Id var summary: String { switch self { case .smart: - return L10n.pair("Moda göre en uygun sonuç", "Best result for the current mode") + return L10n.triple("Moda göre en uygun sonuç", "Best result for the current mode", "当前模式的最佳结果") case .plainText: - return L10n.pair("Yalın ve doğrudan metin", "Simple, direct text") + return L10n.triple("Yalın ve doğrudan metin", "Simple, direct text", "简洁直接的文本") case .cleaned: - return L10n.pair("OCR gürültüsünü azaltır", "Reduces OCR noise") + return L10n.triple("OCR gürültüsünü azaltır", "Reduces OCR noise", "减少 OCR 噪声") case .office: return L10n.pair("Office ve tablo uygulamalarıyla uyumlu", "Works well with spreadsheet and word processor apps") case .markdown: @@ -481,6 +481,7 @@ enum OCRLanguagePreference: String, CaseIterable, Codable, Equatable, Sendable, case spanish = "es-ES" case italian = "it-IT" case portuguese = "pt-BR" + case chinese = "zh-Hans" var id: String { rawValue } @@ -500,6 +501,8 @@ enum OCRLanguagePreference: String, CaseIterable, Codable, Equatable, Sendable, return L10n.pair("Italiano", "Italian") case .portuguese: return L10n.pair("Português", "Portuguese") + case .chinese: + return L10n.triple("Çince", "Chinese", "简体中文") } } @@ -519,6 +522,8 @@ enum OCRLanguagePreference: String, CaseIterable, Codable, Equatable, Sendable, return "IT" case .portuguese: return "PT" + case .chinese: + return "ZH" } } } diff --git a/ScreenTextGrab/Models/CapturePreferences.swift b/ScreenTextGrab/Models/CapturePreferences.swift index 162d0aa..82527be 100644 --- a/ScreenTextGrab/Models/CapturePreferences.swift +++ b/ScreenTextGrab/Models/CapturePreferences.swift @@ -280,6 +280,7 @@ enum InterfaceLanguage: String, CaseIterable, Codable, Equatable, Sendable, Iden case system case turkish case english + case chinese var id: String { rawValue } @@ -291,6 +292,8 @@ enum InterfaceLanguage: String, CaseIterable, Codable, Equatable, Sendable, Iden return "Türkçe" case .english: return "English" + case .chinese: + return "简体中文" } } @@ -302,6 +305,8 @@ enum InterfaceLanguage: String, CaseIterable, Codable, Equatable, Sendable, Iden return L10n.pair("Arayüz her zaman Türkçe görünür.", "The interface always appears in Turkish.") case .english: return L10n.pair("Arayüz her zaman English görünür.", "The interface always appears in English.") + case .chinese: + return L10n.triple("Arayüz her zaman Çince görünür.", "The interface always appears in Chinese.", "界面始终显示为简体中文。") } } @@ -313,6 +318,8 @@ enum InterfaceLanguage: String, CaseIterable, Codable, Equatable, Sendable, Iden return "tr" case .english: return "en" + case .chinese: + return "zh" } } } diff --git a/ScreenTextGrab/Views/Settings/SettingsTabViews.swift b/ScreenTextGrab/Views/Settings/SettingsTabViews.swift index 3e3d601..2532111 100644 --- a/ScreenTextGrab/Views/Settings/SettingsTabViews.swift +++ b/ScreenTextGrab/Views/Settings/SettingsTabViews.swift @@ -62,7 +62,7 @@ struct SettingsGeneralTabView: View { ScrollView { VStack(spacing: 14) { SettingsSectionCard( - title: L10n.pair("Arayüz Dili", "Interface Language"), + title: L10n.triple("Arayüz Dili", "Interface Language", "界面语言"), subtitle: interfaceLanguageDetail ) { Picker("", selection: interfaceLanguageBinding) { @@ -85,7 +85,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Yakalama Modu", "Capture Mode"), + title: L10n.triple("Yakalama Modu", "Capture Mode", "捕获模式"), subtitle: L10n.pair("Metin, altyazı, kod veya tablo odaklı yakalama arasında geçiş yap.", "Switch between text, subtitle, code, or table-focused capture.") ) { LazyVGrid( @@ -108,7 +108,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Çıktı Biçimi", "Output Format"), + title: L10n.triple("Çıktı Biçimi", "Output Format", "输出格式"), subtitle: outputPresetDetail ) { LazyVGrid( @@ -127,7 +127,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Global Kısayol", "Global Shortcut"), + title: L10n.triple("Global Kısayol", "Global Shortcut", "全局快捷键"), subtitle: isRecordingHotkey ? L10n.pair("Yeni kombinasyonu gir. Esc ile iptal edebilirsin.", "Enter the new combination. Press Esc to cancel.") : L10n.pair("Yakalamayı her yerden başlatmak için kullanılır.", "Use it to start capture from anywhere.") @@ -167,7 +167,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Açılışta Başlat", "Launch at Login"), + title: L10n.triple("Açılışta Başlat", "Launch at Login", "开机启动"), subtitle: launchAtLoginDetail ) { HStack(spacing: 12) { @@ -203,7 +203,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("URL Otomasyonu", "URL Automation"), + title: L10n.triple("URL Otomasyonu", "URL Automation", "URL 自动化"), subtitle: L10n.pair( "stg:// bağlantılarının ekran yakalama ve dosya OCR tetiklemesine izin ver.", "Allow stg:// links to trigger screen capture and file OCR." @@ -226,7 +226,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("İzleme Kuralları", "Watch Rules"), + title: L10n.triple("İzleme Kuralları", "Watch Rules", "监听规则"), subtitle: watchSummary ) { HStack(spacing: 10) { @@ -264,7 +264,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Ekran Kaydı İzni", "Screen Recording Permission"), + title: L10n.triple("Ekran Kaydı İzni", "Screen Recording Permission", "屏幕录制权限"), subtitle: permissionSubtitle ) { HStack(spacing: 12) { @@ -310,7 +310,7 @@ struct SettingsGeneralTabView: View { } SettingsSectionCard( - title: L10n.pair("Uygulama Profilleri", "App Profiles"), + title: L10n.triple("Uygulama Profilleri", "App Profiles", "应用配置"), subtitle: appProfileSummary ) { Menu { @@ -399,7 +399,7 @@ struct SettingsOCRTabView: View { ScrollView { VStack(spacing: 14) { SettingsSectionCard( - title: L10n.pair("Tanıma Modu", "Recognition Mode"), + title: L10n.triple("Tanıma Modu", "Recognition Mode", "识别模式"), subtitle: L10n.pair("Otomatik algılamayı açabilir veya tercih ettiğin dilleri sabitleyebilirsin.", "Turn on automatic detection or pin the languages you prefer.") ) { Toggle(L10n.ocrAutomaticLanguage, isOn: automaticDetectionBinding) @@ -418,7 +418,7 @@ struct SettingsOCRTabView: View { } SettingsSectionCard( - title: L10n.pair("Desteklenen Diller", "Supported Languages"), + title: L10n.triple("Desteklenen Diller", "Supported Languages", "支持的语言"), subtitle: ocrSelectionSummary ) { LazyVGrid( @@ -493,7 +493,7 @@ struct SettingsHistoryTabView: View { ScrollView { VStack(spacing: 14) { SettingsSectionCard( - title: L10n.pair("Kayıtlı Bölgeler", "Saved Regions"), + title: L10n.triple("Kayıtlı Bölgeler", "Saved Regions", "保存的区域"), subtitle: savedRegionsSummary ) { HStack(spacing: 10) { @@ -680,7 +680,7 @@ struct SettingsHistoryTabView: View { } SettingsSectionCard( - title: L10n.pair("Yakalama Geçmişi", "Capture History"), + title: L10n.triple("Yakalama Geçmişi", "Capture History", "捕获历史"), subtitle: historySummary ) { TextField(L10n.pair("Geçmişte ara", "Search history"), text: historySearchQuery) @@ -766,7 +766,7 @@ struct SettingsDiagnosticsTabView: View { ScrollView { VStack(spacing: 14) { SettingsSectionCard( - title: L10n.pair("İzin Tanısı", "Permission Diagnostics"), + title: L10n.triple("İzin Tanısı", "Permission Diagnostics", "权限诊断"), subtitle: permissionDiagnostics?.currentState.uiMessage ?? permissionStateMessage ) { VStack(alignment: .leading, spacing: 10) {