Содержание
В рамках этого урока создадим приложение переводчик на kotlin в Android studio. Приложение будет предельно простым и состоять из поля EditText для ввода текста, кнопки “Translate” и поля TextView для вывода перевода. Язык введённого текса будет определятся автоматически переводчиком, а язык выводимого текста будет определятся “локалью” приложения, т. е. языком ввода на устройстве. Для приложения будет нужно разрешение на интернет в манифесте, т.к. перевод получается по средствам интернет сервиса.
Напишем Translater на Android Studio на языке kotlin
Первое что мы сделаем это создадим новый пакет (pakage) translater. В этом пакете будем хранить файлы переводчика, чтобы в будущих проектах не ломая голову копировать весь пакет и применить переводчик, например для локализации базы данных приложения на все языки.
В пакете translate создадим два файла:
- Language – этот файл будет хранить все языки
- TranslateAPI – тут находится
Файл Language
package ru.jandroid.translate2.translate object Language { const val AUTO_DETECT = "auto" const val AFRIKAANS = "af" const val ALBANIAN = "sq" const val ARABIC = "ar" const val ARMENIAN = "hy" const val AZERBAIJANI = "az" const val BASQUE = "eu" const val BELARUSIAN = "be" const val BENGALI = "bn" const val BULGARIAN = "bg" const val CATALAN = "ca" const val CHINESE = "zh-CN" const val CROATIAN = "hr" const val CZECH = "cs" const val DANISH = "da" const val DUTCH = "nl" const val ENGLISH = "en" const val ESTONIAN = "et" const val FILIPINO = "tl" const val FINNISH = "fi" const val FRENCH = "fr" const val GALICIAN = "gl" const val GEORGIAN = "ka" const val GERMAN = "de" const val GREEK = "el" const val GUJARATI = "gu" const val HAITIAN_CREOLE = "ht" const val HEBREW = "iw" const val HINDI = "hi" const val HUNGARIAN = "hu" const val ICELANDIC = "is" const val INDONESIAN = "id" const val IRISH = "ga" const val ITALIAN = "it" const val JAPANESE = "ja" const val KANNADA = "kn" const val KOREAN = "ko" const val LATIN = "la" const val LATVIAN = "lv" const val LITHUANIAN = "lt" const val MACEDONIAN = "mk" const val MALAY = "ms" const val MALTESE = "mt" const val NORWEGIAN = "no" const val PERSIAN = "fa" const val POLISH = "pl" const val PORTUGUESE = "pt" const val ROMANIAN = "ro" const val RUSSIAN = "ru" const val SERBIAN = "sr" const val SLOVAK = "sk" const val SLOVENIAN = "sl" const val SPANISH = "es" const val SWAHILI = "sw" const val SWEDISH = "sv" const val TAMIL = "ta" const val TELUGU = "te" const val THAI = "th" const val TURKISH = "tr" const val UKRAINIAN = "uk" const val URDU = "ur" const val VIETNAMESE = "vi" const val WELSH = "cy" const val YIDDISH = "yi" const val CHINESE_SIMPLIFIED = "zh-CN" const val CHINESE_TRADITIONAL = "zh-TW" }
Не забудьте заменить package на свой, иначе ничего работать не будет.
Насчет этого файла объяснять особо нечего. Это набор констант с названиями языков, которые в себе содержат краткое обозначение языка. По сути этот файл сделан для удобства, чтобы не гадать что es – Испанский, а sw – Шведский и т. д.
Файл TranslateAPI
package ru.jandroid.translate2.translate import android.content.ContentValues import android.os.AsyncTask import android.util.Log import org.json.JSONArray import org.json.JSONException import java.io.BufferedReader import java.io.IOException import java.io.InputStreamReader import java.io.UnsupportedEncodingException import java.net.HttpURLConnection import java.net.MalformedURLException import java.net.URL import java.net.URLEncoder class TranslateAPI(langFrom: String?, langTo: String?, text: String?) { var resp: String? = null var url: String? = null var langFrom: String? = null var langTo: String? = null var word: String? = null private var listener: TranslateListener? = null internal inner class Async : AsyncTask<String?, String?, String?>() { override fun doInBackground(vararg params: String?): String? { try { url = "https://translate.googleapis.com/translate_a/single?" + "client=gtx&" + "sl=" + langFrom + "&tl=" + langTo + "&dt=t&q=" + URLEncoder.encode( word, "UTF-8" ) val obj = URL(url) val con = obj.openConnection() as HttpURLConnection con.setRequestProperty("User-Agent", "Mozilla/5.0") val `in` = BufferedReader(InputStreamReader(con.inputStream)) var inputLine: String? val response = StringBuffer() while (`in`.readLine().also { inputLine = it } != null) { response.append(inputLine) } `in`.close() resp = response.toString() } catch (e: UnsupportedEncodingException) { e.printStackTrace() } catch (e: MalformedURLException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } catch (e: Exception) { e.printStackTrace() } return null } override fun onPostExecute(s: String?) { var temp = "" if (resp == null) { listener!!.onFailure("Network Error") } else { try { val main = JSONArray(resp) val total = main[0] as JSONArray for (i in 0 until total.length()) { val currentLine = total[i] as JSONArray temp = temp + currentLine[0].toString() } Log.d(ContentValues.TAG, "onPostExecute: $temp") if (temp.length > 2) { listener!!.onSuccess(temp) } else { listener!!.onFailure("Invalid Input String") } } catch (e: JSONException) { listener!!.onFailure(e.localizedMessage) e.printStackTrace() } } super.onPostExecute(s) } } fun setTranslateListener(listener: TranslateListener?) { this.listener = listener } interface TranslateListener { fun onSuccess(translatedText: String?) fun onFailure(ErrorText: String?) } init { this.langFrom = langFrom this.langTo = langTo word = text val async: Async = Async() async.execute() } }
Это основной файл, который обеспечивает наше приложение переводом.
Функция doInBackground выполняется вне основного потока и обращается к URL https://translate.googleapis.com/. . . , отправляя langFrom (исходный язык текста который нужно перевести) и langTo (язык на который нужно осуществить перевод) и word (текста который нужно перевести) и исходную кодировку UTF-8.
Функция onPostExecute получает в ответ на предыдущий запрос ответ в виде файла JSON.
И посредствам слушателей, написанных в interface TranslateListener, нас оповещают о том что перевод готов и мы можем его использовать, или сообщается об ошибке.
Вкратце это все, что нужно знать об этом файле. По сути вы вообще можете не задумываться о том как этот файл работает, вам главное знать как им пользоваться, а это мы разберём в MainActivity.
Файл activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:id="@+id/editText" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="32dp" android:layout_marginTop="32dp" android:layout_marginEnd="32dp" android:ems="10" android:inputType="textMultiLine|textPersonName" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/btTranslate" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="Translate" app:layout_constraintEnd_toEndOf="@+id/editText" app:layout_constraintStart_toStartOf="@+id/editText" app:layout_constraintTop_toBottomOf="@+id/editText" /> <TextView android:id="@+id/textView" android:layout_width="0dp" android:layout_height="200dp" android:layout_marginTop="16dp" app:layout_constraintEnd_toEndOf="@+id/editText" app:layout_constraintStart_toStartOf="@+id/editText" app:layout_constraintTop_toBottomOf="@+id/btTranslate" /> </androidx.constraintlayout.widget.ConstraintLayout>
Создадим файл разметки интерфейса Layout.
Файл build.gradle (module)
Добавим View Binding в наш проект следующим образом.
buildTypes { ... // Это ViewBinding buildFeatures{ viewBinding true } ...
Файл MainActivity
Вот мы и перешли к основному файлу, с помощью которого мы и научимся пользоваться пакетом нашим translate.
package ru.jandroid.translate2 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.util.Log import ru.jandroid.translate2.databinding.ActivityMainBinding import ru.jandroid.translate2.translate.Language import ru.jandroid.translate2.translate.TranslateAPI import java.util.* class MainActivity : AppCompatActivity() { lateinit var binding : ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.btTranslate.setOnClickListener { val countryMy = Locale.getDefault().language.lowercase() val text = binding.editText.getText().toString() val translateAPI = TranslateAPI(Language.AUTO_DETECT, countryMy, text) translateAPI.setTranslateListener(object : TranslateAPI.TranslateListener { override fun onSuccess(translatedText: String?) { binding.textView.text = translatedText } override fun onFailure(ErrorText: String?) { Log.d("MyLog", "Error of translate!") } }) } } }
Не забудьте заменить package на ваш, иначе работать ничего не будет. Про подключения binding я говорить ничего не буду, это тема другого урока.
Наше внимание будет приковано к слушателю кнопки btTranclate. Переменная countryMy получает язык локали, т.е. текущий язык на устройстве. Переменная text получает текст из EditText. TranslateAPI обращается к ранее созданному нами классу TranslateAPI для перевода текста text, язык этого текста Language.AUTO_DETECT (определяется автоматически), countryMy язык нашей локали (язык на устройстве). Все теперь запрос на перевод отправлен.
translateAPI.setTranslateListener . . . { } – это слушатель перевода. Мы не можем сразу получить перевод, т.к. нужно время на отправку запроса на сервер и время на ответ от сервера. По этому нужен слушатель, чтобы мы как можно быстрее узнали, что перевод готов.
Как только перевод будет готов функция onSuccess сообщит нам об этом и мы передаем наш перевод в TextView для отображения строкой binding.textView.text = translatedText.
Если в процессе перевода произошла ошибка то функция onFailure сообщит нам об этом и мы выведем сообщение об ошибке Log.d(“MyLog”, “Error of translate!”).
Заключение
Вот и все. По сути я должен был вам написать так: скопируйте все файлы, и не думайте как они работают, а вот о файле MainActivity мы поговорим, потому, что вам нужно знать лишь как пользоваться пакетом translate. Я думаю, вы согласитесь что это просто.
По сути приложение переводчик абсолютно бесполезно, т.к. есть много таких приложений от серьезных брендов, таких как Yandex или Google и т.д., но польза от него есть. Если вы захотите сделать свое приложение мультиязычным, вы конечно же переведете свой интерфейс по средствам перевода файла strings.xml стандартными функциями Android Studio, но что вы будите делать с данными и базы данных или из внешних файлов? Сделаете в базе данных кучу полей под все языки, это конечно круто, но очень трудоемко. А вот воспользоваться переводчиком очень неплохое решение, и если перевод не удался показать английский вариант. Можно даже при первом запуске приложения сделать полный перевод на язык лакали всех данных из базы данных и потом интернет для перевода будет не нужен.