Caplin YT
Caplin YT

Reputation: 265

What is the best way to handle Booleans?

My app is available in German, There are around 30 Xcode generated Localizable.strings files (means app is available in 30 more languages) i'm slowly converting to swift structs, personal opinion.

struct German {
    let contacting_app_services: String = "Kontaktiere App Service.."
    let validating_user: String = "Validiere Nutzer"
    let email_in_use: String = "Diese e-mail wird bereits von einem andern Konto genutzt"
    let account_not_found: String = "Nutzerkonto nicht gefunden. Bitte prüfen und nochmals versuchen"
    let valid_email: String = "Bitte geben Sie eine gültige e-mail Adresse ein"
}

Now, I check if the device is in German:

extension Locale {
    func isGerman() -> Bool {
        return Locale.preferredLanguages[0].range(of:"de") != nil
    }
}

And update my UI with:

if Locale.current.isGerman() {
    self.errorLabel.text = German().valid_email
}

What i'm trying to do:

Upvotes: 0

Views: 93

Answers (2)

Alexander
Alexander

Reputation: 63264

Don't do this. Even if you have some inexplicable repulsion to the localization tools already built into the system, don't do this.

Just imagine what I night mare you would run into if you had to support multiple languages. Imagine you wanted to add support for the 6 official languages of the UN.

if Locale.current.isArabic {
    self.errorLabel.text = Arabic().valid_email
}
else if Locale.current.isChinese {
    self.errorLabel.text =  Chinese().valid_email
}
else if Locale.current.isEnglish {
    self.errorLabel.text =  English().valid_email
}
else if Locale.current.isFrench {
    self.errorLabel.text = French().valid_email
}
else if Locale.current.isGerman {
    self.errorLabel.text = German().valid_email
}
else if Locale.current.isRussian {
    self.errorLabel.text = Russian().valid_email
}
else if Locale.current.isSpanish {
    self.errorLabel.text = Spanish().valid_email
} else {
    // What would you even put here?
}

What an absolute disaster. There are so many issues with it:

  1. You would end up repeating this if/else if/else ladder at every place where you want a localized string!
  2. What do you put in the else case? A default language?
  3. What if you ever change your mind about what to do in the else case? Are you going to go back and change it every where?
  4. What if you want to add a new language? Are you going to go back and add it in everywhere? What if you forget a call site?
  5. How will this look when you want to support 30 languages?

That's obviously a complete non-starter.

Instead, use polymorphism to pick the right string for you:


protocol LocalizedStrings {
    var contactingAppServices: String { get }
    var validatingUser: String { get }
    var emailInUse: String { get }
    var accountNotFound: String { get }
    var validEmail: String { get }
}

struct EnglishLocalizedStrings: LocalizedStrings {
    let contactingAppServices = "Contacting App Services, please wait."
    let validatingUser = "Validating user, please wait."
    let emailInUse = "This e-mail is already in use."
    let accountNotFound = "Account not found."
    let invalidEmail = "This e-mail is not valid"
}

struct ArabicLocalizedStrings: LocalizedStrings {
    // ...
}

// Somewhere in the initalization of your app 
let localizedStrings: LocalizedString = PickTheRightLocalizationStringsObjectForTheUser() 

// somewhere where you need localized strings: 
self.errorLabel.text = localizedStrings.validEmail

And then you can just rely on the dynamic dispatch mechanism to do the branching for you to pick the right string for the job, rather than manually enumerating each possible case yourself, everytime.

Upvotes: 2

Caplin YT
Caplin YT

Reputation: 265

I'd go with:

protocol Translations {
    var valid_email: String { get }
}

struct German: Translations {
    var valid_email: String = "Bitte geben Sie eine gültige e-mail Adresse ein"
}

struct English: Translations {
    var valid_email: String = ""
}

extension Locale {
    static func isGerman() -> Bool {
        return Locale.preferredLanguages[0].range(of:"de") != nil
    }

    static func language() -> Translations {
        if isGerman() {
            return German()
        }
        return English()
    }
}

Usage:

let errorLabel = UILabel()
errorLabel.text = Locale.language().valid_email

Upvotes: 0

Related Questions