Search code examples
jsonswiftgoogle-translate

Getting first element from JSON in Swift (Google Translate)


I'm having trouble getting the first element (which contains the translation) from a JSON generated by Google Translate. I've tried to do it in various ways, such as converting the JSON to an array and working with JSONSerialization, but I haven't been able to figure it out. And though there are similar questions on this site, no answers have worked for me.

As an example, here's what generates an English-to-Spanish translation of "Hello there, I would love some help".

let toLanguage = "es"
let textToTranslate = "Hello there, I would love some help".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
let translateURL = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=" + toLanguage + "&dt=t&dt=t&q=" + textToTranslate!
        let url = URL(string: translateURL)!
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            print(String(data: data!, encoding: .utf8))
        }
        task.resume()

That print statement returns:

("[[[\"Hola, me encantaría un poco de ayuda\",\"Hello there, I would love some help\",null,null,3,null,null,[[]\n]\n,[[[\"88050b4eeda80a4gb03h2aa140d8a487\",\"en_es_2020q2.md\"]\n]\n]\n]\n]\n,null,\"en\",null,null,null,null,[]\n]\n")

I would like to store "Hola, me encantaría un poco de ayuda" as a String, and any guidance would be appreciated! Thank you in advance.


Solution

  • Here is an ugly solution that works, replace the content of your closure with

    if let data = data {
        var reply: [Any] = []
        do {
            reply = try JSONSerialization.jsonObject(with: data) as? [Any] ?? []
        } catch {
            print(error)
        }
        if let next = reply.first as? [Any] {
            if let next = next.first as? [Any] {
                if let translation = next.first as? String {
                    print(translation)
                }
            }
        }
    }
    

    You could wrap everything into a function like this

    func translate(_ phrase: String, to toLanguage: String, completion: @escaping (String?) -> ()) {
        guard let textToTranslate = phrase.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
            let url = URL(string: "https://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=" + toLanguage + "&dt=t&dt=t&q=" + textToTranslate) else {
                completion(nil)
                return
        }
    
        let task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let data = data {
                var reply: [Any] = []
                do {
                    reply = try JSONSerialization.jsonObject(with: data) as? [Any] ?? []
                } catch {
                    print(error)
                    completion(nil)
                }
                if let next = reply.first as? [Any] {
                    if let next = next.first as? [Any] {
                        if let translation = next.first as? String {
                            completion(translation)
                        }
                    }
                }
            }
        }
        task.resume()
    }
    

    That is called with a closure

    translate("Hello there, I would love some help", to: "es", completion: {
        if let reply = $0 {
            print(reply)
        } else {
            print("Translation failed")
        }
    })