android - 如何在 Android 项目中使用谷歌翻译 api v3 将 googleapis/java-translate 库转换为自定义 api 休息请求

标签 android api rest kotlin google-translation-api

在因为 googleapis/java-translate 库为我的应用程序构建版本时看到冲突之前,我使用了这些行并且它运行良好:

    val translate: Translate = TranslateOptions.newBuilder().setApiKey(API_KEY).build().service
    val translations = translate.translate(
         textsToTranslate,
         Translate.TranslateOption.sourceLanguage(sourceLanguage),
         Translate.TranslateOption.targetLanguage(targetLanguage)
    )
然后,在构建发布时,我必须在 app/build.gradle 中添加一些额外的代码以使其正常工作。
但是,我看到我的应用程序从 10Mo 增长到 15Mo。只是为了翻译一些文本而昂贵..
所以我决定自己使用最新的 Google Translate Api v3 进行这些翻译
link
像这样执行一个简单的 api 休息请求:
    val jsonObjectResponse = JSONObject(translate(sourceLanguageCode = sourceLanguage, targetLanguageCode = targetLanguage, textsToTranslate).awaitString())
    val translations = jsonObjectResponse.getJSONArray("translations").toArray { getJSONObject(it) }.map { it.getString("translatedText") }
其中“翻译”功能是:
    private fun translate(sourceLanguageCode: String, targetLanguageCode: String, textsToTranslate: List<String>): Request =
        Fuel.post(path = "https://translation.googleapis.com/v3/projects/$PROJECT_ID:translateText?key=$API_KEY")
            .header(Headers.ACCEPT to "application/json")
            .jsonBody(
                JSONObject().apply {
                    put("contents", JSONArray().apply {
                        textsToTranslate.forEach { text -> put(text) }
                    })
                    put("sourceLanguageCode", sourceLanguageCode)
                    put("targetLanguageCode", targetLanguageCode)
                }.toString()
            )
