有道智云翻译API + retrofit实现在线翻译Android app

目录

1.进入有道智云主页,注册自己的账号(手机号验证码),完善信息随意填

2.登录进来后,创建应用。根据需要选择语言翻译服务。

3. 打开Android Studio,新建空的Activity项目

1. 新建项目,在build.gradle(app)添加retrofit依赖

 2. 打开有道云文本翻译API接入文档,找到json文件示例

3.新建一个接口类,获取json文件

4. 新建一个接口实现类来获取Call<>

 5.更改activity_main.xml布局文件

6. drawable文件夹中添加edit_border.xml

 7.在values文件夹中添加arrays.xml文件

 8.更改mainactivity文件

 9.在Manifest.xml中添加网络权限

4.现在就可以运行了


1.进入有道智云主页,注册自己的账号(手机号验证码),完善信息随意填

记得领取赠送的50元体验金(能用好久)

2.登录进来后,创建应用。根据需要选择语言翻译服务。

 我这里接入方式是API接入,因为用的是retrofit。注意IP地址不要填写,直接为空,就不会有IP限制

创建完成后,记下应用ID和应用密钥,等会会用到

3. 打开Android Studio,新建空的Activity项目

1. 新建项目,在build.gradle(app)添加retrofit依赖

    implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'

 2. 打开有道云文本翻译API接入文档,找到json文件示例

( AndroidStudio下载一个GsonFormatPlus插件)

新建Java类来接收这个json文件,Alt+Insert或者右键选择Generate,选择GsonFormatPlus,会跳出这样一个对话框

 将API接入文档中的json文件示例复制粘贴到左边空白栏,点击OK就会自动生成代码。 

//----更新于2022.11.19----

{
  "errorCode":"0",
  "query":"good", //查询正确时,一定存在
  "translation": [ //查询正确时一定存在
      "好"
  ],
  "basic":{ // 有道词典-基本词典,查词时才有
      "phonetic":"gʊd",
      "uk-phonetic":"gʊd", //英式音标
      "us-phonetic":"ɡʊd", //美式音标
      "uk-speech": "XXXX",//英式发音
      "us-speech": "XXXX",//美式发音
      "explains":[
          "好处",
          "好的",
          "好",
      ]
  },
  "web":[ // 有道词典-网络释义,该结果不一定存在
      {
          "key":"good",
          "value":["良好","善","美好"]
      },
      {...}
  ],
  "dict":{
      "url":"yddict://m.youdao.com/dict?le=eng&q=good"
  },
  "webdict":{
      "url":"http://m.youdao.com/dict?le=eng&q=good"
  },
  "l":"EN2zh-CHS",
  "tSpeakUrl":"XXX",//翻译后的发音地址
  "speakUrl": "XXX" //查询文本的发音地址
}

这个是目前有道提供的最新json文件,因为收到好几个读者回复说,生成不出来相关代码,所以在这统一说明一下。

JSON文件是有自己的格式的。上述文件中,网易有道在 web 整了个省略。因为里面的元素可能是好几个,有道没有一一列举,也无法列举,所以导致无法生成相关javabean代码。把 web 中的{...} 包括前面的(,)逗号删掉,就能正常生成代码啦。

最后结果:

{
    "errorCode": "0",
    "query": "good",
    "translation": ["好"],
    "basic": {
        "phonetic": "gʊd",
        "uk-phonetic": "gʊd",
        "us-phonetic": "ɡʊd",
        "uk-speech": "XXXX",
        "us-speech": "XXXX",
        "explains": [
            "好处",
            "好的",
            "好"
        ]
    },
    "web": [{
        "key": "good",
        "value": [
            "良好",
            "善",
            "美好"
        ]
    }],
    "dict": {"url": "yddict://m.youdao.com/dict?le=eng&q=good"},
    "webdict": {"url": "http://m.youdao.com/dict?le=eng&q=good"},
    "l": "EN2zh-CHS",
    "tSpeakUrl": "XXX",
    "speakUrl": "XXX"
}

//----更新于2022.11.19----

3.新建一个接口类,获取json文件

import retrofit2.Call;
import retrofit2.http.POST;
import retrofit2.http.Query;

public interface GetResult {

    @POST("api")
    Call<TextRes> getTextRes(@Query("from") String from, @Query("to") String to,
                             @Query("appKey") String ID, @Query("salt") String salt,
                             @Query("sign") String sign, @Query("signType") String signType,
                             @Query("curtime") String curtime, @Query("q") String q);
    
}

Call<TestRes>中TestRes是JavaBean类名 

