Skip to content

Commit

Permalink
Implement Apple Translate (#2065)
Browse files Browse the repository at this point in the history
* Implement a first version of Apple's Translation

The user can now choose between his instance's server, DeepL (with API
key) and Apple's Translation framework. A translation is cleared if
the translation type is changed. The strings aren't yet written, but
the translations settings view's inconsistent background is now fixed.

* Transfer the old "always_use_deepl" setting

The "always_use_deepl"-setting is now deleted, but its content is
transferred to the equivalent value in "preferred_translation_type".

* Show the user if the DeepL-API key is still stored

The user is now shown a prompt if they've switched away from
.useDeepl, but there's still an API key stored. The API key is not
deleted if the user doesn't instruct the app to do so, so this change
makes it more transparent, since a user might not expect the key to
be stored and might not want this to be the case.

* Localize Labels

The labels for the buttons and options are now localized. "DeepL API Key" is written consistently (with uppercase Key)

* Run all the strings through localization

The strings "DeepL" and "Apple Translate" are now also saved in
localizable.strings and addressed through keys. They were taken
directly previously, which was inconsistent.

* Fix storage

The selected value for preferredTranslationType wasn't stored, the
synchronization between UserPreferences and Storage is now in place.

* Hide Apple Translate if not yet on iOS 17.4

The Apple Translate option is hidden if the user hasn't updated their
phone to at least iOS 17.4. If the Apple Translate option is selected
but the user has downgraded to before iOS 17.4, the standard instance
option is selected.

* Consistently show Apple Translate

Apple Translate was previously only shown if the standard translate
button was visible, that is now fixed. It's now attached to the
StatusRowView, which is always present.

* Animate the removal of translations

The reset of a translation when the translation type is changed is now
animated, which is important for iPad users if they've translated a
post in the sidebar.

* Add support for the Mac Catalyst build

The Mac Catalyst Version doesn't allow the import of the api, so
compiler flags now check if the import isn't allowed and then remove
all references to Apple Translate.

* Swift Format

* Revert "Run all the strings through localization"

This reverts commit 86c5099.

# Conflicts:
#	Packages/Env/Sources/Env/TranslationType.swift

* Remove the DeepL fallback

The DeepL fallback for the instance translation service is removed,
error messages are shown if a translation fails.

* Allow for the use of an User API Key as fallback

The DeepL fallback is reinstated if the user has put in their own API
Key

* Make the localization keys clear strings

* Make Apple and the instance a fallback

Apple Translate is now a fallback for both other translation types,
the instance service is a fallback for DeepL.
  • Loading branch information
