In this video I complete the Android Translation app! I provide both an Android Text to Speech Example as well as a Speech to Text example. I also review how to use Spinners.
By the end we will be able to say a phrase, translate it into multiple different languages and then press a button and have those translated phrases speak. All of the code follows the video below.
If you value videos like this, help others find out about them by sharing on Google Plus with a click here [googleplusone]
Code From the Videos
MyActivity.java
package com.newthinktank.derekbanas.xmltranslates;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Locale;
public class MyActivity extends Activity implements
TextToSpeech.OnInitListener {
// Define the spoken language we wish to use
// You must install all of these on your phone for text to speech
// Settings - Language & Input - Text-to-speech output -
// Preferred Engine Settings - Install voice data
private Locale currentSpokenLang = Locale.US;
// Create the Locale objects for languages not in Android Studio
private Locale locSpanish = new Locale("es", "MX");
private Locale locRussian = new Locale("ru", "RU");
private Locale locPortuguese = new Locale("pt", "BR");
private Locale locDutch = new Locale("nl", "NL");
// Stores all the Locales in an Array so they are easily found
private Locale[] languages = {locDutch, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN,
locPortuguese, locRussian, locSpanish};
// Synthesizes text to speech
private TextToSpeech textToSpeech;
// Spinner for selecting the spoken language
private Spinner languageSpinner;
// Currently selected language in Spinner
private int spinnerIndex = 0;
// Will hold all translations
private String[] arrayOfTranslations;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
languageSpinner = (Spinner) findViewById(R.id.lang_spinner);
// When the Spinner is changed update the currently selected language
// to speak in
languageSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int index, long l) {
currentSpokenLang = languages[index];
// Store the selected Spinner index for use elsewhere
spinnerIndex = index;
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
textToSpeech = new TextToSpeech(this, this);
}
// When the app closes shutdown text to speech
@Override
public void onDestroy() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
}
super.onDestroy();
}
// Calls for the AsyncTask to execute when the translate button is clicked
public void onTranslateText(View view) {
EditText translateEditText = (EditText) findViewById(R.id.words_edit_text);
// If the user entered words to translate then get the JSON data
if(!isEmpty(translateEditText)){
Toast.makeText(this, "Getting Translations",
Toast.LENGTH_LONG).show();
// Calls for the method doInBackground to execute
new GetXMLData().execute();
} else {
// Post an error message if they didn't enter words
Toast.makeText(this, "Enter Words to Translate",
Toast.LENGTH_SHORT).show();
}
}
// Check if the user entered words to translate
// Returns false if not empty
protected boolean isEmpty(EditText editText){
// Get the text in the EditText convert it into a string, delete whitespace
// and check length
return editText.getText().toString().trim().length() == 0;
}
// Initializes text to speech capability
@Override
public void onInit(int status) {
// Check if TextToSpeech is available
if (status == TextToSpeech.SUCCESS) {
int result = textToSpeech.setLanguage(currentSpokenLang);
// If language data or a specific language isn't available error
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(this, "Language Not Supported", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(this, "Text To Speech Failed", Toast.LENGTH_SHORT).show();
}
}
// Speaks the selected text using the correct voice for the language
public void readTheText(View view) {
// Set the voice to use
textToSpeech.setLanguage(currentSpokenLang);
// Check that translations are in the array
if (arrayOfTranslations.length >= 9){
// There aren't voices for our first 3 languages so skip them
// QUEUE_FLUSH deletes previous text to read and replaces it
// with new text
textToSpeech.speak(arrayOfTranslations[spinnerIndex+4], TextToSpeech.QUEUE_FLUSH, null);
} else {
Toast.makeText(this, "Translate Text First", Toast.LENGTH_SHORT).show();
}
}
class GetXMLData extends AsyncTask<Void, Void, Void>{
String stringToPrint = "";
@Override
protected Void doInBackground(Void... voids) {
String xmlString = "";
String wordsToTranslate = "";
EditText translateEditText = (EditText) findViewById(R.id.words_edit_text);
wordsToTranslate = translateEditText.getText().toString();
wordsToTranslate = wordsToTranslate.replace(" ", "+");
DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams());
HttpPost httpPost = new HttpPost("http://newjustin.com/translateit.php?action=xmltranslations&english_words=" + wordsToTranslate);
httpPost.setHeader("Content-type", "text/xml");
InputStream inputStream = null;
try{
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null){
sb.append(line);
}
xmlString = sb.toString();
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(new StringReader(xmlString));
int eventType = xpp.getEventType();
while(eventType != XmlPullParser.END_DOCUMENT){
if((eventType == XmlPullParser.START_TAG) && (!xpp.getName().equals("translations"))){
stringToPrint = stringToPrint + xpp.getName() + " : ";
} else if(eventType == XmlPullParser.TEXT){
stringToPrint = stringToPrint + xpp.getText() + "\n";
}
eventType = xpp.next();
}
} catch (MalformedURLException e){
e.printStackTrace();
} catch (UnsupportedEncodingException e){
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XmlPullParserException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
TextView translateTextView = (TextView) findViewById(R.id.translate_text_view);
// Make the TextView scrollable
translateTextView.setMovementMethod(new ScrollingMovementMethod());
// Eliminate the "language :" part of the string for the
// translations
String stringOfTranslations = stringToPrint.replaceAll("\\w+\\s:","#");
// Store the translations into an array
arrayOfTranslations = stringOfTranslations.split("#");
translateTextView.setText(stringToPrint);
}
}
// Converts speech to text
public void ExceptSpeechInput(View view) {
// Starts an Activity that will convert speech to text
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
// Use a language model based on free-form speech recognition
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
// Recognize speech based on the default speech of device
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
// Prompt the user to speak
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.speech_input_phrase));
try{
startActivityForResult(intent, 100);
} catch (ActivityNotFoundException e){
Toast.makeText(this, getString(R.string.stt_not_supported_message), Toast.LENGTH_LONG).show();
}
}
// The results of the speech recognizer are sent here
protected void onActivityResult(int requestCode, int resultCode, Intent data){
// 100 is the request code sent by startActivityForResult
if((requestCode == 100) && (data != null) && (resultCode == RESULT_OK)){
// Store the data sent back in an ArrayList
ArrayList<String> spokenText = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
EditText wordsEntered = (EditText) findViewById(R.id.words_edit_text);
// Put the spoken text in the EditText
wordsEntered.setText(spokenText.get(0));
}
}
}
strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">XML Translates</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="translate_text_view">Enter the words to translate above</string>
<string name="translate_button">Translate</string>
<string name="speech_input_phrase">Say the Phrase</string>
<string name="stt_not_supported_message">Your Device Doesn\'t Support Speech to Text</string>
<string-array name="language_array">
<item>Dutch</item>
<item>French</item>
<item>German</item>
<item>Italian</item>
<item>Portuguese</item>
<item>Russian</item>
<item>Spanish</item>
</string-array>
</resources>
activity_my.xml
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MyActivity">
<EditText
android:id="@+id/words_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Speak"
android:id="@+id/button"
android:layout_below="@+id/words_edit_text"
android:layout_alignParentLeft="true"
android:layout_marginTop="16dp"
android:onClick="ExceptSpeechInput"/>
<Button
android:id="@+id/translate_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="70dp"
android:text="@string/translate_button"
android:onClick="onTranslateText"
android:layout_below="@+id/words_edit_text"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lang_spinner"
android:layout_below="@+id/translate_button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:entries="@array/language_array"
android:layout_marginTop="10dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read"
android:id="@+id/button2"
android:layout_below="@+id/lang_spinner"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:onClick="readTheText"/>
<TextView
android:id="@+id/translate_text_view"
android:text="@string/translate_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_below="@+id/button2"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
</RelativeLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.newthinktank.derekbanas.xmltranslates" >
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MyActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Hi Derek,
Great tutorial and nice little app. I watched it but have not built it locally yet.
I was wondering why you said Android does not support all the languages in the TTS list, and you chose only those 6 in question. Why for example the Chinese was not implemented for this tutorial? Sorry if I’m asking a dumb question.
Thanks
Hi Moj,
The Chinese language shows up in the Local class, but not in TTS. They show all the available tts languages here.
I suppose it’s because your web service translator does not extend to these other languages?
Yes you are correct
Sir,can image be send to android via json?
It is best to reference it by url
Derek,
Thank you for all the work you’ve put into the Android Studio tutorials. I am having trouble embedding videos into my app and getting them to play on a device. I have working examples of playing videos from a remote server, but need to include videos in an app. If you can help me get this going, I will save you a warm spot in heaven.
Thanks,
Dan
Derek,
Never mind. I got it working. Thank you so much for all the great tutorials.
You still get the complimentary warm spot in heaven.
Thanks,
Dan
Great I’m glad you fixed it. Sorry I couldn’t get to you quicker.
I’ll try to make a video on that topic this week.
Could you make a Navigation Drawer tutorial. I’m having trouble taking the info from the selected button and inflating the appropriate fragment.
That video will come out very soon