4. 新建一个接口实现类来获取Call<>

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class TextTranslator {
    String q;

    public TextTranslator(String s) {
        this.q = s;
    }

    static String APP_KEY = "你的应用ID", signType = "v3";
    static final String APP_SECRET = "你的应用密钥";
    static String BASE_URL = "https://openapi.youdao.com/";

    public Call<TextRes> getCall(String from, String to) {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
        final GetResult getR = retrofit.create(GetResult.class);

        String salt = String.valueOf(System.currentTimeMillis());
        String curtime = String.valueOf(System.currentTimeMillis() / 1000);
        String sign = getDigest(APP_KEY + truncate(q) + salt + curtime + APP_SECRET);
        return getR.getTextRes(from, to, APP_KEY, salt, sign, signType, curtime, q);
    }

    private static String truncate(String q) {
        if (q == null) {
            return null;
        }
        int len = q.length();
        return len <= 20 ? q : (q.substring(0, 10) + len + q.substring(len - 10, len));
    }

    private static String getDigest(String string) {
        if (string == null) {
            return null;
        }
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
                '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        byte[] btInput = string.getBytes(StandardCharsets.UTF_8);
        try {
            MessageDigest mdInst = MessageDigest.getInstance("SHA-256");
            mdInst.update(btInput);
            byte[] md = mdInst.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (NoSuchAlgorithmException e) {
            return null;
        }
    }
}

 5.更改activity_main.xml布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="50dp"
    android:layout_marginStart="50dp"
    android:layout_marginEnd="50dp"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Spinner
        android:id="@+id/lan_spinner"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_marginBottom="20dp"
        android:entries="@array/language"
        android:theme="@style/lan_spinner" />

    <LinearLayout
        android:id="@+id/all_li"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <EditText
            android:id="@+id/trans"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/edit_border"
            android:hint="输入内容"
            android:textSize="25sp" />

        <LinearLayout
            android:id="@+id/trans_l"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:visibility="gone">

            <TextView
                android:id="@+id/block"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="基本释义:"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/trans_tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="#0089B3"
                android:textSize="25sp" />
        </LinearLayout>

        <LinearLayout
            android:id="@+id/exp_l"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:visibility="gone">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="拓展释义:"
                android:textSize="20sp" />

            <TextView
                android:id="@+id/exp_tv"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="#00A8DC"
                android:textSize="25sp" />
        </LinearLayout>

        <Button
            android:id="@+id/search"
            android:layout_width="160dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_gravity="center"
            android:text="查询"
            android:textSize="20sp" />
    </LinearLayout>

</LinearLayout>

6. drawable文件夹中添加edit_border.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="10dp" />
    <stroke
        android:width="0.8dp"
        android:color="@color/black" />
    <padding
        android:bottom="4dp"
        android:left="6dp"
        android:right="6dp"
        android:top="4dp" />
</shape>

 7.在values文件夹中添加arrays.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="language">
        <item>自动检测</item>
        <item>英文 → 中文</item>
        <item>中文 → 英文</item>
        <item>中文 → 日语</item>
        <item>中文 → 韩语</item>
        <item>中文 → 法语</item>
        <item>中文 → 俄语</item>
    </string-array>
    <style name="lan_spinner" parent="Widget.AppCompat.Light.DropDownItem.Spinner">
        <item name="android:textSize">20sp</item>
        <item name="paddingStart">0dp</item>
        <item name="paddingEnd">0dp</item>
        <item name="background">@drawable/edit_border</item>
    </style>
</resources>

 8.更改mainactivity文件

import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class MainActivity extends AppCompatActivity {
    EditText trans;
    TextView transTv, expTv;
    Button search;
    LinearLayout transLi, expLi;
    String exp, tran, pho;
    String from = "auto", to = "auto", q;
    TextRes tr;
    Spinner spinner;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
        clickAndListener();
    }

    private void init() {
        trans = findViewById(R.id.trans);
        transTv = findViewById(R.id.trans_tv);
        expTv = findViewById(R.id.exp_tv);
        search = findViewById(R.id.search);
        transLi = findViewById(R.id.trans_l);
        expLi = findViewById(R.id.exp_l);
        spinner = findViewById(R.id.lan_spinner);
    }

    private void clickAndListener() {
        search.setOnClickListener(v -> textResult());

        trans.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                if (s.length() == 0) {
                    transLi.setVisibility(View.GONE);
                    expLi.setVisibility(View.GONE);
                }
                search.setVisibility(View.VISIBLE);
            }

            @Override
            public void afterTextChanged(Editable s) {
            }
        });

        spinnerListener();
    }

    private void textResult() {
        q = trans.getText().toString().trim();
        TextTranslator t = new TextTranslator(q);
        Call<TextRes> call = t.getCall(from, to);
        call.enqueue(new Callback<TextRes>() {
            @Override
            public void onResponse(@NonNull Call<TextRes> call, @NonNull Response<TextRes> response) {
                tr = response.body();
                if (tr != null) {
                    int code = tr.getErrorCode();
                    if (0 == code) {
                        exp = tr.getExplains();
                        tran = tr.getTrans();
                        pho = tr.getUkPho();
                        if (pho != null) {
                            transTv.setText(tran + pho);
                        } else {
                            transTv.setText(tran);
                        }
                        transLi.setVisibility(View.VISIBLE);
                        search.setVisibility(View.GONE);
                        if (!tran.equals(exp) && exp != null) {
                            expTv.setText(exp);
                            expLi.setVisibility(View.VISIBLE);
                        }
                    } else if (113 == code) {
                        toaPrint("请输入翻译内容");
                    } else toaPrint("请求错误,错误码为:" + tr.getErrorCode());
                }
            }

            @Override
            public void onFailure(@NonNull Call<TextRes> call, @NonNull Throwable t) {
                Log.i("TAG", "onFailure");
                toaPrint("请检查网络设置!");
            }
        });
    }

    private void toaPrint(String s) {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
    }

    private void spinnerListener() {
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                switch (position) {
                    case 1://英文 → 中文
                        from = "en";
                        to = "zh-CHS";
                        break;
                    case 2://中文 → 英文
                        from = "zh-CHS";
                        to = "en";
                        break;
                    case 3://中文 → 日语
                        from = "zh-CHS";
                        to = "ja";
                        break;
                    case 4://中文 → 韩语
                        from = "zh-CHS";
                        to = "ko";
                        break;
                    case 5://中文 → 法语
                        from = "zh-CHS";
                        to = "fr";
                        break;
                    case 6://中文 → 俄语
                        from = "zh-CHS";
                        to = "ru";
                        break;
                    default:
                        break;
                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });
    }
}

 9.在Manifest.xml中添加网络权限

<uses-permission android:name="android.permission.INTERNET"/>

 10.关于GsonFormatPlus的设置补充

4.现在就可以运行了

             

 源码下载:GitHub - Beacon0423/Androidhttps://github.com/Beacon0423/Android

欢迎批评点赞 

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 31
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

-情绪零碎-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值