Localisation Settings Not Changing the System Defined Text in Swift 4.2 - ios

I have 2 lang support for my app
1) English - en
2) German - de
I have done all the procedures for localization, the only issue is
whenever I change the language from "en" to "de" or vice versa then
after the system text is not changing to the latest lang, but it
reflects when I kill the app and reopen it.
For Example:
The popover Copy-LookUp-Share is not localsied to German Lang. but the other things from .string file are lcoalised properly.
My change lang code:
func setLanguage(languageCode:String) {
var appleLanguages = UserDefaults.standard.object(forKey: "AppleLanguages") as! [String]
appleLanguages.remove(at: 0)
appleLanguages.insert(languageCode, at: 0)
UserDefaults.standard.set(appleLanguages, forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
if let languageDirectoryPath = Bundle.main.path(forResource: languageCode, ofType: "lproj") {
bundle = Bundle.init(path: languageDirectoryPath)
} else {
resetLocalization()
}
}
func resetLocalization() {
bundle = Bundle.main
}
FYI: Similar thing happens in 'WeChat' iOS application.

Those are UIKit SDK private menu items and you cannot control them, probably they are just created once then kept cached.
The only thing you can try is to force update in the moment of language change, like
UIMenuController.shared.update()
Note: actually using "AppleLanguages" key for that purpose is not documented, so it is kind of hucky. L10N is system settings originated feature, by design.

Related

Swift - how to get ios device current language

My device running iOS 12 and has English language as its primary language and Hebrew as it's secondary language.
Now I'm opening my application with English as it's Base localization.
In the application I have list of three languages: English, Hebrew and French.
At first the attribute Locale.preferredLanguages result is: ["en-IL", "he-IL", "fr-IL"]
If I want to localize my entire application without to change the operating system language I'm changing only AppleLanguages array on UserDefaults like that:
func currentAppleLanguage() -> String {
return (UserDefaults.standard.object(forKey: "AppleLanguages") as? NSArray)?
.firstObject as? String ?? ""
}
func setAppleLanguageTo(lang: String) {
UserDefaults.standard.set([lang], forKey: "AppleLanguages")
}
And after I make that change I'm restarting my application and the language changes.
The thing is after I change AppleLanguages at UserDefaults for example to "he", the Locale.preferredLanguages attribute turns into: ["he"]
So now I don't have the preferredLanguages fallback localizations that set on the operating system at the settings application.
Moreover, I'd like to now how can I get the current running device language on the operating system even after I change the application language with AppleLanguages like facebook does
I'd like to mention I notice that when I edit the running scheme of Application Language to another language it changes the AppleLanguages as well.
Instead of replacing the array of "AppleLanguages" with just a single value, update the existing list so the specified language is moved to the top.
func currentAppleLanguage() -> String {
return UserDefaults.standard.stringArray(forKey: "AppleLanguages")?.first ?? ""
}
func setAppleLanguageTo(lang: String) {
// Get the current list
var languages = UserDefaults.standard.stringArray(forKey: "AppleLanguages") ?? []
// Get all locales using the specified language
let matching = languages.filter { $0.hasPrefix(lang) }
if matching.count > 0 {
// Remove those entries from the list
languages.removeAll { $0 == lang }
// Add them back at the start of the list
languages.insert(contentsOf: matching, at: 0)
} else {
// It wasn't found in the list so add it at the top
languages.insert(lang, at: 0)
}
UserDefaults.standard.set(languages, forKey: "AppleLanguages")
}
This keeps the full list. It just reorders the values so the desired language is first.

Localized text not showing for Privacy alert in iOS

I am developing an iOS application which supports English and Arabic. User can change the application language from inside the app.
When user changes the language I am setting it like ,
//change app language
UserDefaults.standard.set([language], forKey: "AppleLanguages")
currentLanguage = language
UserDefaults.standard.synchronize()
//current language updating
var currentLanguage : String{
get{
if let selectedLanguage = UserDefaults.standard.string(forKey: "selectedLanguage"){
return selectedLanguage
}else{
let language = Locale.preferredLanguages[0]
if language.hasPrefix("ar"){
return SupportedLanguage.ar.rawValue
}else{
return SupportedLanguage.en.rawValue
}
}
}
set{
UserDefaults.standard.setValue(newValue, forKey: "selectedLanguage")
}
}
In this way, App is not exiting. Just reloading the root view controller
The issue I am facing is, when I change the application language like this, the privacy alerts like “..requesting permission for using Location”, “… would ,like to use Photo album” etc are not showing in the selected language. I have created InfoPlist.string files for English and Arabic and added like
NSCameraUsageDescription = ".... would like to access Camera";
NSLocationAlwaysAndWhenInUseUsageDescription = ".... wants to use your current location for better usability";
Still its not showing. Also I tried deleting, cleaning app, deleting derived data.
Any idea why its happening?
Changing AppleLanguages key needs app to be restarted so new localization applied , you can try to use NSLocalizedString with tableName or change current bundle you read from , but system localization won't be changed until app restarted

Set Language in Swift 3 failed [duplicate]

This question already has answers here:
How to force NSLocalizedString to use a specific language
(28 answers)
Closed 5 years ago.
Sir.
I am trying to create an app of multi-language support. I use the abbreviations like zh-Hant, en , jp to save as user default. And change the language of the app. Taking place holder of textfield as an example, if I click the collection view item, the text of place holder of textfield will change. However , I can't do this. The simulator language is English as default
Here is my work in-progress :
Localisation File : Japan (jp)
"User Email"; = "ユーザーメール";
Set Text method
let lcode : String = self.langList[indexPath.item].code
print("You selected cell #\(indexPath.item) and code : \(lcode)")
UserDefaults.standard.setValue(lcode, forKey: "lang")
txtUsername.placeholder = "User Email".localized(lang: lcode)
String exntension
extension String {
func localized(lang:String) ->String {
if let path = Bundle.main.path(forResource: lang, ofType: "lproj") {
if let bundle = Bundle(path: path) {
return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "")
}
}
return "";
}
The language of the app is dependant on the device language. To test the localized string, change your device language. Otherwise, though this is not recommended, you can change your app language on runtime by adding UserDefaults.standard.set("zh", forKey: "AppleLanguages") to your ViewController. But you will have to restart the app to see the language changes.

Change app language at run time

I am trying to change the the lang that I get with NSLocalizedString at run time.
I know that this question as been already asking, but I do not find an answers for Swift 3.
I have try:
UserDefaults.standard.removeObject(forKey: "AppleLanguages")
UserDefaults.standard.set("en", forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
and:
let language = "en"
let path = Bundle.main.path(forResource: language, ofType: "lproj")
let bundle = Bundle(path: path!)
let string = bundle?.localizedString(forKey: "AppleLanguages", value: language, table: nil)
but nothing works....
Thank you for your help!
So at the end, I've used a custom localisator class available on Github, which allow you to switch language from anywhere in the app and even save if for further launches of the app.
It is written in swift 2.2, but Xcode automatically update the code to Swift 3. Just had to change at to places in the Demo:
notification.name == kNotificationLanguageChanged
to:
notification.name.rawValue == kNotificationLanguageChanged
https://github.com/micazeve/iOS-CustomLocalisator

Force NSLocalizedString to use a specific language using Swift

With swift, how can I force my app to read data from a specific Localizable.strings.
I put this in didFinishLaunchingWithOptions before instantiate the ViewController but it still show me the App in English.
NSUserDefaults.standardUserDefaults().removeObjectForKey("AppleLanguages")
NSUserDefaults.standardUserDefaults().setObject("fr", forKey: "AppleLanguages"
NSUserDefaults.standardUserDefaults().synchronize()
And I tried to pass an Array for the "AppleLanguages" key like this but it still doesn't work:
NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages"
And once this is done, can I call this inside the App and take the changes in consideration without restarting the App?
It's not possible to change app's language immediately by changing the value of AppleLanguages. It requires restarting the app before the change takes effect.
It seems that your problem is accessing the localization strings of different languages rather than changing the app's language, right? If you want your app to support multiple languages, you can just provide the translations and rely on settings.app for the actual change.
If you want to access the localization strings from other than currently used localization, you need to get access to the proper translations bundle. And then just query that bundle for the translations. The following piece of code should do the trick.
let language = "en"
let path = Bundle.main.path(forResource: language, ofType: "lproj")
let bundle = Bundle(path: path!)
let string = bundle?.localizedStringForKey("key", value: nil, table: nil)
With NSLocalizedString you can specify the bundle.
let language = "fr"
let path = Bundle.main.path(forResource: language, ofType: "lproj")!
let bundle = Bundle(path: path)!
let localizedString = NSLocalizedString(key, bundle: bundle, comment: "")
Or with a bundle, you may also call localizedStringForKey:value:table: directly too.
#Radu I also made this working for XCUITests thanks to #Markus' original answer :
You can specify explicitly the path to your MainBundle, it will only work on your Mac with the Simulator, but it is often used in continuous integration platforms so this might be acceptable :
let language: String = "en"
let path = "/Users/{username}/{path_to_your_project}/\(language).lproj"
let bundle = Bundle(path: path)
let string = bundle?.localizedString(forKey: "key", value: nil, table: nil)
In swift 4, I have solved it without needing to restart or use libraries.
After trying many options, I found this function, where you pass the stringToLocalize (of Localizable.String, the strings file) that you want to translate, and the language in which you want to translate it, and what it returns is the value for that String that you have in Strings file:
    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }
Taking into account this function, I created it as global in a Swift file:
struct CustomLanguage {
func createBundlePath () -> Bundle {
let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
return Bundle(path: path!)!
}
}
To access from the whole app, and in each string of the rest of ViewControllers, instead of putting:
NSLocalizedString ("StringToLocalize", comment: “")
I have replaced it with
let customLang = CustomLanguage() //declare at top
NSLocalizedString("StringToLocalize", tableName: nil, bundle: customLang.createBundlePath(), value: "", comment: “”) //use in each String
I do not know if it's the best way, but I found it very simple, and it works for me, I hope it helps you!

Resources