Translations for Akkoma (#934)

* Translations for Akkoma

* simplify akkoma translation code

---------

Co-authored-by: sk <sk22@mailbox.org>
This commit is contained in:
Jacoco
2023-11-15 14:32:56 +01:00
committed by GitHub
parent cde332684e
commit 786ce78b08
6 changed files with 76 additions and 25 deletions

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.AkkomaTranslation;
public class AkkomaTranslateStatus extends MastodonAPIRequest<AkkomaTranslation>{
public AkkomaTranslateStatus(String id, String lang){
super(HttpMethod.GET, "/statuses/"+id+"/translations/"+lang.toUpperCase(), AkkomaTranslation.class);
}
}

View File

@@ -19,12 +19,15 @@ import android.widget.Toolbar;
import org.joinmastodon.android.E; import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships; import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.polls.SubmitPollVote; import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
import org.joinmastodon.android.api.requests.statuses.AkkomaTranslateStatus;
import org.joinmastodon.android.api.requests.statuses.TranslateStatus; import org.joinmastodon.android.api.requests.statuses.TranslateStatus;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.PollUpdatedEvent; import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AkkomaTranslation;
import org.joinmastodon.android.model.DisplayItemsParent; import org.joinmastodon.android.model.DisplayItemsParent;
import org.joinmastodon.android.model.Poll; import org.joinmastodon.android.model.Poll;
import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.model.Relationship;
@@ -60,6 +63,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@@ -855,38 +859,52 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
status.translationState=Status.TranslationState.SHOWN; status.translationState=Status.TranslationState.SHOWN;
}else{ }else{
status.translationState=Status.TranslationState.LOADING; status.translationState=Status.TranslationState.LOADING;
new TranslateStatus(status.getContentStatus().id, Locale.getDefault().getLanguage()) Consumer<Translation> successCallback=(result)->{
.setCallback(new Callback<>(){ status.translation=result;
status.translationState=Status.TranslationState.SHOWN;
updateTranslation(itemID);
};
MastodonAPIRequest<?> req=isInstanceAkkoma()
? new AkkomaTranslateStatus(status.getContentStatus().id, Locale.getDefault().getLanguage()).setCallback(new Callback<>(){
@Override
public void onSuccess(AkkomaTranslation result){
if(getActivity()!=null) successCallback.accept(result.toTranslation());
}
@Override
public void onError(ErrorResponse error){
if(getActivity()!=null) translationCallbackError(status, itemID);
}
})
: new TranslateStatus(status.getContentStatus().id, Locale.getDefault().getLanguage()).setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Translation result){ public void onSuccess(Translation result){
if(getActivity()==null) if(getActivity()!=null) successCallback.accept(result);
return;
status.translation=result;
status.translationState=Status.TranslationState.SHOWN;
updateTranslation(itemID);
} }
@Override @Override
public void onError(ErrorResponse error){ public void onError(ErrorResponse error){
if(getActivity()==null) if(getActivity()!=null) translationCallbackError(status, itemID);
return;
status.translationState=Status.TranslationState.HIDDEN;
updateTranslation(itemID);
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.translation_failed)
.setPositiveButton(R.string.ok, null)
.show();
} }
}) });
.setTimeout(60000) // 1 minute
.exec(accountID); // 1 minute
req.setTimeout(60000).exec(accountID);
} }
} }
} }
updateTranslation(itemID); updateTranslation(itemID);
} }
private void translationCallbackError(Status status, String itemID) {
status.translationState=Status.TranslationState.HIDDEN;
updateTranslation(itemID);
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.translation_failed)
.setPositiveButton(R.string.ok, null)
.show();
}
private void updateTranslation(String itemID) { private void updateTranslation(String itemID) {
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class); TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
if(text!=null){ if(text!=null){
@@ -896,6 +914,9 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
notifyItemChanged(itemID, TextStatusDisplayItem.class); notifyItemChanged(itemID, TextStatusDisplayItem.class);
} }
if(isInstanceAkkoma())
return;
SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class); SpoilerStatusDisplayItem.Holder spoiler=findHolderOfType(itemID, SpoilerStatusDisplayItem.Holder.class);
if(spoiler!=null){ if(spoiler!=null){
spoiler.rebind(); spoiler.rebind();

View File

@@ -0,0 +1,14 @@
package org.joinmastodon.android.model;
public class AkkomaTranslation extends BaseModel{
public String text;
public String detectedLanguage;
public Translation toTranslation() {
Translation translation=new Translation();
translation.content=text;
translation.detectedSourceLanguage=detectedLanguage;
translation.provider="Akkoma";
return translation;
}
}

View File

@@ -161,11 +161,15 @@ public class Instance extends BaseModel{
case BUBBLE_TIMELINE -> pleromaFeatures case BUBBLE_TIMELINE -> pleromaFeatures
.map(f -> f.contains("bubble_timeline")) .map(f -> f.contains("bubble_timeline"))
.orElse(false); .orElse(false);
case MACHINE_TRANSLATION -> pleromaFeatures
.map(f -> f.contains("akkoma:machine_translation"))
.orElse(false);
}; };
} }
public enum Feature { public enum Feature {
BUBBLE_TIMELINE BUBBLE_TIMELINE,
MACHINE_TRANSLATION
} }
@Parcel @Parcel

View File

@@ -220,10 +220,11 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
public static final Pattern BOTTOM_TEXT_PATTERN = Pattern.compile("(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️)(?:\uD83D\uDC49\uD83D\uDC48(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️))*\uD83D\uDC49\uD83D\uDC48"); public static final Pattern BOTTOM_TEXT_PATTERN = Pattern.compile("(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️)(?:\uD83D\uDC49\uD83D\uDC48(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️))*\uD83D\uDC49\uD83D\uDC48");
public boolean isEligibleForTranslation(AccountSession session){ public boolean isEligibleForTranslation(AccountSession session){
Instance instanceInfo = AccountSessionManager.getInstance().getInstanceInfo(session.domain); Instance instanceInfo=AccountSessionManager.getInstance().getInstanceInfo(session.domain);
boolean translateEnabled = instanceInfo != null && boolean translateEnabled=instanceInfo!=null && (
instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null && (instanceInfo.v2!=null && instanceInfo.v2.configuration.translation!=null && instanceInfo.v2.configuration.translation.enabled) ||
instanceInfo.v2.configuration.translation.enabled; (instanceInfo.isAkkoma() && instanceInfo.hasFeature(Instance.Feature.MACHINE_TRANSLATION))
);
try { try {
Pair<String, List<String>> decoded=BOTTOM_TEXT_PATTERN.matcher(getStrippedText()).find() Pair<String, List<String>> decoded=BOTTOM_TEXT_PATTERN.matcher(getStrippedText()).find()

View File

@@ -191,7 +191,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
public void updateTranslation(boolean updateText){ public void updateTranslation(boolean updateText){
if(item.status==null) if(item.status==null)
return; return;
boolean translateEnabled=!item.disableTranslate && item.status.isEligibleForTranslation(item.parentFragment.getSession()); boolean translateEnabled=!item.disableTranslate && item.status.isEligibleForTranslation(item.parentFragment.getSession()) && !item.isForQuote;
if(translationFooter==null && translateEnabled){ if(translationFooter==null && translateEnabled){
translationFooter=translationFooterStub.inflate(); translationFooter=translationFooterStub.inflate();
translationInfo=findViewById(R.id.translation_info_text); translationInfo=findViewById(R.id.translation_info_text);