[JAVA] Translator using Microsoft Translator Text API on Android ~ Implementation ~

Translator using Microsoft Translator Text API on Android ~ Implementation ~

I made an Android app that translates using the MicrosoftTranslatorText API, so I will keep a memorandum of the introduction method. In this article Translate using Microsoft Translator Text API on Android ~ Preparation ~ Using the key obtained in, we will implement the translation function in the Android application with the MicrosofTranslatorText API.

Official documentation

http://docs.microsofttranslator.com/text-translate.html#!/default/get_Translate

1. Get API token

To translate using the MicrosoftTranslatorTextAPI, you need to get an API token first. Create a class that inherits AsyncTask because it communicates.

TranslateAPIGetTokenRequest.java



package <package name>;

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

public class TranslateAPIGetTokenRequest extends AsyncTask<String, Void, String>{
    private static final String KEY = "<API key obtained in preparation>"; //API key
    private static final String LOG_TAG = "GetTokenRequest"; //Log tag
    private static final String HTTP_OK = "HTTP_OK"; //HttpUrlConnection status
    private String mTranslateWord = ""; //Translated text
    private String mApiToken = ""; //API token
    private MainActivity mActivity; //For callback

    //constructor
    public TranslateAPIGetTokenRequest(MainActivity activity,String word){
        mActivity = activity;
        mTranslateWord = word;
    }

    @Override
    protected String doInBackground(String... params) {
        String urlStr = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"; //API token acquisition request URL
        String result = null;
        HttpURLConnection con;
        URL url = null;
        BufferedReader reader = null;
        try{
            url = new URL(urlStr);
        }catch(Exception e){
            e.printStackTrace();
        }

        try {
            con = (HttpsURLConnection) url.openConnection();
            con.setRequestMethod("POST");
            con.addRequestProperty("Content-Type","application/json");
            con.addRequestProperty("Ocp-Apim-Subscription-Key", KEY);

            final int status = con.getResponseCode();
            Log.d(LOG_TAG, "result:" + status);
            if (status == HttpURLConnection.HTTP_OK) {
                result= HTTP_OK;
                StringBuilder stringBuilder = new StringBuilder();
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    stringBuilder.append(inputLine);
                }
                String recvData = stringBuilder.toString();
                mApiToken = recvData;
                Log.d(LOG_TAG, "http post success  recvData: " + recvData);
            } else{
                result = String.valueOf(status);
            }

        }catch(Exception e){
            Log.e(LOG_TAG,e.toString());
        }

        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(LOG_TAG, "onPostExecute, result: " + result);
        //Status is HTTP_If it is OK, start a translation request
        if(result.equals(HTTP_OK)) {
            TranslateAPITranslateRequest trans = new TranslateAPITranslateRequest(mActivity, mTranslateWord, mApiToken);
            trans.execute();
        }else{
            Log.d("GetTokenRequest", "onPostExecute:Error");
        }
    }
}

Code commentary

1. Make the API key a class constant

private static final String KEY = ""; // API key `

2. Hold the callback destination Activity and translated text in the constructor

This is because I want to specify the text to translate when calling from Activity.

    //constructor
    public TranslateAPIGetTokenRequest(MainActivity activity,String word){
        mActivity = activity;
        mTranslateWord = word;
    }
3. Specify the endpoint

The endpoint of API token acquisition is as follows. https://api.cognitive.microsoft.com/sts/v1.0/issueToken

String urlStr = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken"; //API token acquisition request URL
4. Set request parameters

You need to set the API key in the parameter Ocp-Apim-Subscription-Key.

Request method: POST Content-Type:application/json ** Ocp-Apim-Subscription-Key: API key ** (key obtained in preparation)

con.setRequestMethod("POST");
con.addRequestProperty("Content-Type","application/json");
con.addRequestProperty("Ocp-Apim-Subscription-Key", KEY);
5. Hold the API token received in the response as a member variable

If the request is successful, a string of about 700 characters will be returned. That is the API token.

