Our DNA is written in Objective-C
Jump

Introducing the POEditor.com API and Tool

If you want to be successful in international markets you need to localize your app in as many languages as you can. For iWoman we use POEditor.com. As the number of localization grows it becomes increasingly time-consuming to update all localizations in your Xcode project, let alone deal with plurals which are not supported in the XLIFF format.

Today I am showing off, how I got the update process to be a matter of seconds. I achieved this by writing a POEditor.com API and building a command line tool – I call POET (for POEditor Tool) which greatly simplifies the update process.

BSA Banner

By writing the API wrapper in Swift 3 I was able to leverage some great new features of the language, in particular the ability to have generic type aliases. I also used what I learned researching the Result pattern, which I had researched for a previous talk.

The POEditorAPI project is on GitHub and I invite you to check it out and by any means help extend it. So far I have implemented four API functions, but it is easy add additional ones, mostly copy/pasting and adjusting the parameters and expected result types.

I am giving a tour of the project and showing it in action in this video:

I am particularly proud of discovering an elegant way of URL-encoding the form fields for the body of the HTTP POST. The URLComponents class does that for us.

import Foundation

extension URLRequest
{
   static func formPost(url: URL, fields: [String: Any]) -> URLRequest
   {
      var request = URLRequest.init(url: url, timeoutInterval: 10.0)
      request.httpMethod = "POST"
      request.setValue("application/x-www-form-urlencoded",
                       forHTTPHeaderField: "Content-Type")

      // URL-encode form fields
      var components = URLComponents()

      components.queryItems = fields.map { (key, value) -> URLQueryItem in
         return URLQueryItem(name: key, value: "\(value)")
      }

      // create form post data and length
      let data = components.url!.query!.data(using: .utf8)!
      request.httpBody = data
      request.setValue("\(data.count)", forHTTPHeaderField: "Content-Length")

      return request
   }
}

This extension for URLRequest is the core for all interaction with the POEditor API. Since all responses should be JSON I have a second extension to also take care of decoding it.

Command Line Input

POET requires user input on the command line for specifying the API token, selecting a project and specifying the translation export threshold. Turns out, this is easy in Swift 3 as well:

// get token from user if needed
if settings.token == nil
{
   // no api token
   print("Enter POEditor API Token> ", terminator: "")
   settings.token = readLine(strippingNewline: true)
}

Note the terminator parameter on the print function. This defaults to \n but if you pass an empty string the curser remains in the same line, awaiting user input.

You cannot embed dynamic frameworks in command line binaries. So I just added the source of POEditorAPI to the command line utility target. But for platforms that do support dynamic frameworks you can simply embed the iOS or macOS framework. It is also available on Cocoapods.

Conclusion

Other famous tools, use web development languages like Ruby or JavaScript. But I live and breathe Swift and so I wanted to have my own API and command line utility written in my favorite language.

I believe you will find it instructive how I structured the API calls, using the Result programming pattern, generics and some other modern approaches. I would love to hear your comments and if you want to use the project in an app of yours.

Above all, I hope that you – if you are also a user of POEditor.com – can automate your update process with the help of poet. What could be more poetical than time savings?


Also published on Medium.


Categories: Projects

Leave a Comment

%d bloggers like this: