Add Apple offline language downloads in settings
This commit is contained in:
@@ -33,6 +33,10 @@
|
||||
3ACB685F297633BC00C46468 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 3ACB685D297633BC00C46468 /* Localizable.strings */; };
|
||||
3ACBCB78295FE5C70037388A /* TimeAgoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ACBCB77295FE5C70037388A /* TimeAgoTests.swift */; };
|
||||
3AE45AF6297BB2E700C1D842 /* LibreTranslateServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE45AF5297BB2E700C1D842 /* LibreTranslateServer.swift */; };
|
||||
3AF9B5A82CA0B5CF0021A08E /* LanguageSortComparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5A72CA0B5CF0021A08E /* LanguageSortComparator.swift */; };
|
||||
3AF9B5A92CA0B5CF0021A08E /* LanguageSortComparator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5A72CA0B5CF0021A08E /* LanguageSortComparator.swift */; };
|
||||
3AF9B5AB2CA0D2D90021A08E /* AppleTranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5AA2CA0D2D90021A08E /* AppleTranslationSettingsView.swift */; };
|
||||
3AF9B5AC2CA0D2D90021A08E /* AppleTranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF9B5AA2CA0D2D90021A08E /* AppleTranslationSettingsView.swift */; };
|
||||
3CCD1E6A2A874C4E0099A953 /* Nip98HTTPAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CCD1E692A874C4E0099A953 /* Nip98HTTPAuth.swift */; };
|
||||
4C011B5E2BD0A56A002F2F9B /* ChatEventView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C011B5C2BD0A56A002F2F9B /* ChatEventView.swift */; };
|
||||
4C011B5F2BD0A56A002F2F9B /* ChatroomThreadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C011B5D2BD0A56A002F2F9B /* ChatroomThreadView.swift */; };
|
||||
@@ -1332,6 +1336,8 @@
|
||||
3AF6336829884C6B0005672A /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
3AF6336929884C6B0005672A /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
3AF6336A29884C6B0005672A /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "pt-PT"; path = "pt-PT.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
3AF9B5A72CA0B5CF0021A08E /* LanguageSortComparator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageSortComparator.swift; sourceTree = "<group>"; };
|
||||
3AF9B5AA2CA0D2D90021A08E /* AppleTranslationSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleTranslationSettingsView.swift; sourceTree = "<group>"; };
|
||||
3CCD1E692A874C4E0099A953 /* Nip98HTTPAuth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nip98HTTPAuth.swift; sourceTree = "<group>"; };
|
||||
4C011B5C2BD0A56A002F2F9B /* ChatEventView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatEventView.swift; sourceTree = "<group>"; };
|
||||
4C011B5D2BD0A56A002F2F9B /* ChatroomThreadView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChatroomThreadView.swift; sourceTree = "<group>"; };
|
||||
@@ -2276,6 +2282,7 @@
|
||||
4C1A9A2029DDD3E100516EAC /* KeySettingsView.swift */,
|
||||
4C1A9A2429DDDF2600516EAC /* ZapSettingsView.swift */,
|
||||
4C1A9A2629DDE31900516EAC /* TranslationSettingsView.swift */,
|
||||
3AF9B5AA2CA0D2D90021A08E /* AppleTranslationSettingsView.swift */,
|
||||
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */,
|
||||
5053ACA62A56DF3B00851AE3 /* DeveloperSettingsView.swift */,
|
||||
D7FD12252BD345A700CF195B /* FirstAidSettingsView.swift */,
|
||||
@@ -2743,6 +2750,7 @@
|
||||
D74AAFCE2B155D8C006CF0F4 /* ZapDataModel.swift */,
|
||||
D74AAFD32B155ECB006CF0F4 /* Zaps+.swift */,
|
||||
D74AAFD52B155F0C006CF0F4 /* WalletConnect+.swift */,
|
||||
3AF9B5A72CA0B5CF0021A08E /* LanguageSortComparator.swift */,
|
||||
);
|
||||
path = Util;
|
||||
sourceTree = "<group>";
|
||||
@@ -3774,6 +3782,7 @@
|
||||
5C8711DE2C460C06007879C2 /* PostingTimelineView.swift in Sources */,
|
||||
4CA9275D2A28FF630098A105 /* LongformView.swift in Sources */,
|
||||
4C75EFAD28049CFB0006080F /* PostButton.swift in Sources */,
|
||||
3AF9B5AC2CA0D2D90021A08E /* AppleTranslationSettingsView.swift in Sources */,
|
||||
D7EDED1E2B11797D0018B19C /* LongformEvent.swift in Sources */,
|
||||
504323A92A3495B6006AE6DC /* RelayModelCache.swift in Sources */,
|
||||
5C4D9EA72C042FA5005EA0F7 /* HighlightDraftContentView.swift in Sources */,
|
||||
@@ -3971,6 +3980,7 @@
|
||||
4C7D09622A098D0E00943473 /* WalletConnect.swift in Sources */,
|
||||
4C3EA67928FF7ABF00C48A62 /* list.c in Sources */,
|
||||
4C64987E286D082C00EAE2B3 /* DirectMessagesModel.swift in Sources */,
|
||||
3AF9B5A92CA0B5CF0021A08E /* LanguageSortComparator.swift in Sources */,
|
||||
4C12535E2A76CA870004F4B8 /* SwitchedTimelineNotify.swift in Sources */,
|
||||
D74F430A2B23F0BE00425B75 /* DamusPurple.swift in Sources */,
|
||||
9CA876E229A00CEA0003B9A3 /* AttachMediaUtility.swift in Sources */,
|
||||
@@ -4355,6 +4365,7 @@
|
||||
D73E5E7E2C6A97F4007EB227 /* Hashtags.swift in Sources */,
|
||||
D73E5E7F2C6A97F4007EB227 /* LocalNotification.swift in Sources */,
|
||||
D73E5E802C6A97F4007EB227 /* CredentialHandler.swift in Sources */,
|
||||
3AF9B5AB2CA0D2D90021A08E /* AppleTranslationSettingsView.swift in Sources */,
|
||||
D73E5E812C6A97F4007EB227 /* KeyboardVisible.swift in Sources */,
|
||||
D73E5E832C6A97F4007EB227 /* AVPlayer+Additions.swift in Sources */,
|
||||
D73E5E842C6A97F4007EB227 /* Zaps+.swift in Sources */,
|
||||
@@ -4449,6 +4460,7 @@
|
||||
D73E5EDE2C6A97F4007EB227 /* AppearanceSettingsView.swift in Sources */,
|
||||
D73E5EDF2C6A97F4007EB227 /* KeySettingsView.swift in Sources */,
|
||||
D73E5EE02C6A97F4007EB227 /* ZapSettingsView.swift in Sources */,
|
||||
3AF9B5A82CA0B5CF0021A08E /* LanguageSortComparator.swift in Sources */,
|
||||
D73E5F792C6A9C4C007EB227 /* HomeModel.swift in Sources */,
|
||||
D73E5EE12C6A97F4007EB227 /* TranslationSettingsView.swift in Sources */,
|
||||
D73E5EE22C6A97F4007EB227 /* SearchSettingsView.swift in Sources */,
|
||||
|
||||
51
damus/Util/LanguageSortComparator.swift
Normal file
51
damus/Util/LanguageSortComparator.swift
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// LanguageSortComparator.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Terry Yiu on 9/22/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct LanguageSortComparator: SortComparator {
|
||||
var order: SortOrder
|
||||
|
||||
func compare(_ lhs: Locale.Language, _ rhs: Locale.Language) -> ComparisonResult {
|
||||
let comparisonResult = compareForward(lhs, rhs)
|
||||
switch order {
|
||||
case .forward:
|
||||
return comparisonResult
|
||||
case .reverse:
|
||||
switch comparisonResult {
|
||||
case .orderedAscending:
|
||||
return .orderedDescending
|
||||
case .orderedDescending:
|
||||
return .orderedAscending
|
||||
case .orderedSame:
|
||||
return .orderedSame
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func compareForward(_ lhs: Locale.Language, _ rhs: Locale.Language) -> ComparisonResult {
|
||||
let currentLocale = Locale.current
|
||||
let localizedLhs = currentLocale.localizedString(forLanguage: lhs)
|
||||
let localizedRhs = currentLocale.localizedString(forLanguage: rhs)
|
||||
|
||||
return localizedLhs.localizedCompare(localizedRhs)
|
||||
}
|
||||
}
|
||||
|
||||
extension Locale {
|
||||
func localizedString(forLanguage language: Locale.Language) -> String {
|
||||
guard let languageCode = language.languageCode, let localizedLanguageCode = localizedString(forLanguageCode: languageCode.identifier) else {
|
||||
return language.languageCode?.identifier ?? language.minimalIdentifier
|
||||
}
|
||||
|
||||
if let region = language.region, let localizedRegion = localizedString(forRegionCode: region.identifier) {
|
||||
return "\(localizedLanguageCode) (\(localizedRegion))"
|
||||
} else {
|
||||
return localizedLanguageCode
|
||||
}
|
||||
}
|
||||
}
|
||||
90
damus/Views/Settings/AppleTranslationSettingsView.swift
Normal file
90
damus/Views/Settings/AppleTranslationSettingsView.swift
Normal file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// AppleTranslationSettingsView.swift
|
||||
// damus
|
||||
//
|
||||
// Created by Terry Yiu on 9/22/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Translation
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct AppleTranslationSettingsView: View {
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
|
||||
@State private var supportedLanguages: [Locale.Language] = []
|
||||
@State private var installedLanguages = Set<Locale.Language>()
|
||||
@State private var installingLanguages = Set<Locale.Language>()
|
||||
@State private var languageTranslationConfigurations = [Locale.Language: TranslationSession.Configuration]()
|
||||
|
||||
var body: some View {
|
||||
if settings.translation_service == .none {
|
||||
if !installedLanguages.isEmpty {
|
||||
Section(NSLocalizedString("Available Offline", comment: "Section for downloaded languages for Apple offline translations.")) {
|
||||
ForEach(installedLanguages.sorted(using: LanguageSortComparator(order: .forward)), id: \.self) { language in
|
||||
Text(Locale.current.localizedString(forLanguage: language))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Section(NSLocalizedString("Languages Available for Download", comment: "Section for downloadable languages for Apple offline translations.")) {
|
||||
ForEach(supportedLanguages.filter { !installedLanguages.contains($0) }, id: \.self) { language in
|
||||
HStack {
|
||||
Text(Locale.current.localizedString(forLanguage: language))
|
||||
Button(
|
||||
action: {
|
||||
installingLanguages.insert(language)
|
||||
languageTranslationConfigurations[language]?.invalidate()
|
||||
},
|
||||
label: {
|
||||
Image(systemName: "arrow.down.circle")
|
||||
}
|
||||
)
|
||||
}
|
||||
.translationTask(languageTranslationConfigurations[language]) { session in
|
||||
if installingLanguages.contains(language) {
|
||||
do {
|
||||
// Display a sheet asking the user's permission
|
||||
// to start downloading the language pairing by
|
||||
// translating a dummy string.
|
||||
//
|
||||
// We do not use `session.prepareTranslation()` because
|
||||
// it does not throw errors as loudly as `session.translate` does,
|
||||
// which helps us indicate when language download is complete.
|
||||
_ = try await session.translate("A")
|
||||
installedLanguages.insert(language)
|
||||
installingLanguages.remove(language)
|
||||
} catch {
|
||||
// Handle any errors.
|
||||
print("Error downloading language \(language): \(error)")
|
||||
installingLanguages.remove(language)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
Task {
|
||||
let languageAvailability = LanguageAvailability()
|
||||
supportedLanguages = await languageAvailability.supportedLanguages
|
||||
supportedLanguages.sort(using: LanguageSortComparator(order: .forward))
|
||||
installedLanguages.removeAll()
|
||||
|
||||
for supportedLanguage in supportedLanguages {
|
||||
let status = await languageAvailability.status(from: supportedLanguage, to: nil)
|
||||
switch status {
|
||||
case .installed:
|
||||
installedLanguages.insert(supportedLanguage)
|
||||
case .supported:
|
||||
languageTranslationConfigurations[supportedLanguage] = TranslationSession.Configuration(
|
||||
source: supportedLanguage
|
||||
)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,13 +6,14 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Translation
|
||||
|
||||
struct TranslationSettingsView: View {
|
||||
@ObservedObject var settings: UserSettingsStore
|
||||
var damus_state: DamusState
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section(NSLocalizedString("Translations", comment: "Section title for selecting the translation service.")) {
|
||||
@@ -100,8 +101,15 @@ struct TranslationSettingsView: View {
|
||||
Toggle(NSLocalizedString("Translate DMs", comment: "Toggle to translate direct messages."), isOn: $settings.translate_dms)
|
||||
.toggleStyle(.switch)
|
||||
*/
|
||||
} else if #available(iOS 18.0, *) {
|
||||
Toggle(NSLocalizedString("Automatically translate notes", comment: "Toggle to automatically translate notes."), isOn: $settings.auto_translate)
|
||||
.toggleStyle(.switch)
|
||||
}
|
||||
}
|
||||
|
||||
if #available(iOS 18.0, *) {
|
||||
AppleTranslationSettingsView(settings: settings)
|
||||
}
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("Translation", comment: "Navigation title for translation settings."))
|
||||
.onReceive(handle_notify(.switched_timeline)) { _ in
|
||||
|
||||
Reference in New Issue
Block a user