diff --git a/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java b/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java index 5fdd7255..6292da43 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java +++ b/app/src/main/java/app/fedilab/android/mastodon/activities/CheckHomeCacheActivity.java @@ -202,7 +202,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity { IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() { @Override public String getFormattedValue(float value) { - if (value < xVals.size()) { + if (value >= 0 && value < xVals.size()) { return xVals.get((int) value); } else return ""; @@ -363,7 +363,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity { IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() { @Override public String getFormattedValue(float value) { - if (value < xVals2.size()) { + if (value >= 0 && value < xVals2.size()) { return xVals2.get((int) value); } else return ""; diff --git a/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java b/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java index 1ec9f71a..3c43dc9b 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java +++ b/app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java @@ -15,6 +15,7 @@ package app.fedilab.android.mastodon.client.endpoints; * see . */ import java.util.Date; +import java.util.LinkedHashMap; import java.util.List; import app.fedilab.android.mastodon.client.entities.api.Account; @@ -25,14 +26,17 @@ import app.fedilab.android.mastodon.client.entities.api.Poll; import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus; import app.fedilab.android.mastodon.client.entities.api.Status; import app.fedilab.android.mastodon.client.entities.api.StatusSource; +import app.fedilab.android.mastodon.client.entities.api.params.StatusParams; import okhttp3.MultipartBody; import okhttp3.RequestBody; import retrofit2.Call; +import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.Field; import retrofit2.http.FormUrlEncoded; import retrofit2.http.GET; import retrofit2.http.Header; +import retrofit2.http.Headers; import retrofit2.http.Multipart; import retrofit2.http.POST; import retrofit2.http.PUT; @@ -74,6 +78,16 @@ public interface MastodonStatusesService { @Header("Authorization") String token, @Path("id") String id); + + @Headers({"Accept: application/json"}) + @PUT("statuses/{id}") + Call updateStatus( + @Header("Idempotency-Key") String idempotency_Key, + @Header("Authorization") String token, + @Path("id") String id, + @Body StatusParams statusParams + ); + //Post a status @FormUrlEncoded @PUT("statuses/{id}") @@ -92,9 +106,9 @@ public interface MastodonStatusesService { @Field("spoiler_text") String spoiler_text, @Field("visibility") String visibility, @Field("language") String language, - @Field("media_attributes[][id]") List media_id, - @Field("media_attributes[][description]") List media_description, - @Field("media_attributes[][focus]") List focus + @Field("media_attributes[]") LinkedHashMap media_id, + @Field("media_attributes[]") LinkedHashMap media_description, + @Field("media_attributes[]") LinkedHashMap focus ); //Post a scheduled status diff --git a/app/src/main/java/app/fedilab/android/mastodon/client/entities/api/params/StatusParams.java b/app/src/main/java/app/fedilab/android/mastodon/client/entities/api/params/StatusParams.java new file mode 100644 index 00000000..5057f0e2 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/mastodon/client/entities/api/params/StatusParams.java @@ -0,0 +1,65 @@ +package app.fedilab.android.mastodon.client.entities.api.params; +/* Copyright 2025 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + + +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +public class StatusParams implements Serializable { + @SerializedName("id") + public String id; + @SerializedName("status") + public String status; + @SerializedName("media_ids") + public List media_ids; + @SerializedName("poll") + public PollParams pollParams; + @SerializedName("in_reply_to_id") + public String in_reply_to_id; + @SerializedName("sensitive") + public Boolean sensitive; + @SerializedName("spoiler_text") + public String spoiler_text; + @SerializedName("visibility") + public String visibility; + @SerializedName("language") + public String language; + @SerializedName("media_attributes") + public List media_attributes; + + public static class PollParams implements Serializable{ + @SerializedName("options") + public List poll_options; + @SerializedName("expires_in") + public Integer poll_expire_in; + @SerializedName("multiple") + public Boolean poll_multiple; + @SerializedName("hide_totals") + public Boolean poll_hide_totals; + + } + + public static class MediaParams implements Serializable { + @SerializedName("id") + public String id; + @SerializedName("description") + public String description; + @SerializedName("focus") + public String focus; + } +} diff --git a/app/src/main/java/app/fedilab/android/mastodon/helper/CustomEmoji.java b/app/src/main/java/app/fedilab/android/mastodon/helper/CustomEmoji.java index 707bb309..69e02ad7 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/helper/CustomEmoji.java +++ b/app/src/main/java/app/fedilab/android/mastodon/helper/CustomEmoji.java @@ -106,7 +106,9 @@ public class CustomEmoji extends ReplacementSpan { if (drawableCallBack != null) { drawableCallBack.invalidateDrawable(drawable); } - view.invalidate(); + if(view != null) { + view.invalidate(); + } } @Override diff --git a/app/src/main/java/app/fedilab/android/mastodon/helper/TranslateHelper.java b/app/src/main/java/app/fedilab/android/mastodon/helper/TranslateHelper.java index 7f91a364..7b0e9584 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/helper/TranslateHelper.java +++ b/app/src/main/java/app/fedilab/android/mastodon/helper/TranslateHelper.java @@ -72,8 +72,15 @@ public class TranslateHelper { String translatorVersion = sharedpreferences.getString(context.getString(R.string.SET_TRANSLATOR_VERSION), "PRO"); params.setPro(translatorVersion.equals("PRO")); String apikey = sharedpreferences.getString(context.getString(R.string.SET_TRANSLATOR_API_KEY), null); - if (apikey != null) { + if (apikey != null && !apikey.trim().isEmpty()) { myTransL.setDeeplAPIKey(apikey.trim()); + } else { //Issue with API key (empty or null) + SharedPreferences.Editor editor = sharedpreferences.edit(); + editor.putString(context.getString(R.string.SET_TRANSLATOR), "FEDILAB"); + editor.commit(); + et = MyTransL.translatorEngine.LIBRETRANSLATE; + myTransL.setTranslator(et); + myTransL.setLibretranslateDomain("translate.fedilab.app"); } } diff --git a/app/src/main/java/app/fedilab/android/mastodon/jobs/ComposeWorker.java b/app/src/main/java/app/fedilab/android/mastodon/jobs/ComposeWorker.java index e128c415..34eb74b1 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/jobs/ComposeWorker.java +++ b/app/src/main/java/app/fedilab/android/mastodon/jobs/ComposeWorker.java @@ -47,6 +47,7 @@ import com.google.gson.Gson; import java.io.IOException; import java.net.IDN; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; @@ -59,6 +60,7 @@ import app.fedilab.android.mastodon.client.entities.api.Attachment; import app.fedilab.android.mastodon.client.entities.api.Poll; import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus; import app.fedilab.android.mastodon.client.entities.api.Status; +import app.fedilab.android.mastodon.client.entities.api.params.StatusParams; import app.fedilab.android.mastodon.client.entities.app.Account; import app.fedilab.android.mastodon.client.entities.app.BaseAccount; import app.fedilab.android.mastodon.client.entities.app.CachedBundle; @@ -164,9 +166,8 @@ public class ComposeWorker extends Worker { } dataPost.messageToSend = statuses.size() - startingPosition; dataPost.messageSent = 0; - List media_edit_id = null; - List media_edit_description = null; - List media_edit_focus = null; + List media_attributes = null; + for (int i = startingPosition; i < statuses.size(); i++) { if (dataPost.notificationBuilder != null) { dataPost.notificationBuilder.setProgress(100, dataPost.messageSent * 100 / dataPost.messageToSend, true); @@ -179,15 +180,15 @@ public class ComposeWorker extends Worker { attachmentIds = new ArrayList<>(); for (Attachment attachment : statuses.get(i).media_attachments) { if (attachment.id != null) { - if (media_edit_id == null) { - media_edit_id = new ArrayList<>(); - media_edit_description = new ArrayList<>(); - media_edit_focus = new ArrayList<>(); + if (media_attributes == null) { + media_attributes = new ArrayList<>(); } + StatusParams.MediaParams mediaParams = new StatusParams.MediaParams(); + mediaParams.id = attachment.id; + mediaParams.description = attachment.description; + mediaParams.focus = attachment.focus; attachmentIds.add(attachment.id); - media_edit_id.add(attachment.id); - media_edit_description.add(attachment.description); - media_edit_focus.add(attachment.focus); + media_attributes.add(mediaParams); } else { MultipartBody.Part fileMultipartBody; if (watermark && attachment.mimeType != null && attachment.mimeType.contains("image")) { @@ -207,7 +208,6 @@ public class ComposeWorker extends Worker { attachmentIds.add(replyId); } } - } } List poll_options = null; @@ -274,10 +274,25 @@ public class ComposeWorker extends Worker { statusCall = mastodonStatusesService.createStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive, statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language, statuses.get(i).quote_id, statuses.get(i).content_type); } else { //Status is edited - statusCall = mastodonStatusesService.updateStatus(null, dataPost.token, dataPost.statusEditId, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in, - poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive, - statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language, - media_edit_id, media_edit_description, media_edit_focus); + StatusParams statusParams = new StatusParams(); + statusParams.status = statuses.get(i).text; + statusParams.media_ids = attachmentIds; + if(poll_options != null) { + statusParams.pollParams = new StatusParams.PollParams(); + statusParams.pollParams.poll_options = poll_options; + statusParams.pollParams.poll_expire_in = poll_expire_in; + statusParams.pollParams.poll_multiple = poll_multiple; + statusParams.pollParams.poll_hide_totals = poll_hide_totals; + } + statusParams.in_reply_to_id = statuses.get(i).quote_id == null ? in_reply_to_status : null; + statusParams.sensitive = statuses.get(i).sensitive; + statusParams.spoiler_text = statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null; + statusParams.visibility = statuses.get(i).visibility.toLowerCase(); + statusParams.language = statuses.get(i).language; + statusParams.media_attributes = media_attributes; + statusCall = mastodonStatusesService.updateStatus(null, dataPost.token, + dataPost.statusEditId, + statusParams); } try { Response statusResponse = statusCall.execute(); diff --git a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java index e5040d3e..8f15fa9b 100644 --- a/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -471,7 +471,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } else if (list_id != null) { ident = "@l@" + list_id; } else if (remoteInstance != null && !checkRemotely) { - if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) { + if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null && (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG)) { ident = "@R@" + pinnedTimeline.remoteInstance.host; } else { ident = "@R@" + remoteInstance; diff --git a/mytransl/src/main/java/com/github/stom79/mytransl/MyTransL.java b/mytransl/src/main/java/com/github/stom79/mytransl/MyTransL.java index e2c997ec..549ee181 100644 --- a/mytransl/src/main/java/com/github/stom79/mytransl/MyTransL.java +++ b/mytransl/src/main/java/com/github/stom79/mytransl/MyTransL.java @@ -29,7 +29,7 @@ public class MyTransL { private static MyTransL myTransL; private static String libretranslateDomain; private static String lingvaDomain; - private final translatorEngine te; + private translatorEngine te; private String yandexAPIKey, deeplAPIKey, systranAPIKey, libreTranslateAPIKey, lingvaAPIKey; private int timeout = 30; private boolean obfuscation = false; @@ -38,6 +38,10 @@ public class MyTransL { this.te = te; } + public void setTranslator(translatorEngine te) { + this.te = te; + } + public static synchronized MyTransL getInstance(translatorEngine te) { if (myTransL == null) myTransL = new MyTransL(te); diff --git a/mytransl/src/main/java/com/github/stom79/mytransl/async/TransAsync.java b/mytransl/src/main/java/com/github/stom79/mytransl/async/TransAsync.java index b4f6f2e3..755f4819 100644 --- a/mytransl/src/main/java/com/github/stom79/mytransl/async/TransAsync.java +++ b/mytransl/src/main/java/com/github/stom79/mytransl/async/TransAsync.java @@ -29,6 +29,8 @@ import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; @@ -125,6 +127,7 @@ public class TransAsync { str_response = new Client().get(url, this.timeout); } else if (te == MyTransL.translatorEngine.DEEPL) { String key = MyTransL.getInstance(te).getDeeplAPIKey(); + params.setSplit_sentences(true); url = Helper.getDeeplAbsoluteUrl(contentToSend, toLanguage, params, key); str_response = new Client().get(url, this.timeout); } else if (te == MyTransL.translatorEngine.SYSTRAN) { @@ -149,7 +152,7 @@ public class TransAsync { } else if (te == MyTransL.translatorEngine.LINGVA) { String key = MyTransL.getInstance(te).getLibreTranslateAPIKey(); //String contentToSendEncoded = URLEncoder.encode(contentToSend, "UTF-8"); - String lingvaURL = MyTransL.getLingvaUrl() + this.params.getSource_lang() + "/" + toLanguage + "/" + contentToSend; + String lingvaURL = MyTransL.getLingvaUrl() + this.params.getSource_lang() + "/" + toLanguage + "/" + URLEncoder.encode(contentToSend, "utf-8"); str_response = new Client().get(lingvaURL, this.timeout); } } catch (IOException | NoSuchAlgorithmException | KeyManagementException err) { diff --git a/mytransl/src/main/java/com/github/stom79/mytransl/client/Client.java b/mytransl/src/main/java/com/github/stom79/mytransl/client/Client.java index 26826622..b094883b 100644 --- a/mytransl/src/main/java/com/github/stom79/mytransl/client/Client.java +++ b/mytransl/src/main/java/com/github/stom79/mytransl/client/Client.java @@ -64,18 +64,11 @@ public class Client { httpsURLConnection.setConnectTimeout(timeout * 1000); httpsURLConnection.setRequestProperty("http.keepAlive", "false"); httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); - if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); httpsURLConnection.setRequestMethod("GET"); //Read the reply if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { Reader in; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), StandardCharsets.UTF_8)); - } else { - //noinspection CharsetObjectCanBeUsed - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), "UTF-8")); - } + in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (int c; (c = in.read()) >= 0; ) sb.append((char) c); @@ -84,13 +77,8 @@ public class Client { return sb.toString(); } else { Reader in; - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), StandardCharsets.UTF_8)); - } else { - //noinspection CharsetObjectCanBeUsed - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), "UTF-8")); - } - StringBuilder sb = new StringBuilder();// TODO Auto-generated catch block + in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), StandardCharsets.UTF_8)); + StringBuilder sb = new StringBuilder(); for (int c; (c = in.read()) >= 0; ) sb.append((char) c); httpsURLConnection.disconnect(); @@ -115,19 +103,12 @@ public class Client { URL url = new URL(urlConnection); HttpsURLConnection httpsURLConnection = (HttpsURLConnection) url.openConnection(); byte[] postDataBytes; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - postDataBytes = jsonObject.toString().getBytes(StandardCharsets.UTF_8); - } else { - //noinspection CharsetObjectCanBeUsed - postDataBytes = jsonObject.toString().getBytes("utf-8"); - } + postDataBytes = jsonObject.toString().getBytes(StandardCharsets.UTF_8); httpsURLConnection.setRequestProperty("User-Agent", USER_AGENT); httpsURLConnection.setConnectTimeout(timeout * 1000); httpsURLConnection.setDoInput(true); httpsURLConnection.setDoOutput(true); httpsURLConnection.setUseCaches(false); - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - httpsURLConnection.setSSLSocketFactory(new TLSSocketFactory()); httpsURLConnection.setRequestMethod("POST"); httpsURLConnection.setRequestProperty("Content-Type", "application/json"); httpsURLConnection.setRequestProperty("Accept", "application/json"); @@ -140,12 +121,7 @@ public class Client { //Read the reply if (httpsURLConnection.getResponseCode() >= 200 && httpsURLConnection.getResponseCode() < 400) { Reader in; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), StandardCharsets.UTF_8)); - } else { - //noinspection CharsetObjectCanBeUsed - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), "UTF-8")); - } + in = new BufferedReader(new InputStreamReader(httpsURLConnection.getInputStream(), StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (int c; (c = in.read()) >= 0; ) sb.append((char) c); @@ -154,12 +130,7 @@ public class Client { return sb.toString(); } else { Reader in; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), StandardCharsets.UTF_8)); - } else { - //noinspection CharsetObjectCanBeUsed - in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), "UTF-8")); - } + in = new BufferedReader(new InputStreamReader(httpsURLConnection.getErrorStream(), StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (int c; (c = in.read()) >= 0; ) sb.append((char) c); diff --git a/mytransl/src/main/java/com/github/stom79/mytransl/translate/Translate.java b/mytransl/src/main/java/com/github/stom79/mytransl/translate/Translate.java index 38997b1f..22cd94c8 100644 --- a/mytransl/src/main/java/com/github/stom79/mytransl/translate/Translate.java +++ b/mytransl/src/main/java/com/github/stom79/mytransl/translate/Translate.java @@ -30,6 +30,7 @@ import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; import java.util.Map; @@ -156,11 +157,11 @@ public class Translate { String text = spannableString.toString(); Matcher matcher; - //Mentions with instances (@name@domain) will be replaced by __o0__, __o1__, etc. + //Mentions with instances (@name@domain) will be replaced int i = 0; matcher = mentionOtherInstancePattern.matcher(text); while (matcher.find()) { - String key = "$o" + i; + String key = "§" + i; String value = matcher.group(0); if (value != null) { this.mentionConversion.put(key, value); @@ -170,10 +171,9 @@ public class Translate { } //Extracts Emails matcher = Patterns.EMAIL_ADDRESS.matcher(text); - i = 0; - //replaces them by a kind of variable which shouldn't be translated ie: __e0__, __e1__, etc. + //replaces them by a kind of variable which shouldn't be translated while (matcher.find()) { - String key = "$e" + i; + String key = "§" + i; String value = matcher.group(0); if (value != null) { this.mailConversion.put(key, value); @@ -182,11 +182,10 @@ public class Translate { i++; } - //Same for mentions with __m0__, __m1__, etc. - i = 0; + //Same for mentions w matcher = mentionPattern.matcher(text); while (matcher.find()) { - String key = "$m" + i; + String key = "§" + i; String value = matcher.group(0); if (value != null) { this.mentionConversion.put(key, value); @@ -197,10 +196,9 @@ public class Translate { //Extracts urls matcher = Patterns.WEB_URL.matcher(text); - i = 0; - //replaces them by a kind of variable which shouldn't be translated ie: __u0__, __u1__, etc. + //replaces them by a kind of variable which shouldn't be translated ie: _ while (matcher.find()) { - String key = "$u" + i; + String key = "§" + i; String value = matcher.group(0); int end = matcher.end(); if (spannableString.length() > end && spannableString.charAt(end) == '/') { @@ -213,11 +211,9 @@ public class Translate { } i++; } - i = 0; - //Same for tags with __t0__, __t1__, etc. matcher = hashtagPattern.matcher(text); while (matcher.find()) { - String key = "$t" + i; + String key = "§" + i; String value = matcher.group(0); if (value != null) { this.tagConversion.put(key, value); @@ -348,7 +344,13 @@ public class Translate { try { JSONObject translationJson = new JSONObject(response); //Retrieves the translated content - translate.setTranslatedContent(translationJson.getString("translation")); + String content; + try { + content = URLDecoder.decode(translationJson.getString("translation"), "utf-8"); + } catch (UnsupportedEncodingException e) { + content = translationJson.getString("translation"); + } + translate.setTranslatedContent(content); //Retrieves the initial language translate.setInitialLanguage(initialLanguage); } catch (JSONException e1) {