feat: Show translation provider
This commit is contained in:
parent
3b77ed7612
commit
258aea3682
|
@ -183,8 +183,9 @@
|
||||||
"direct": "Only mentioned user can see this post."
|
"direct": "Only mentioned user can see this post."
|
||||||
},
|
},
|
||||||
"translation": {
|
"translation": {
|
||||||
"translated_from": "Translated from %s",
|
"translated_from": "Translated from %s using %s",
|
||||||
"unknown_language": "Unknown",
|
"unknown_language": "Unknown",
|
||||||
|
"unknown_provider": "Unknown",
|
||||||
"show_original": "Shown Original"
|
"show_original": "Shown Original"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -39,7 +39,7 @@ extension DataSourceFacade {
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension DataSourceFacade {
|
private extension DataSourceFacade {
|
||||||
static func translateStatus(provider: Provider, status: Status) async throws -> String? {
|
static func translateStatus(provider: Provider, status: Status) async throws -> Status.TranslatedContent? {
|
||||||
do {
|
do {
|
||||||
let value = try await provider.context
|
let value = try await provider.context
|
||||||
.apiService
|
.apiService
|
||||||
|
@ -52,7 +52,7 @@ private extension DataSourceFacade {
|
||||||
throw TranslationFailure.emptyOrInvalidResponse
|
throw TranslationFailure.emptyOrInvalidResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
return content
|
return Status.TranslatedContent(content: content, provider: value.provider)
|
||||||
} catch {
|
} catch {
|
||||||
throw TranslationFailure.emptyOrInvalidResponse
|
throw TranslationFailure.emptyOrInvalidResponse
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21509" systemVersion="21G217" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="22C65" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||||
<entity name="Application" representedClassName="CoreDataStack.Application" syncable="YES">
|
<entity name="Application" representedClassName="CoreDataStack.Application" syncable="YES">
|
||||||
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
|
||||||
<attribute name="name" attributeType="String"/>
|
<attribute name="name" attributeType="String"/>
|
||||||
|
@ -218,7 +218,7 @@
|
||||||
<attribute name="sensitive" attributeType="Boolean" usesScalarValueType="YES"/>
|
<attribute name="sensitive" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||||
<attribute name="spoilerText" optional="YES" attributeType="String"/>
|
<attribute name="spoilerText" optional="YES" attributeType="String"/>
|
||||||
<attribute name="text" optional="YES" attributeType="String"/>
|
<attribute name="text" optional="YES" attributeType="String"/>
|
||||||
<attribute name="translatedContent" optional="YES" transient="YES" attributeType="String"/>
|
<attribute name="translatedContent" optional="YES" transient="YES" attributeType="Transformable"/>
|
||||||
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
|
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
|
||||||
<attribute name="uri" attributeType="String"/>
|
<attribute name="uri" attributeType="String"/>
|
||||||
<attribute name="url" optional="YES" attributeType="String"/>
|
<attribute name="url" optional="YES" attributeType="String"/>
|
||||||
|
|
|
@ -11,6 +11,16 @@ import Foundation
|
||||||
public final class Status: NSManagedObject {
|
public final class Status: NSManagedObject {
|
||||||
public typealias ID = String
|
public typealias ID = String
|
||||||
|
|
||||||
|
public class TranslatedContent: NSObject {
|
||||||
|
public let content: String
|
||||||
|
public let provider: String?
|
||||||
|
|
||||||
|
public init(content: String, provider: String?) {
|
||||||
|
self.content = content
|
||||||
|
self.provider = provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// sourcery: autoGenerateProperty
|
// sourcery: autoGenerateProperty
|
||||||
@NSManaged public private(set) var identifier: ID
|
@NSManaged public private(set) var identifier: ID
|
||||||
// sourcery: autoGenerateProperty
|
// sourcery: autoGenerateProperty
|
||||||
|
@ -103,7 +113,7 @@ public final class Status: NSManagedObject {
|
||||||
@NSManaged public private(set) var revealedAt: Date?
|
@NSManaged public private(set) var revealedAt: Date?
|
||||||
|
|
||||||
// sourcery: autoUpdatableObject
|
// sourcery: autoUpdatableObject
|
||||||
@NSManaged public private(set) var translatedContent: String?
|
@NSManaged public private(set) var translatedContent: TranslatedContent?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Status {
|
extension Status {
|
||||||
|
@ -504,7 +514,7 @@ extension Status: AutoUpdatableObject {
|
||||||
self.revealedAt = revealedAt
|
self.revealedAt = revealedAt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public func update(translatedContent: String?) {
|
public func update(translatedContent: TranslatedContent?) {
|
||||||
if self.translatedContent != translatedContent {
|
if self.translatedContent != translatedContent {
|
||||||
self.translatedContent = translatedContent
|
self.translatedContent = translatedContent
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,12 +381,14 @@ public enum L10n {
|
||||||
public enum Translation {
|
public enum Translation {
|
||||||
/// Show Original
|
/// Show Original
|
||||||
public static let showOriginal = L10n.tr("Localizable", "Common.Controls.Status.Translation.ShowOriginal", fallback: "Show Original")
|
public static let showOriginal = L10n.tr("Localizable", "Common.Controls.Status.Translation.ShowOriginal", fallback: "Show Original")
|
||||||
/// Translated from %@
|
/// Translated from %@ using %@
|
||||||
public static func translatedFrom(_ p1: Any) -> String {
|
public static func translatedFrom(_ p1: Any, _ p2: Any) -> String {
|
||||||
return L10n.tr("Localizable", "Common.Controls.Status.Translation.TranslatedFrom", String(describing: p1), fallback: "Translated from %@")
|
return L10n.tr("Localizable", "Common.Controls.Status.Translation.TranslatedFrom", String(describing: p1), String(describing: p2), fallback: "Translated from %@ using %@")
|
||||||
}
|
}
|
||||||
/// Unknown
|
/// Unknown
|
||||||
public static let unknownLanguage = L10n.tr("Localizable", "Common.Controls.Status.Translation.UnknownLanguage", fallback: "Unknown")
|
public static let unknownLanguage = L10n.tr("Localizable", "Common.Controls.Status.Translation.UnknownLanguage", fallback: "Unknown")
|
||||||
|
/// Unknown
|
||||||
|
public static let unknownProvider = L10n.tr("Localizable", "Common.Controls.Status.Translation.UnknownProvider", fallback: "Unknown")
|
||||||
}
|
}
|
||||||
public enum Visibility {
|
public enum Visibility {
|
||||||
/// Only mentioned user can see this post.
|
/// Only mentioned user can see this post.
|
||||||
|
|
|
@ -134,8 +134,9 @@ Please check your internet connection.";
|
||||||
"Common.Controls.Status.Tag.Url" = "URL";
|
"Common.Controls.Status.Tag.Url" = "URL";
|
||||||
"Common.Controls.Status.TapToReveal" = "Tap to reveal";
|
"Common.Controls.Status.TapToReveal" = "Tap to reveal";
|
||||||
"Common.Controls.Status.Translation.ShowOriginal" = "Show Original";
|
"Common.Controls.Status.Translation.ShowOriginal" = "Show Original";
|
||||||
"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@";
|
"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@";
|
||||||
"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown";
|
"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown";
|
||||||
|
"Common.Controls.Status.Translation.UnknownProvider" = "Unknown";
|
||||||
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
||||||
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
||||||
"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post.";
|
"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post.";
|
||||||
|
|
|
@ -62,8 +62,9 @@ Please check your internet connection.";
|
||||||
"Common.Controls.Actions.SignUp" = "Create account";
|
"Common.Controls.Actions.SignUp" = "Create account";
|
||||||
"Common.Controls.Actions.Skip" = "Skip";
|
"Common.Controls.Actions.Skip" = "Skip";
|
||||||
"Common.Controls.Actions.TakePhoto" = "Take Photo";
|
"Common.Controls.Actions.TakePhoto" = "Take Photo";
|
||||||
"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@";
|
"Common.Controls.Actions.TranslatePost.Title" = "Translate from %@ using %@";
|
||||||
"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown";
|
"Common.Controls.Actions.TranslatePost.UnknownLanguage" = "Unknown";
|
||||||
|
"Common.Controls.Actions.TranslatePost.UnknownProvider" = "Unknown";
|
||||||
"Common.Controls.Actions.TryAgain" = "Try Again";
|
"Common.Controls.Actions.TryAgain" = "Try Again";
|
||||||
"Common.Controls.Actions.UnblockDomain" = "Unblock %@";
|
"Common.Controls.Actions.UnblockDomain" = "Unblock %@";
|
||||||
"Common.Controls.Friendship.Block" = "Block";
|
"Common.Controls.Friendship.Block" = "Block";
|
||||||
|
@ -130,8 +131,9 @@ Please check your internet connection.";
|
||||||
"Common.Controls.Status.Tag.Url" = "URL";
|
"Common.Controls.Status.Tag.Url" = "URL";
|
||||||
"Common.Controls.Status.TapToReveal" = "Tap to reveal";
|
"Common.Controls.Status.TapToReveal" = "Tap to reveal";
|
||||||
"Common.Controls.Status.Translation.ShowOriginal" = "Show Original";
|
"Common.Controls.Status.Translation.ShowOriginal" = "Show Original";
|
||||||
"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@";
|
"Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@";
|
||||||
"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown";
|
"Common.Controls.Status.Translation.UnknownLanguage" = "Unknown";
|
||||||
|
"Common.Controls.Status.Translation.UnknownProvider" = "Unknown";
|
||||||
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
"Common.Controls.Status.UserReblogged" = "%@ reblogged";
|
||||||
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
"Common.Controls.Status.UserRepliedTo" = "Replied to %@";
|
||||||
"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post.";
|
"Common.Controls.Status.Visibility.Direct" = "Only mentioned user can see this post.";
|
||||||
|
|
|
@ -246,13 +246,14 @@ extension StatusView {
|
||||||
func revertTranslation() {
|
func revertTranslation() {
|
||||||
guard let originalStatus = viewModel.originalStatus else { return }
|
guard let originalStatus = viewModel.originalStatus else { return }
|
||||||
viewModel.translatedFromLanguage = nil
|
viewModel.translatedFromLanguage = nil
|
||||||
|
viewModel.translatedUsingProvider = nil
|
||||||
originalStatus.reblog?.update(translatedContent: nil)
|
originalStatus.reblog?.update(translatedContent: nil)
|
||||||
originalStatus.update(translatedContent: nil)
|
originalStatus.update(translatedContent: nil)
|
||||||
configure(status: originalStatus)
|
configure(status: originalStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureTranslated(status: Status) {
|
func configureTranslated(status: Status) {
|
||||||
let translatedContent: String? = {
|
let translatedContent: Status.TranslatedContent? = {
|
||||||
if let translatedContent = status.reblog?.translatedContent {
|
if let translatedContent = status.reblog?.translatedContent {
|
||||||
return translatedContent
|
return translatedContent
|
||||||
}
|
}
|
||||||
|
@ -269,10 +270,11 @@ extension StatusView {
|
||||||
|
|
||||||
// content
|
// content
|
||||||
do {
|
do {
|
||||||
let content = MastodonContent(content: translatedContent, emojis: status.emojis.asDictionary)
|
let content = MastodonContent(content: translatedContent.content, emojis: status.emojis.asDictionary)
|
||||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||||
viewModel.content = metaContent
|
viewModel.content = metaContent
|
||||||
viewModel.translatedFromLanguage = status.reblog?.language ?? status.language
|
viewModel.translatedFromLanguage = status.reblog?.language ?? status.language
|
||||||
|
viewModel.translatedUsingProvider = status.reblog?.translatedContent?.provider ?? status.translatedContent?.provider
|
||||||
viewModel.isCurrentlyTranslating = false
|
viewModel.isCurrentlyTranslating = false
|
||||||
} catch {
|
} catch {
|
||||||
assertionFailure(error.localizedDescription)
|
assertionFailure(error.localizedDescription)
|
||||||
|
|
|
@ -49,6 +49,7 @@ extension StatusView {
|
||||||
// Translation
|
// Translation
|
||||||
@Published public var isCurrentlyTranslating = false
|
@Published public var isCurrentlyTranslating = false
|
||||||
@Published public var translatedFromLanguage: String?
|
@Published public var translatedFromLanguage: String?
|
||||||
|
@Published public var translatedUsingProvider: String?
|
||||||
|
|
||||||
@Published public var timestamp: Date?
|
@Published public var timestamp: Date?
|
||||||
public var timestampFormatter: ((_ date: Date) -> String)?
|
public var timestampFormatter: ((_ date: Date) -> String)?
|
||||||
|
@ -145,6 +146,7 @@ extension StatusView {
|
||||||
isMediaSensitive = false
|
isMediaSensitive = false
|
||||||
isSensitiveToggled = false
|
isSensitiveToggled = false
|
||||||
translatedFromLanguage = nil
|
translatedFromLanguage = nil
|
||||||
|
translatedUsingProvider = nil
|
||||||
isCurrentlyTranslating = false
|
isCurrentlyTranslating = false
|
||||||
|
|
||||||
activeFilters = []
|
activeFilters = []
|
||||||
|
@ -629,7 +631,9 @@ extension StatusView.ViewModel {
|
||||||
guard
|
guard
|
||||||
let context = self.context,
|
let context = self.context,
|
||||||
let authContext = self.authContext
|
let authContext = self.authContext
|
||||||
else { return nil }
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil
|
var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil
|
||||||
context.managedObjectContext.performAndWait {
|
context.managedObjectContext.performAndWait {
|
||||||
|
|
|
@ -191,6 +191,7 @@ public final class StatusView: UIView {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular))
|
label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular))
|
||||||
label.textColor = Asset.Colors.Label.secondary.color
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
|
label.numberOfLines = 2
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
lazy var translatedInfoView: UIView = {
|
lazy var translatedInfoView: UIView = {
|
||||||
|
@ -212,10 +213,14 @@ public final class StatusView: UIView {
|
||||||
containerView.addSubview($0)
|
containerView.addSubview($0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
translatedInfoLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
|
||||||
|
revertButton.setContentHuggingPriority(.required, for: .horizontal)
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
containerView.heightAnchor.constraint(equalToConstant: 24),
|
containerView.heightAnchor.constraint(equalToConstant: 24),
|
||||||
translatedInfoLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
|
translatedInfoLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
|
||||||
translatedInfoLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
|
translatedInfoLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
|
||||||
|
translatedInfoLabel.trailingAnchor.constraint(equalTo: revertButton.leadingAnchor, constant: -16),
|
||||||
revertButton.topAnchor.constraint(equalTo: containerView.topAnchor),
|
revertButton.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||||
revertButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16),
|
revertButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16),
|
||||||
revertButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
revertButton.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
|
||||||
|
@ -735,12 +740,18 @@ extension StatusView {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
viewModel.$translatedFromLanguage
|
Publishers.CombineLatest(
|
||||||
|
viewModel.$translatedFromLanguage,
|
||||||
|
viewModel.$translatedUsingProvider
|
||||||
|
)
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] translatedFromLanguage in
|
.sink { [weak self] translatedFromLanguage, translatedUsingProvider in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
if let translatedFromLanguage = translatedFromLanguage {
|
if let translatedFromLanguage = translatedFromLanguage {
|
||||||
self.translatedInfoLabel.text = L10n.Common.Controls.Status.Translation.translatedFrom(Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? L10n.Common.Controls.Status.Translation.unknownLanguage)
|
self.translatedInfoLabel.text = L10n.Common.Controls.Status.Translation.translatedFrom(
|
||||||
|
Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? L10n.Common.Controls.Status.Translation.unknownLanguage,
|
||||||
|
translatedUsingProvider ?? L10n.Common.Controls.Status.Translation.unknownProvider
|
||||||
|
)
|
||||||
self.translatedInfoView.isHidden = false
|
self.translatedInfoView.isHidden = false
|
||||||
} else {
|
} else {
|
||||||
self.translatedInfoView.isHidden = true
|
self.translatedInfoView.isHidden = true
|
||||||
|
|
Loading…
Reference in New Issue