mirror of https://github.com/M66B/FairEmail.git
DeepL integration
This commit is contained in:
parent
7da2935408
commit
ffd197db8b
|
@ -142,6 +142,8 @@ import org.bouncycastle.operator.OutputEncryptor;
|
|||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
|
||||
import org.bouncycastle.util.Store;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.Node;
|
||||
|
@ -162,6 +164,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
@ -205,6 +209,7 @@ import javax.mail.internet.MimeMultipart;
|
|||
import javax.mail.internet.MimeUtility;
|
||||
import javax.mail.internet.ParseException;
|
||||
import javax.mail.util.ByteArrayDataSource;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import biweekly.Biweekly;
|
||||
import biweekly.ICalendar;
|
||||
|
@ -310,6 +315,8 @@ public class FragmentCompose extends FragmentBase {
|
|||
private static final int REQUEST_SEND = 14;
|
||||
private static final int REQUEST_PERMISSION = 15;
|
||||
|
||||
private static final int DEEPL_TIMEOUT = 20; // seconds
|
||||
|
||||
private static ExecutorService executor = Helper.getBackgroundExecutor(1, "encrypt");
|
||||
|
||||
@Override
|
||||
|
@ -1452,6 +1459,8 @@ public class FragmentCompose extends FragmentBase {
|
|||
state == State.LOADED && hasPermission(Manifest.permission.READ_CONTACTS));
|
||||
menu.findItem(R.id.menu_answer_insert).setEnabled(state == State.LOADED);
|
||||
menu.findItem(R.id.menu_answer_create).setEnabled(state == State.LOADED);
|
||||
menu.findItem(R.id.menu_translate).setEnabled(state == State.LOADED);
|
||||
menu.findItem(R.id.menu_translate).setVisible(etBody.hasSelection() && BuildConfig.DEBUG);
|
||||
menu.findItem(R.id.menu_clear).setEnabled(state == State.LOADED);
|
||||
|
||||
int colorEncrypt = Helper.resolveColor(getContext(), R.attr.colorEncrypt);
|
||||
|
@ -1481,12 +1490,18 @@ public class FragmentCompose extends FragmentBase {
|
|||
boolean save_drafts = prefs.getBoolean("save_drafts", true);
|
||||
boolean send_dialog = prefs.getBoolean("send_dialog", true);
|
||||
boolean image_dialog = prefs.getBoolean("image_dialog", true);
|
||||
String deepl = prefs.getString("deepl", null);
|
||||
|
||||
menu.findItem(R.id.menu_save_drafts).setChecked(save_drafts);
|
||||
menu.findItem(R.id.menu_send_dialog).setChecked(send_dialog);
|
||||
menu.findItem(R.id.menu_image_dialog).setChecked(image_dialog);
|
||||
menu.findItem(R.id.menu_media).setChecked(media);
|
||||
menu.findItem(R.id.menu_compact).setChecked(compact);
|
||||
menu.findItem(R.id.menu_translate_english).setEnabled(deepl != null);
|
||||
menu.findItem(R.id.menu_translate_french).setEnabled(deepl != null);
|
||||
menu.findItem(R.id.menu_translate_german).setEnabled(deepl != null);
|
||||
menu.findItem(R.id.menu_translate_italian).setEnabled(deepl != null);
|
||||
menu.findItem(R.id.menu_translate_spanish).setEnabled(deepl != null);
|
||||
|
||||
if (EntityMessage.PGP_SIGNONLY.equals(encrypt) ||
|
||||
EntityMessage.SMIME_SIGNONLY.equals(encrypt))
|
||||
|
@ -1541,6 +1556,24 @@ public class FragmentCompose extends FragmentBase {
|
|||
} else if (itemId == R.id.menu_answer_create) {
|
||||
onMenuAnswerCreate();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_key) {
|
||||
onMenuTranslateKey();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_english) {
|
||||
onMenuTranslate("EN");
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_french) {
|
||||
onMenuTranslate("FR");
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_german) {
|
||||
onMenuTranslate("DE");
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_italian) {
|
||||
onMenuTranslate("IT");
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_translate_spanish) {
|
||||
onMenuTranslate("ES");
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_clear) {
|
||||
StyleHelper.apply(R.id.menu_clear, getViewLifecycleOwner(), null, etBody);
|
||||
return true;
|
||||
|
@ -1905,6 +1938,87 @@ public class FragmentCompose extends FragmentBase {
|
|||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private void onMenuTranslateKey() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
prefs.edit().putString("deepl", "").apply();
|
||||
}
|
||||
|
||||
private void onMenuTranslate(String target) {
|
||||
int start = etBody.getSelectionStart();
|
||||
int end = etBody.getSelectionEnd();
|
||||
Editable edit = etBody.getText();
|
||||
|
||||
if (start > end) {
|
||||
int tmp = start;
|
||||
start = end;
|
||||
end = tmp;
|
||||
}
|
||||
|
||||
while (start > 0 && edit.charAt(start - 1) != '\n')
|
||||
start--;
|
||||
|
||||
// Expand selection at end
|
||||
while (end > 0 && end < edit.length() && edit.charAt(end - 1) != '\n')
|
||||
end++;
|
||||
|
||||
final int insert = end;
|
||||
|
||||
String text = edit.subSequence(start, end).toString();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putString("target", target);
|
||||
args.putString("text", text);
|
||||
|
||||
new SimpleTask<String>() {
|
||||
@Override
|
||||
protected String onExecute(Context context, Bundle args) throws Throwable {
|
||||
String target = args.getString("target");
|
||||
String text = args.getString("text");
|
||||
String request =
|
||||
"text=" + URLEncoder.encode(text, StandardCharsets.UTF_8.name()) +
|
||||
"&target_lang=" + URLEncoder.encode(target, StandardCharsets.UTF_8.name());
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
String deepl = prefs.getString("deepl", null);
|
||||
|
||||
URL url = new URL("https://api-free.deepl.com/v2/translate?auth_key=" + deepl);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
connection.setReadTimeout(DEEPL_TIMEOUT * 1000);
|
||||
connection.setConnectTimeout(DEEPL_TIMEOUT * 1000);
|
||||
connection.setRequestProperty("User-Agent", WebViewEx.getUserAgent(context));
|
||||
connection.setRequestProperty("Accept", "*/*");
|
||||
connection.setRequestProperty("Content-Length", Integer.toString(request.length()));
|
||||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||
connection.connect();
|
||||
|
||||
try {
|
||||
connection.getOutputStream().write(request.getBytes());
|
||||
String response = Helper.readStream(connection.getInputStream());
|
||||
|
||||
JSONObject jroot = new JSONObject(response);
|
||||
JSONArray jtranslations = jroot.getJSONArray("translations");
|
||||
JSONObject jtranslation = (JSONObject) jtranslations.get(0);
|
||||
return jtranslation.getString("text");
|
||||
} finally {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onExecuted(Bundle args, String translated) {
|
||||
edit.insert(insert, "\n" + translated);
|
||||
etBody.setSelection(insert + 1 + translated.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onException(Bundle args, Throwable ex) {
|
||||
Log.unexpectedError(getParentFragmentManager(), ex);
|
||||
}
|
||||
}.execute(this, args, "compose:translate");
|
||||
}
|
||||
|
||||
private boolean onActionStyle(int action, View anchor) {
|
||||
Log.i("Style action=" + action);
|
||||
return StyleHelper.apply(action, getViewLifecycleOwner(), anchor, etBody);
|
||||
|
|
|
@ -66,6 +66,35 @@
|
|||
android:title="@string/title_create_template"
|
||||
app:showAsAction="never" />
|
||||
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_translate"
|
||||
android:title="@string/title_translate"
|
||||
app:showAsAction="never">
|
||||
<menu>
|
||||
<group>
|
||||
<item
|
||||
android:id="@+id/menu_translate_key"
|
||||
android:title="@string/title_translate_key" />
|
||||
<item
|
||||
android:id="@+id/menu_translate_english"
|
||||
android:title="@string/title_translate_english" />
|
||||
<item
|
||||
android:id="@+id/menu_translate_french"
|
||||
android:title="@string/title_translate_french" />
|
||||
<item
|
||||
android:id="@+id/menu_translate_german"
|
||||
android:title="@string/title_translate_german" />
|
||||
<item
|
||||
android:id="@+id/menu_translate_italian"
|
||||
android:title="@string/title_translate_italian" />
|
||||
<item
|
||||
android:id="@+id/menu_translate_spanish"
|
||||
android:title="@string/title_translate_spanish" />
|
||||
</group>
|
||||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_clear"
|
||||
android:title="@string/title_style_clear"
|
||||
|
|
|
@ -1107,6 +1107,13 @@
|
|||
<string name="title_insert_contact_group">Insert contact group</string>
|
||||
<string name="title_insert_template">Insert template</string>
|
||||
<string name="title_create_template">Create template</string>
|
||||
<string name="title_translate" translatable="false">Translate</string>
|
||||
<string name="title_translate_key" translatable="false">Set key</string>
|
||||
<string name="title_translate_english" translatable="false">English</string>
|
||||
<string name="title_translate_french" translatable="false">French</string>
|
||||
<string name="title_translate_german" translatable="false">German</string>
|
||||
<string name="title_translate_italian" translatable="false">Italian</string>
|
||||
<string name="title_translate_spanish" translatable="false">Spanish</string>
|
||||
<string name="title_edit_plain_text">Edit as plain text</string>
|
||||
<string name="title_edit_formatted_text">Edit as reformatted text</string>
|
||||
<string name="title_select_certificate">Select public key</string>
|
||||
|
|
Loading…
Reference in New Issue