Thursday, August 19, 2010

Google Translate and iPhone apps

Your Ad Here

The Cocoa and Cocoa Touch frameworks has a really nice function for acquiring a localized string NSLocalizedString(). Just pass in a key and you are done, for strings that are known at least. Sometimes you are getting unknown strings from a data source not under your control, strings representing just a fraction of the text in your UI. Leaving this text in it's source language looks weird, and skipping translation all together just feel wrong.

Google Translate to the rescue

Turns out that Google Translate has a nice AJAX API, feed it a URL request and get a JSON response. Admittedly the translations are not always perfect, even quite humorous at times, but good enough if you provide the user a warning.
So let us create a sibling to NSLocalizedString() called CWTranslatedString(). It should take two arguments; the string to translate, and the source language ISO code. We should also be able to get the users currently selected language, that will be used as the destination language when translating. So this is our header:

NSString* CWCurrentLanguageIdentifier();

NSString* CWTranslatedString(NSString* string, NSString* sourceLanguageIdentifier);    

Currently your iPhone application must be terminated in order for the user to change the language. And even when Apple adds multitasking for third-party apps we can assume the user do not go about and switch languages too often, so we let CWCurrentLanguageIdentifier() cache the language code:

NSString* CWCurrentLanguageIdentifier() {
    static NSString* currentLanguage = nil;
    if (currentLanguage == nil) {
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        NSArray* languages = [defaults objectForKey:@"AppleLanguages"];
        currentLanguage = [[languages objectAtIndex:0] retain];
    return currentLanguage;
Now for the CWTranslatedString() function. The JSON 
response from Google Translate is well formatted with no line breaks, so
 let's not bother with a proper JSON-parser. We can use a simple NSScanner,
 and just return the source string for any unexpected result. We also 
short circuit and return the source string if the source and dest 
language as equal. 
NSString* CWTranslatedString(NSString* string, NSString* sourceLanguageIdentifier) {
    static NSString* queryURL = @"";
    if (sourceLanguageIdentifier == nil) {
        sourceLanguageIdentifier = @"en";
    if ([sourceLanguageIdentifier isEqual:CWCurrentLanguageIdentifier()] || string == nil) {
        return string;
    NSString* escapedString = [string stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSString* query = [NSString stringWithFormat:queryURL,
                       escapedString, sourceLanguageIdentifier, CWCurrentLanguageIdentifier()];
    NSString* response = [NSString stringWithContentsOfURL:[NSURL URLWithString:query]
                                                  encoding:NSUTF8StringEncoding error:NULL];
    if (response == nil) {
        return string;
    NSScanner* scanner = [NSScanner scannerWithString:response];
    if (![scanner scanUpToString:@"\"translatedText\":\"" intoString:NULL]) {
        return string;
    if (![scanner scanString:@"\"translatedText\":\"" intoString:NULL]) {
        return string;
    NSString* result = nil;
    if (![scanner scanUpToString:@"\"}" intoString:&result]) {
        return string;
    return result;
And that is it. Not perfect, but nice to have. 

No comments:

Post a Comment

Submit Express Inc.Search Engine Optimization Services