if (status == HttpURLConnection.HTTP_OK) {
                result= HTTP_OK;
                StringBuilder stringBuilder = new StringBuilder();
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    stringBuilder.append(inputLine);
                }
                String recvData = stringBuilder.toString();
                mTranslateToken = recvData;
                Log.d(LOG_TAG, "http post success  recvData: " + recvData);
} else {
               result = String.valueOf(status);
       }
6. When communication is completed (when onPostExecute is called), execute the translation request class.

At this time, specify the API token, callback destination activity, and translated text obtained in 5 in the argument of the constructor.

    @Override
    protected void onPostExecute(String result) {
        Log.d(LOG_TAG, "onPostExecute, result: " + result);
        //Status is HTTP_If it is OK, start a translation request
        if(result.equals(HTTP_OK)) {
            TranslateAPITranslateRequest trans = new TranslateAPITranslateRequest(mActivity, mTranslateWord, mTranslateToken);
            trans.execute();
        }else{
            Log.d("GetTokenRequest", "onPostExecute:Error");
        }
    }

It seems nonsense to call the AsyncTask class in succession like this ...

2. Translation request

Make a translation request using the API token obtained in 1. As with the API token acquisition request, use a class that inherits AsyncTask.

TranslateAPITranslateRequest.java


package <package name>;

import android.os.AsyncTask;
import android.util.Log;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

public class TranslateAPITranslateRequest extends AsyncTask<String, Void, String> {
    private static final String LOG_TAG = "TranslateRequest"; //Log tag
    private static final String HTTP_OK = "HTTP_OK";
    private String mTranslateWord = "";//Untranslated text
    private String mTranslatedWord = ""; //Post-translation text
    private String mApiToken = ""; //API token
    private MainActivity mActivity; //Callback destination Activity

    //constructor
    public TranslateAPITranslateRequest(MainActivity activity,String word,String token){
        Log.d(LOG_TAG,"word:" + word);
        mActivity = activity;
        mTranslateWord = word;
        mApiToken = token;
    }

    @Override
    protected String doInBackground(String... params) {
        Log.d(LOG_TAG,"doInBackground,translateWord:" + mTranslateWord);

        String urlStr = null;
        try {
            urlStr = "http://api.microsofttranslator.com/v2/Http.svc/Translate?from=ja&to=en&text=" + URLEncoder.encode(mTranslateWord, "UTF-8") ;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        String result = null;
        HttpURLConnection con;
        URL url = null;
        BufferedReader reader = null;
        try{
            url = new URL(urlStr);
        }catch(Exception e){
            e.printStackTrace();
        }

        try {
            con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            con.addRequestProperty("Authorization","Bearer " + mApiToken);

            final int status = con.getResponseCode();
            Log.d(LOG_TAG, "result:" + status);
            if (status == HttpURLConnection.HTTP_OK) {
                //Processing to receive response, etc.
                result=HTTP_OK;
                StringBuilder stringBuilder = new StringBuilder();
                reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    stringBuilder.append(inputLine);
                }
                mTranslatedWord = stringBuilder.toString();
                mTranslatedWord = mTranslatedWord.replace("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", "");
                mTranslatedWord = mTranslatedWord.replace("</string>", "");
                Log.d(LOG_TAG, "http post success recvData: " + mTranslatedWord);
            } else{
                result=String.valueOf(status);
            }

        }catch(Exception e){
            Log.e(LOG_TAG, e.toString());
        }

        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        Log.d(LOG_TAG, "onPostExecute, result:" + result);
        if(result.equals(HTTP_OK)) {
            mActivity.callback(MainActivity.CALLBACK_FINISH_TRANSLATE_CODE, mTranslatedWord);
        }else{
            Log.d(LOG_TAG, "onPostExecute:Error");
        }
    }
}

Code commentary

1. Hold the callback destination Activity, untranslated text, and API token in the constructor
    //constructor
    public TranslateAPITranslateRequest(MainActivity activity,String word,String token){
        Log.d(LOG_TAG,"word:" + word);
        mActivity = activity;
        mTranslateWord = word;
        mApiToken = token;
    }
2. Specify the endpoint and URL parameters