但它返回:“HTTP Exception 401 Unauthorhorized”。该链接没有提到 API_KEY 的使用,所以我想它与..
注意:Fuel 只是 Kotlin/Android 的 HTTP 网络库,以避免样板代码。
恢复:使用 googleapis/java-translate 的第一个正在工作,但第二个(自定义)不起作用并返回:“HTTP Exception 401 Unautohorized”。
我哪里错了?
额外说明:我知道我现在不限于 android 应用程序的包名称,但在这里,我只想让它工作:)
编辑
  • jsonBody 函数将标题“Content-Type”隐式添加到“application/json”
  • 如果apiKey不能在v3中使用,我可以使用其他方式吗?我已经有firebase Crashlytics,这意味着我已经有一个谷歌服务来处理与谷歌服务的通信,但是到处都有太多的文档,这太糟糕了,这让我感到恶心。我可以使用哪个库来处理 android 应用程序中的凭据,而不会因“Meta-*** 冲突”等而破坏我的应用程序。我在这片信息的海洋中感到困惑和迷失。

  • 编辑 - 2020 年 12 月 3 日
    再见赏金 [400]
    最终使用带有 REST 的 Google Translate API v2:
    // portion of suspend function code
    coroutineScope {
            async(Dispatchers.IO) {
                try {
                    //handleTranslateV3Response(requests, JSONObject(translateV3(sourceLanguageCode = sourceLanguage, targetLanguageCode = targetLanguage, textsToTranslate = textsToTranslate).awaitString()))
                    //handleTranslateV2Response(requests, JSONObject(translateV2RestrictedToApplication(targetLanguageCode = targetLanguage, textsToTranslate = textsToTranslate, signature = signature).awaitString()))
                    handleTranslateV2Response(requests, JSONObject(translateV2(targetLanguageCode = targetLanguage, textsToTranslate = textsToTranslate).awaitString()))
                } catch (e: Exception) {
                    Timber.tag("Translate").e(e)
                    val message: String = "An error occurred while translating ${sourceLanguage} to ${targetLanguage}"
                    requests.mapIndexed { index, entityTranslationRequest ->
                        TranslationResponse.Error(message, entityTranslationRequest)
                    }
                }
            }
        }
    
        /**
         * Usage of Google Translate API v2 without restriction
         * This function works properly
         */
        private fun translateV2(targetLanguageCode: String, textsToTranslate: List<String>): Request =
            Fuel.post(path = "https://translation.googleapis.com/language/translate/v2?key=$API_KEY")
                .header(Headers.ACCEPT to "application/json")
                .jsonBody(
                    JSONObject().apply {
                        put("q", JSONArray().apply {
                            textsToTranslate.forEach { text -> put(text) }
                        })
                        put("target", targetLanguageCode)
                    }.toString()
                )
                .header(Headers.CONTENT_TYPE to "application/json; charset=utf-8")
    
        private fun handleTranslateV2Response(requests: List<EntityTranslationRequest>, jsonObject: JSONObject): List<TranslationResponse> {
            val translations = jsonObject.getJSONObject("data").getJSONArray("translations").toArray { getJSONObject(it) }.map { it.getString("translatedText") }
    
            return requests.mapIndexed { index, entityTranslationRequest ->
                TranslationResponse.Success(translations[index], entityTranslationRequest)
            }
        }
    
    在此 API KEY 上使用 Android 应用程序限制时,以下代码不起作用。
    根据同一问题的 this stackoverflow linkthis stackoverflow linkthis stackoverflow link
    如果不使用处理 Auth2、凭据等的多个谷歌库之一,就没有正确的方法可以自己发送指纹......
        /**
         * Usage of Google Translate API v2 with restriction to android app
         * This function doesn't work and returns a "HTTP Exception 403 Forbidden"
         * @param signature SHA-1
         */
        private fun translateV2RestrictedToApplication(signature: String, targetLanguageCode: String, textsToTranslate: List<String>): Request =
            Fuel.post(path = "https://translation.googleapis.com/language/translate/v2?key=$API_KEY")
                .header(Headers.ACCEPT to "application/json")
                .header("X-Android-Package" to BuildConfig.APPLICATION_ID)
                .header("X-Android-Cert" to signature.toLowerCase())
                .jsonBody(
                    JSONObject().apply {
                        put("q", JSONArray().apply {
                            textsToTranslate.forEach { text -> put(text) }
                        })
                        put("target", targetLanguageCode)
                    }.toString()
                )
                .header(Headers.CONTENT_TYPE to "application/json; charset=utf-8")
    
    下面是 v3 的代码,它不起作用,因为它需要似乎只能从 Google 库生成的 token ,而且我厌倦了到处 split 的文档,这让我感到恶心。
        /**
         * Usage of Google Translate API v3
         * This function doesn't work and returns a "HTTP Exception 401 Unautorhorized"
         */
        private fun translateV3(sourceLanguageCode: String, targetLanguageCode: String, textsToTranslate: List<String>): Request =
            Fuel.post(path = "https://translation.googleapis.com/v3/projects/$PROJECT_ID:translateText")
                .header(Headers.ACCEPT to "application/json")
                .header(Headers.AUTHORIZATION to "Bearer {token provided by some Google libraries I guess}")
                .jsonBody(
                    JSONObject().apply {
                        put("contents", JSONArray().apply {
                            textsToTranslate.forEach { text -> put(text) }
                        })
                        put("sourceLanguageCode", sourceLanguageCode)
                        put("targetLanguageCode", targetLanguageCode)
                    }.toString()
                )
                .header(Headers.CONTENT_TYPE to "application/json; charset=utf-8")
    
        private fun handleTranslateV3Response(requests: List<EntityTranslationRequest>, jsonObject: JSONObject): List<TranslationResponse> {
            val translations = jsonObject.getJSONArray("translations").toArray { getJSONObject(it) }.map { it.getString("translatedText") }
    
            return requests.mapIndexed { index, entityTranslationRequest ->
                TranslationResponse.Success(translations[index], entityTranslationRequest)
            }
        }
    

    最佳答案

    我从 IBM Watson Translator 得到了同样的错误并解决了它
    所以我以为错误来了

  • 内容类型请求:必须指定为 "Content-Type":"application/json"
  • 授权:我不确定你,但大多数时候授权 key (api key )
    必须在请求头中指定
  • API KEY:如果api key在单词之间有空格,它可能不起作用
  • 大部分时间取决于api key

    我有 this教程作为在 v3 中完成它的最简单方法。
    并开始您需要来自 header 的授权和内容类型请求,您需要这样做
    //okhttp3 library used
    fun doRequest(){
                val json = """${data("en","fr","Hello World")}"""
                val request = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json);
                val response = Request.Builder()
                        .url("https://translation.googleapis.com/v3/projects/project-number-or-id/locations/us-central1:translateText")
                        .post(request)
                        .addHeader("Authorization", "Bearer YOUR_API_GOES_HERE")
                        .addHeader("Content-Type", "application/json; charset=utf-8")
                        .build()
                val answer = client.newCall(response).execute().body()!!.string()
    print(answer)
    }
    
    警告 : 如果 API_KEY 有“apikey SFKHNKSJH-CSDFSCU”这样的空间,你需要使用 this 将其转换为单个 key 一种工具
    fun data(fromLang: String, toLang: String, word: String): String{
          return """{
      "sourceLanguageCode": "${fromLang}",
      "targetLanguageCodes": "${toLang}",
      "contents": ["${word}"]
    }"""
    
    }
    
    These文档可能会对您有所帮助。

    关于android - 如何在 Android 项目中使用谷歌翻译 api v3 将 googleapis/java-translate 库转换为自定义 api 休息请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64820683/

    相关文章:

    android - 通过保存 Bundle 并将其传递给 Android 中的其他 Activity 来添加从 EditText 检索到的整数值

    java - Drawable.createFromStream 和 getResources().getDrawable,为什么它们的输出不同?

    javascript - Angular $HTTP 发布 - 动态 URL 和定义发布

    javascript - 读取 Angular2 和 ionic 中的 API 响应

    asp.net-mvc - 用于移动应用程序的 REST API 上的 OAuth

    javascript - angularjs动态改变页脚

    android - 是否可以为单个类提供多种委托(delegate)类型?

    php - 如何使用 API 创建 GitHub Gist?

    asp.net - 设置 POST Web API 方法?

    java - 禁止在运行时通过 Rest Assured 发送空字段