Google Translate Tutorial for iOS: How To Translate Text With Google Translate and JSON on the iPhone

A Google translate tutorial on how you can easily use Google Translate to translate text into different languages on the iPhone. By Ray Wenderlich.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

Performing the Translation

We are going to retrieve the JSON response from the web server asynchronously. This means that rather than using initWithContentsOfURL – which is a no-no because it makes the interface unresponsive while the download is taking place – we will register ourselves as a delegate so we get notifications as the data is being downloaded in the background.

So to accomplish this, add three more member variables to your class in GoogleTranslateViewController.h:

NSMutableData *responseData;
NSMutableArray *translations;
NSString *_lastText;

And one property:

@property (nonatomic, copy) NSString * lastText;

Then go to GoogleTranslateViewController.m and add the following header:

#import "JSON.h"

And the following line right under the @implementation:

@synthesize lastText = _lastText;

And modify the dealloc method to include our cleanup code before we forget:

- (void)dealloc {
    [translations release];
    [_lastText release];
    [super dealloc];
}

Last piece of grunt work – create the translations array in the viewDidLoad method as follows:

- (void)viewDidLoad {
    [super viewDidLoad];
    translations = [[NSMutableArray alloc] init]; 
}

Ok – now time to perform the translation. Add the following methods to the bottom of the file:

- (void)performTranslation {
        
    responseData = [[NSMutableData data] retain];
    
    NSString *langString = @"en|ja";
    NSString *textEscaped = [_lastText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *langStringEscaped = [langString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString *url = [NSString stringWithFormat:@"http://ajax.googleapis.com/ajax/services/language/translate?q=%@&v=1.0&langpair=%@",
                     textEscaped, langStringEscaped];
    
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    [[NSURLConnection alloc] initWithRequest:request delegate:self];
    
}

- (IBAction)doTranslation {
    
    [translations removeAllObjects];
    [textField resignFirstResponder];
    
    button.enabled = NO;
    self.lastText = textField.text;
    [translations addObject:_lastText];
    textView.text = _lastText;    
    
    [self performTranslation];
    
}

Let’s look at doTranslation first. In this method, we clear out our member variable that we are going to use to store the translations. We also remove the keyboard from the display by calling resignFirstResponder on the text field. We set the button to disabled, store away the text that the user wants to translate in lastText and set the initial value of the text view to that value, and then call the performTranslation method.

In performTranslation, we first initialize an NSMutableData object that will be used to store the JSON response as it comes back from the server.

We then construct the URL to retrieve the translation from the Google server, using stringByAddingPercentEscapesUsingEncoding in order to escape our string properly.

Finally, we create an NSURLConnection with a NSURLRequest in order to start the process of downloading the data asynchronously. We set ourselves as the delegate so we will receive callbacks when the data arrives.

So let’s write those callbacks now! Add the following to the bottom of the file:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [responseData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    [responseData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    textView.text = [NSString stringWithFormat:@"Connection failed: %@", [error description]];
    button.enabled = YES;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [connection release];
    
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
    [responseData release];
        
    NSMutableDictionary *luckyNumbers = [responseString JSONValue];
    [responseString release];
    if (luckyNumbers != nil) {
        
        NSDecimalNumber * responseStatus = [luckyNumbers objectForKey:@"responseStatus"];
        if ([responseStatus intValue] != 200) {
            button.enabled = YES;
            return;
        }
        
        NSMutableDictionary *responseDataDict = [luckyNumbers objectForKey:@"responseData"];
        if (responseDataDict != nil) {
            NSString *translatedText = [responseDataDict objectForKey:@"translatedText"];
            [translations addObject:translatedText];
            self.lastText = translatedText;            
            textView.text = [textView.text stringByAppendingFormat:@"\n%@", translatedText];
            button.enabled = YES;
        }
    }
    
}

Most of this is the pretty standard method way to collect the data as it comes in our NSMutableArray (responseData).

However the real fun occurs in connectionDidFinishLoading. We convert our NSData to a string, and then call a shortcut extension on NSString to invoke the JSON parser and convert the JSON string into the appropriate object (we know in this case that it will be a NSMutableDictionary). Note that we could have done this same thing by instantiating a SBJsonParser object and calling objectWithString – but this is just a bit simpler.

We then look inside the response, check the status to make sure we were successful, and then get the sub-dictionary of “responseData”. We then pull our the translated text, and add the results to the text view.

Compile and run your project, and if all works well you should see something like the following:

Our first translation

Finishing Touches

Now let’s add a little fun to the project and keep performing the translations back and forth until we arrive at a final result. Modify the beginning of your performTranslation method to look as follows:

- (void)performTranslation {
        
    // Break if we exceed limit
    if (translations.count > 50) {
        button.enabled = YES;
        return;
    }
    
    responseData = [[NSMutableData data] retain];
    BOOL translateToEnglish = ([translations count] % 2 == 0);
    
    // Bail if we have a match
    if (!translateToEnglish && [translations count] >= 3) {
        NSString *oldString = [translations objectAtIndex:[translations count] - 3];
        if ([oldString caseInsensitiveCompare:_lastText] == NSOrderedSame) {
            button.enabled = YES;
            return;
        }
    }
    
    NSString *langString;
    if (translateToEnglish) {
        langString = @"ja|en";        
    } else {
        langString = @"en|ja";
    }
    
    NSString *textEscaped = [_lastText stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    ///...

Here we just add a little fun logic into the mix. We bail out if we’ve performed over 50 back and forth translations. We figure out if we’re translating to English or not by checking the size of our translation array – we alternate between English and Japanese, so every time the count is divisible by 2, we must be trying to translate some Japanese to English.

We check to see if the last English result matches the current English result, and we know we’re done if it matches. Lastly, we set the language string to alternate based on what we’re trying to do.

Now navigate to the connectionDidFinishLoading method. Add the following line inside at the end of the if (responseDataDict != nil) block:

[self performTranslation];

Compile and run the project, and you now should see some amusing results! Funny how much is lost in translation!

Screenshot of A Full and Amusing Translation

Can I Use Google Translate in My App?

If your app is free, definitely.

But if your app is paid, it’s a good question. According to the Google AJAX API Terms of Service, generally the implementation of Google Translate in your application must be available free of charge. So it’s pretty clear that Google wouldn’t allow you to whip up an app that is just a wrapper over Google Translate and sell it as-is.

However it’s a bit more unclear what is allowed when you have significant other features in your app, and Google translate is just one part of that. Some people on the Google AJAX forums believe that as long as you aren’t charging for the translation results specifically and give attribution to Google, you’ll be OK. I’ve also seen people doing this already on the App Store and haven’t heard of any issues.

But neither I nor the other folks are lawyers, so you might want to consult with one if you want to use Google APIs in your app!