The translation request endpoints are: http://api.microsofttranslator.com/v2/Http.svc/Translate The URL parameters are as follows. text: The text you want to translate. ** Required ** to: Translated language code. ** Required ** from: Language code before translation. Any appid: API token. ** Required, but not required if header parameter: Authorization specifies API token. ** **

    try {
           urlStr = "http://api.microsofttranslator.com/v2/Http.svc/Translate?from=ja&to=en&text=" + URLEncoder.encode(mTranslateWord, "UTF-8") ;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

This time, we will translate from Japanese to English, so we have specified from = ja and to = en. The API token is then specified in the header parameter.

3. Specify request parameters

Request method: GET (There is a theory that there is no problem with POST) Authorization: API token (*)

The following is the format of the API token. ** "Bearer \ <API token >" ** You need to put a Bearer on the head. ** Please note that there is a space between the Bearer and the API token. ** ** This format is also used when the appid is specified in the URL parameter.

    con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("GET");
    con.addRequestProperty("Authorization","Bearer " + mApiToken);
4. Replace the translation result received in the response with unnecessary parts and keep it in the member variable.

If the request is successful, the translation result will be returned in the following format.

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[Translation result]</string>

I want to return only the translation result, so delete the unnecessary part.


    mTranslatedWord = stringBuilder.toString();
    mTranslatedWord = mTranslatedWord.replace("<string xmlns=\"http://schemas.microsoft.com/2003/10/Serialization/\">", "");
    mTranslatedWord = mTranslatedWord.replace("</string>", "");

Quite forcible?

5. Call back to Activity when communication is completed (when onPostExecute is called).

If the communication is successful, the received translation result will be called back to Activity. I am using the callback function implemented in MainActivity.


    @Override
    protected void onPostExecute(String result) {
        Log.d(LOG_TAG, "onPostExecute, result:" + result);
        if(result.equals(HTTP_OK)) {
            mActivity.callback(MainActivity.CALLBACK_FINISH_TRANSLATE_CODE, mTranslatedWord);
        }else{
            Log.d(LOG_TAG, "onPostExecute:Error");
        }
    }

After that, it is OK if you display the translation result on TextView etc. on the Activity side.

MainActivity.java


 /**
   *Callback method.
   *Called after background processing is completed.
   */
    public void callback(final int responseCode, String word) {
        if (CALLBACK_FINISH_TRANSLATE_CODE == responseCode) {
            translateResultText.setText(word);
        }
    }

When starting translation, describe as follows in Activity and start from acquisition of API token.

    TranslateAPIGetTokenRequest trans = new TranslateAPIGetTokenRequest(MainActivity.this, [The text you want to translate]);
    trans.execute();

3. I tried to translate

I tried to translate the character string entered in EditText to see how accurate it actually is. The text is pulled from the official documentation of the Microsoft Translator API.

1. Japanese ⇒ English

Screenshot_20171129-140425.png

Google translate

msae2.PNG

In this way, the English text of the translated word is completely different.

2. English ⇒ Japanese

Screenshot_20171129-093344.png

Google translate

msae.PNG

** Conclusion **

As expected, Google seems to have higher translation accuracy. But I wish I could do this for free!

That's it.

Recommended Posts

Translator using Microsoft Translator Text API on Android ~ Implementation ~
Translate using Microsoft Translator Text API in Java (Japanese → English)
(Android) Dynamically change text using DataBinding
Save ArrayList using GSON on Android
[Android] Implementation of side-scrolling ListView using RecyclerView
Try using the service on Android Oreo
Sobel filter using OpenCV on Android (Java)
Try using the Emotion API from Android
Try using Firebase Cloud Functions on Android (Java)
Android application development using Unity + ARCore on Ubuntu
(Android) Try to display static text using DataBinding
Try communication using gRPC on Android + Java server
Run the Android emulator on Docker using Android Emulator Container Scripts
Using PAY.JP API with Rails ~ Implementation Preparation ~ (payjp.js v2)
Try image classification using TensorFlow Lite on Android (JAVA)