damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 957ac1dc03bf6a250fad08f24e323076049a9994
parent a58ca2918a9e319af4f3cdb29818804aa7a68812
Author: Mazin <cm@monstaboyent.com>
Date:   Tue,  9 May 2023 22:38:11 -0400

Add translate.nostr.wine to available translation services

Closes: https://github.com/damus-io/damus/pull/1113
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus/Models/TranslationService.swift | 3+++
Mdamus/Models/UserSettingsStore.swift | 14++++++++++++++
Mdamus/Util/Translator.swift | 25+++++++++++++++++++++++++
Mdamus/Views/Settings/TranslationSettingsView.swift | 11+++++++++++
4 files changed, 53 insertions(+), 0 deletions(-)

diff --git a/damus/Models/TranslationService.swift b/damus/Models/TranslationService.swift @@ -32,6 +32,7 @@ enum TranslationService: String, CaseIterable, Identifiable, StringCodable { case libretranslate case deepl case nokyctranslate + case winetranslate var model: Model { switch self { @@ -43,6 +44,8 @@ enum TranslationService: String, CaseIterable, Identifiable, StringCodable { return .init(tag: self.rawValue, displayName: NSLocalizedString("DeepL (Proprietary, Higher Accuracy)", comment: "Dropdown option for selecting DeepL as the translation service.")) case .nokyctranslate: return .init(tag: self.rawValue, displayName: NSLocalizedString("NoKYCTranslate.com (Prepay with BTC)", comment: "Dropdown option for selecting NoKYCTranslate.com as the translation service.")) + case .winetranslate: + return .init(tag: self.rawValue, displayName: NSLocalizedString("translate.nostr.wine (DeepL, Pay with BTC)", comment: "Dropdown option for selecting translate.nostr.wine as the translation service.")) } } } diff --git a/damus/Models/UserSettingsStore.swift b/damus/Models/UserSettingsStore.swift @@ -244,6 +244,15 @@ class UserSettingsStore: ObservableObject { internal_nokyctranslate_api_key = newValue == "" ? nil : newValue } } + + var winetranslate_api_key: String { + get { + return internal_winetranslate_api_key ?? "" + } + set { + internal_winetranslate_api_key = newValue == "" ? nil : newValue + } + } // These internal keys are necessary because entries in the keychain need to be Optional, // but the translation view needs non-Optional String in order to use them as Bindings. @@ -252,6 +261,9 @@ class UserSettingsStore: ObservableObject { @KeychainStorage(account: "nokyctranslate_apikey") var internal_nokyctranslate_api_key: String? + + @KeychainStorage(account: "winetranslate_apikey") + var internal_winetranslate_api_key: String? @KeychainStorage(account: "libretranslate_apikey") var internal_libretranslate_api_key: String? @@ -269,6 +281,8 @@ class UserSettingsStore: ObservableObject { return internal_deepl_api_key != nil case .nokyctranslate: return internal_nokyctranslate_api_key != nil + case .winetranslate: + return internal_winetranslate_api_key != nil } } } diff --git a/damus/Util/Translator.swift b/damus/Util/Translator.swift @@ -26,6 +26,8 @@ public struct Translator { return try await translateWithLibreTranslate(text, from: sourceLanguage, to: targetLanguage) case .nokyctranslate: return try await translateWithNoKYCTranslate(text, from: sourceLanguage, to: targetLanguage) + case .winetranslate: + return try await translateWithWineTranslate(text, from: sourceLanguage, to: targetLanguage) case .deepl: return try await translateWithDeepL(text, from: sourceLanguage, to: targetLanguage) case .none: @@ -111,6 +113,29 @@ public struct Translator { return response.translatedText } + private func translateWithWineTranslate(_ text: String, from sourceLanguage: String, to targetLanguage: String) async throws -> String? { + let url = try makeURL("https://translate.nostr.wine", path: "/translate") + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + struct RequestBody: Encodable { + let q: String + let source: String + let target: String + let api_key: String? + } + let body = RequestBody(q: text, source: sourceLanguage, target: targetLanguage, api_key: userSettingsStore.winetranslate_api_key) + request.httpBody = try encoder.encode(body) + + struct Response: Decodable { + let translatedText: String + } + let response: Response = try await decodedData(for: request) + return response.translatedText + } + private func makeURL(_ baseUrl: String, path: String) throws -> URL { guard var components = URLComponents(string: baseUrl) else { throw URLError(.badURL) diff --git a/damus/Views/Settings/TranslationSettingsView.swift b/damus/Views/Settings/TranslationSettingsView.swift @@ -73,6 +73,17 @@ struct TranslationSettingsView: View { Link(NSLocalizedString("Get API Key with BTC/Lightning", comment: "Button to navigate to nokyctranslate website to get a translation API key."), destination: URL(string: "https://nokyctranslate.com")!) } } + + if settings.translation_service == .winetranslate { + SecureField(NSLocalizedString("API Key (required)", comment: "Prompt for required entry of API Key to use translation server."), text: $settings.winetranslate_api_key) + .disableAutocorrection(true) + .disabled(settings.translation_service != .winetranslate) + .autocapitalization(UITextAutocapitalizationType.none) + + if settings.winetranslate_api_key == "" { + Link(NSLocalizedString("Get API Key with BTC/Lightning", comment: "Button to navigate to translate.nostr.wine to get a translation API key."), destination: URL(string: "https://translate.nostr.wine")!) + } + } if settings.translation_service != .none { Toggle(NSLocalizedString("Automatically translate notes", comment: "Toggle to automatically translate notes."), isOn: $settings.auto_translate)