Recently Loot’s iOS app had a bug which only occured on certain locale settings. As Loot only uses GBP at this time, we expect all payments the user makes from the app (some people call them transfers, but the accurate banking term is payments) to be formatted in the GBP way - GBP symbol immediately next to the pounds unit, period seperating pounds and pence - £23.42.

So it turned out that the bug was caused by an NSNumberFormatter taking on the locale settings of the user’s device rather then us setting it manually, which in turn caused us not to be able to read the amount of money that the user would like to make a payment in as we couldn’t read the format. Simple fix.

The interesting part was that we then started looking at how we can test against this problem in the future in our UI Tests. It turns out that running your UITests in multiple locales is very easy. It looks like this:

override func setup() {
    super.setup()
    let app = XCUIApplication() 
    app.launchArguments = ["-AppleLanguages", "(de)", "-AppleLocale", "de_DE"]
    app.launch()
}

This is the exact same as setting the local settings on your Xcode scheme.

Next we wanted to be able to run every one of our UITests in a select few locales. Again, easy:

class InternationUITests: XCTestCase {
    let testClasses: [XCTestCase.Type] = [SomeUITests.self, SomeMoreUITests.self]
    
    override func setUp() {
        super.setUp()
        continueAfterFailure = true
    }

    func runTestsInLanguage(language: String, locale: String) {
        let app = XCUIApplication()
        app.launchArguments = ["-AppleLanguages", "(\(language))", "-AppleLocale", locale]
        app.launch()
        for testClass in self.testClasses {
            for test in testClass.testInvocations() {
                let testTarget = testClass.init() // local variable as NSInvocation uses a weak pointer
                test.target = testTarget
                test.invoke()
            }
        }
        app.terminate()
    }
    
    func testInGerman() {
        self.runTestsInLanguage("de", locale: "de_DE")
    }

    func testInItalian() {
        self.runTestsInLanguage("it", locale: "it")
    }
}

Language codes

You can print out the availble language codes like this:

print(NSLocale.availableLocaleIdentifiers())