diff --git a/WorterBuch/TranslationService.swift b/WorterBuch/TranslationService.swift new file mode 100644 index 0000000..8fe1d0c --- /dev/null +++ b/WorterBuch/TranslationService.swift @@ -0,0 +1,34 @@ +// +// TranslationService.swift +// WorterBuch +// +// Created by Claude on 07.12.2025. +// + +import Foundation +import Translation + +@available(iOS 18.0, *) +class TranslationService { + static func translate(text: String, from sourceLanguage: String = "de", to targetLanguage: String = "en") async -> String? { + do { + let sourceLocale = Locale.Language(identifier: sourceLanguage) + let targetLocale = Locale.Language(identifier: targetLanguage) + + print("Attempting translation from \(sourceLanguage) to \(targetLanguage)") + + // Create session - requires language pack to be installed + let session = TranslationSession(installedSource: sourceLocale, target: targetLocale) + + let response = try await session.translate(text) + return response.targetText + } catch { + print("Translation error: \(error)") + print("To enable translation:") + print("1. Open the Translate app on your iPad") + print("2. Download German language pack") + print("3. Try the translate button again") + return nil + } + } +} diff --git a/WorterBuch/VocabularyFieldCell.swift b/WorterBuch/VocabularyFieldCell.swift index dac81ab..93649ae 100644 --- a/WorterBuch/VocabularyFieldCell.swift +++ b/WorterBuch/VocabularyFieldCell.swift @@ -12,6 +12,8 @@ struct VocabularyFieldCell: View { let drawing: PKDrawing let text: String let onTap: () -> Void + var showTranslateButton: Bool = false + var onTranslate: (() -> Void)? = nil var body: some View { VStack(alignment: .leading, spacing: 4) { @@ -41,19 +43,30 @@ struct VocabularyFieldCell: View { } // Transcribed text - selectable but not editable - if !text.isEmpty { - SelectableTextView( - text: text.lowercased(), - font: .preferredFont(forTextStyle: .body), - textColor: .label - ) - .frame(maxWidth: .infinity, alignment: .leading) - .frame(height: 40) - } else { - Text(" ") - .font(.body) + HStack(spacing: 8) { + if !text.isEmpty { + SelectableTextView( + text: text.lowercased(), + font: .preferredFont(forTextStyle: .body), + textColor: .label + ) .frame(maxWidth: .infinity, alignment: .leading) .frame(height: 40) + } else { + Text(" ") + .font(.body) + .frame(maxWidth: .infinity, alignment: .leading) + .frame(height: 40) + } + + if showTranslateButton, let onTranslate = onTranslate { + Button(action: onTranslate) { + Image(systemName: "arrow.right.arrow.left.circle.fill") + .foregroundColor(.blue) + .font(.system(size: 20)) + } + .frame(width: 40, height: 40) + } } } .padding(8) diff --git a/WorterBuch/VocabularyGridView.swift b/WorterBuch/VocabularyGridView.swift index 6db6035..f385d3c 100644 --- a/WorterBuch/VocabularyGridView.swift +++ b/WorterBuch/VocabularyGridView.swift @@ -86,7 +86,8 @@ struct VocabularyGridView: View { entry: entry, onSelectField: { fieldType in openFieldEditor(for: entry, fieldType: fieldType) - } + }, + onTranslate: translateEntry ) .listRowInsets(EdgeInsets(top: 6, leading: 12, bottom: 6, trailing: 12)) .listRowSeparator(.hidden) @@ -211,11 +212,35 @@ struct VocabularyGridView: View { print("Error saving context: \(nsError), \(nsError.userInfo)") } } + + private func translateEntry(_ entry: VocabularyEntry) { + guard let germanText = entry.germanWordText, !germanText.isEmpty else { return } + guard entry.englishTranslationText?.isEmpty ?? true else { return } + + Task { + if #available(iOS 18.0, *) { + if let translation = await TranslationService.translate(text: germanText) { + await MainActor.run { + entry.englishTranslationText = translation + saveContext() + } + } + } else { + print("Translation requires iOS 18.0 or later") + } + } + } } struct VocabularyEntryRow: View { @ObservedObject var entry: VocabularyEntry let onSelectField: (FieldType) -> Void + let onTranslate: (VocabularyEntry) -> Void + + var shouldShowTranslateButton: Bool { + !(entry.germanWordText?.isEmpty ?? true) && + (entry.englishTranslationText?.isEmpty ?? true) + } var body: some View { HStack(spacing: 12) { @@ -239,7 +264,9 @@ struct VocabularyEntryRow: View { VocabularyFieldCell( drawing: entry.englishTranslationPKDrawing, text: entry.englishTranslationText ?? "", - onTap: { onSelectField(.englishTranslation) } + onTap: { onSelectField(.englishTranslation) }, + showTranslateButton: shouldShowTranslateButton, + onTranslate: { onTranslate(entry) } ) .frame(maxWidth: .infinity) }