Havhingstor authored May 13, 2024
1 parent a8039df commit 48fadde
Show file tree
Hide file tree
Showing 15 changed files with 517 additions and 354 deletions.
4 changes: 0 additions & 4 deletions IceCubesApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@
9F7D93942980063100EE6B7A /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9F7D93932980063100EE6B7A /* AppAccount */; };
9F7D939A29805DBD00EE6B7A /* AccountSettingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */; };
9FA6FD6229C04A8800E2312C /* TranslationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */; };
9FAD85832971BF7200496AB1 /* Secret.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9FAD85822971BF7200496AB1 /* Secret.plist */; };
9FAD858B29743F7400496AB1 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FAD858A29743F7400496AB1 /* ShareViewController.swift */; };
9FAD858E29743F7400496AB1 /* (null) in Resources */ = {isa = PBXBuildFile; };
9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */; platformFilters = (ios, maccatalyst, ); settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -271,7 +270,6 @@
9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "IceCubesApp-release.xcconfig"; sourceTree = "<group>"; };
9F7D939929805DBD00EE6B7A /* AccountSettingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSettingView.swift; sourceTree = "<group>"; };
9FA6FD6129C04A8800E2312C /* TranslationSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TranslationSettingsView.swift; sourceTree = "<group>"; };
9FAD85822971BF7200496AB1 /* Secret.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Secret.plist; sourceTree = "<group>"; };
9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
9FAD858A29743F7400496AB1 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
9FAD858F29743F7400496AB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -602,7 +600,6 @@
9FAE4AC8293774FF00772766 /* Info.plist */,
9F398AB429360A5800A889F2 /* App */,
9F398AB529360A6100A889F2 /* Resources */,
9FAD85822971BF7200496AB1 /* Secret.plist */,
);
path = IceCubesApp;
sourceTree = "<group>";
Expand Down Expand Up @@ -960,7 +957,6 @@
9F18801829AE477F00D85459 /* favorite.wav in Resources */,
9F24EEB829360C330042359D /* Preview Assets.xcassets in Resources */,
069709A8298C87B5006E4CB5 /* OpenDyslexic-Regular.otf in Resources */,
9FAD85832971BF7200496AB1 /* Secret.plist in Resources */,
9F18801229AE477F00D85459 /* tabSelection.wav in Resources */,
9F18801429AE477F00D85459 /* bookmark.wav in Resources */,
9F18801629AE477F00D85459 /* refresh.wav in Resources */,
Expand Down
30 changes: 29 additions & 1 deletion IceCubesApp/App/Tabs/Settings/SettingsTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ struct SettingsTabs: View {
@Binding var popToRootTab: Tab

let isModal: Bool


@State private var startingPoint: SettingsStartingPoint? = nil

var body: some View {
NavigationStack(path: $routerPath.path) {
Form {
Expand Down Expand Up @@ -64,6 +66,32 @@ struct SettingsTabs: View {
}
.withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.onAppear {
startingPoint = RouterPath.settingsStartingPoint
RouterPath.settingsStartingPoint = nil
}
.navigationDestination(item: $startingPoint) { targetView in
switch targetView {
case .display:
DisplaySettingsView()
case .haptic:
HapticSettingsView()
case .remoteTimelines:
RemoteTimelinesSettingView()
case .tagGroups:
TagsGroupSettingView()
case .recentTags:
RecenTagsSettingView()
case .content:
ContentSettingsView()
case .swipeActions:
SwipeActionsSettingsView()
case .tabAndSidebarEntries:
EmptyView()
case .translation:
TranslationSettingsView()
}
}
}
.onAppear {
routerPath.client = client
Expand Down
68 changes: 55 additions & 13 deletions IceCubesApp/App/Tabs/Settings/TranslationSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,13 @@ struct TranslationSettingsView: View {

var body: some View {
Form {
deepLToggle
if preferences.alwaysUseDeepl {
translationSelector
if preferences.preferredTranslationType == .useDeepl {
Section("settings.translation.user-api-key") {
deepLPicker
SecureField("settings.translation.user-api-key", text: $apiKey)
.textContentType(.password)
}
.onAppear {
readValue()
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
Expand All @@ -37,6 +34,7 @@ struct TranslationSettingsView: View {
#endif
}
}
backgroundAPIKey
autoDetectSection
}
.navigationTitle("settings.translation.navigation-title")
Expand All @@ -48,19 +46,39 @@ struct TranslationSettingsView: View {
writeNewValue()
}
.onAppear(perform: updatePrefs)
.onAppear(perform: readValue)
}

@ViewBuilder
private var deepLToggle: some View {
private var translationSelector: some View {
@Bindable var preferences = preferences
Toggle(isOn: $preferences.alwaysUseDeepl) {
Text("settings.translation.always-deepl")
Picker("settings.translation.preferred-translation-type", selection: $preferences.preferredTranslationType) {
ForEach(allTTCases, id: \.self) { type in
Text(type.description).tag(type)
}
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}

var allTTCases: [TranslationType] {
TranslationType.allCases.filter { type in
if type != .useApple {
return true
}
#if canImport(_Translation_SwiftUI)
if #available(iOS 17.4, *) {
return true
} else {
return false
}
#else
return false
#endif
}
}

@ViewBuilder
private var deepLPicker: some View {
@Bindable var preferences = preferences
Expand All @@ -80,6 +98,34 @@ struct TranslationSettingsView: View {
} footer: {
Text("settings.translation.auto-detect-post-language-footer")
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}

@ViewBuilder
private var backgroundAPIKey: some View {
if preferences.preferredTranslationType != .useDeepl,
!apiKey.isEmpty
{
Section {
Text("The DeepL API Key is still stored!")
if preferences.preferredTranslationType == .useServerIfPossible {
Text("It can however still be used as a fallback for your instance's translation service.")
}
Button(role: .destructive) {
withAnimation {
writeNewValue(value: "")
readValue()
}
} label: {
Text("action.delete")
}
}
#if !os(visionOS)
.listRowBackground(theme.primaryBackgroundColor)
#endif
}
}

private func writeNewValue() {
Expand All @@ -91,11 +137,7 @@ struct TranslationSettingsView: View {
}

private func readValue() {
if let apiKey = DeepLUserAPIHandler.readIfAllowed() {
self.apiKey = apiKey
} else {
apiKey = ""
}
apiKey = DeepLUserAPIHandler.readKey()
}

private func updatePrefs() {
Expand Down
Loading

0 comments on commit 48fadde

Please sign in to comment.