Currently, the generated code uses the NSLocale.currentLocale() in formatted strings, which is the locale the users device is set to.
However, an app can override this to a different preferred language, e.g. by setting AppleLanguage or AppleLocale in the user defaults.
This preferred language is used by NSLocalizedString, but it doesn't change currentLocale.
This example demonstrates the problem:
// nl.proj/Localizable.strings
"someKey" = "Dutch: %.1f"
// en.proj/Localizable.strings
"someKey" = "English: %.1f"
Generated Swift code:
static func someKey(_: Void) -> String {
return String(format: NSLocalizedString("someKey", comment: ""), locale: NSLocale.currentLocale(), 1234.5)
}
On a Dutch device, with AppleLanguages set to ["en"], we see a mix of Dutch and English decimal marks. Instead of everything in English.
Expected: "English: 1,234.5" (English string and English decimal mark)
Result: "English: 1.234,5" (English string and Dutch decimal mark)
@tomlokhorst Do you know how other library/tools or even a normal app project work with this? We just generate code in the app so a normal app should have the same problems right?
I'm unsure what the best practices are for doing this. I'll look into it some more.
Found this StackOverflow answer: http://stackoverflow.com/a/21937800/586489 Seems preferredLocalizations does respect the environment variables you describe and takes into account the languages the app supports.
Note that preferredLanguages is not what is app is running in, but preferredLocalizations is according to this blog: http://mjtsai.com/blog/2014/12/09/nslocale-preferredlanguages-vs-nsbundle-preferredlocalizations/
This blog also seems interesting with a lot of information: http://maniak-dobrii.com/understanding-ios-internationalization/
Objc.io also has a clear and interesting take on this: https://www.objc.io/issues/9-strings/string-localization/#choosing-the-right-locale
Ultimately it comes down to your judgment of what makes the most sense for a specific use case, but you might want the app鈥檚 interface to be localized consistently in some cases. In order to retrieve the locale your app is currently using instead of the user鈥檚 systemwide locale, we have to ask the main bundle for its preferred language:
NSString *localization = [NSBundle mainBundle].preferredLocalizations.firstObject;
NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:localization];
Conclusion:
If we want to be consistent with the language the app is running in we should use preferredLocalizations from the bundle. If we want to be consistent with the operation system itself we should use currentLocale from NSLocale. I seems to me that in R.swift we want to use preferredLocalizations, so we should change to that I think.
Hi @mac-cain13, thanks again for the great library!
I normally prefer to use the Locale.currentas it makes sure numbers are formatted like the user is used to (and prefers). In an app I'm working on right now I have a couple of localized strings with Int parameters. As the development language of my app is set to 'en' (which is correct), I now get commas as thousands-separator. My own phone is set to en_NL and I prefer to have a period as the separator.
Of course I understand the request in this thread, so would it be possible to add a (command line) config parameter to set the preferred order of the locales?
fileprivate static let applicationLocale = hostingBundle.preferredLocalizations.first.flatMap(Locale.init) ?? Locale.current
I have now 'fixed' it with an extra Run Script phase after R.swift, which does the trick as well..
/usr/bin/sed -i '' 's/hostingBundle.preferredLocalizations.first.flatMap(Locale.init) ?? Locale.current/Locale.current/' "$SRCROOT/R.generated.swift"
@rbresjer There's an open issue for choosing a specific locale for localised strings: https://github.com/mac-cain13/R.swift/issues/219
Does that cover your use case?
@tomlokhorst Thanks for your reply. Not entirely, because I'd like to have the rest of the string in the auto-detected locale.. But my current workaround works good enough.