I'm having trouble accessing localized resources from my Intents extension.
I've got a couple of JSON files that are localized into different languages in a framework that's shared between my app and the extension. When I access them though my app via path(forResource:ofType), it accesses the proper localized version, but if I call it from the extension in the Shortcuts app, then it returns the English, even if both the app itself and the Shortcuts app are both set to another language.
The only way I can get the correct language to appear is if I change the device language - changing it just for the app or for Shortcuts doesn't have an effect.
I'm building with the iOS 14 SDK, but the same behavior occurs on both iOS 13 and 14.
Firstly, please check Target Membership of Localizable file, make sure it was checked your extension.
Secondly, save your app language in UserDefaults which have AppGroups.
static func setLanguageExtension(_ language: String, forKey: String) {
if let userDefault = UserDefaults(suiteName: "APP_LANGUAGE") {
userDefault.setValue(language, forKey: forKey)
}
}
static func getLanguageExtension(key: String) -> String? {
if let userDefault = UserDefaults(suiteName: "APP_LANGUAGE") {
return userDefault.string(forKey: key)
} else {
return "en-US"
}
}
Related
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.
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.
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
I cannot pass data call directory extension from main app
I've created one App group and turned it on in App capabilities for both targets (main app and extension)
I pass data with NSUser
-Create Data in main app
var userDefaults = UserDefaults(suiteName: "group.test.callapp")
userDefaults?.set("mynumber", forKey: "mykey")
-Retrieve Data in extension
var baseDescription = "test"
let newUserDefaults = UserDefaults(suiteName: "group.test.callapp")
if let testUserId = newUserDefaults?.object(forKey: "mykey") as? String
{
baseDescription = testUserId
}
When i do it in only main app - everything is ok, but when i do it in extension (i do it in 'addIdentificationPhoneNumbers' function) - it doesn't work, baseDescripton doesn't change
Your solutions shoud work, the only problem I can see is that you don't have App Groups enabled (with your "group.test.callapp" group) both for your application and the extension. Check Target->Capabilities if this is enabled for both. Another caveat is to pass the phone number in the international format (with country code).
I'm trying to add TodayExtension to my existing app and I want that app and extension will share data through NSUserDefaults.
According to this tutorial http://www.glimsoft.com/06/28/ios-8-today-extension-tutorial/
I did like it say:
Create new target with Today extension
Add new App-Group in Extension and App
Add code to app
Add code to extension
App Code
func updateExtensionData() {
let key = "identityCode"
let valueForStore:Float = 2.0
let extensiontDefaults = NSUserDefaults(suiteName: "group.company.mineSharedDefaults")
extensiontDefaults?.setFloat(valueForStore, forKey: key)
let results = extensiontDefaults?.synchronize()
let checkCode = extensiontDefaults?.objectForKey(key)
print("code for save \(valueForStore) synchronize result \(results) readed code \(checkCode!)")
}
Extension code
private func updateData() {
let key = "identityCode"
let extensionDefaults = NSUserDefaults(suiteName: "group.company.mineSharedDefaults")
let checkCode = extensionDefaults?.floatForKey(key)
print("synchronize result \(resut) readed code \(checkCode!)")
}
Issue
My issue is that extension always read 0 instead of 2. Clearly I'm missing something. There is some major difference between iOS8 and 9 in case of AppGroup and NSUserDefaults? I know that there is but between app an watchOS2.
For being more clear this is keys from App and Extension NSUserDefaults
App Keys
AppleKeyboards
AppleKeyboardsExpanded
AddingEmojiKeybordHandled
AppleLanguages
ApplePasscodeKeyboards
PreferredLanguages
AppleLocale
NSInterfaceStyle
MSVLoggingMasterSwitchEnabledKey
NSLanguages
AppleITunesStoreItemKinds
identityCode
AppleLanguagesDidMigrate
PKEnableStockholmSettings
Extension Keys
AppleKeyboards
AppleKeyboardsExpanded
AddingEmojiKeybordHandled
AppleLanguages
ApplePasscodeKeyboards
PreferredLanguages
AppleLocale
NSInterfaceStyle
MSVLoggingMasterSwitchEnabledKey
NSLanguages
AppleITunesStoreItemKinds
AppleLanguagesDidMigrate
PKEnableStockholmSettings
It's clear that key identityCode is not appearing in extension at all.
Ok I'm not sure what helps but I've done two thing:
rename current AppGroup identifier and create new one with name group.my.entire.bundle.id.of.my.app.sharedData instead of group.appname.sharedData
remove and create new AppGroup identifier
I can use "identityCode" as key.
CThere could be several things!
first; did you allow keychain sharing under "Capabilities" for both your container app and the extension, and did you set the Keychain groups to the same group?
I recommend using this: https://github.com/kefbytes/KeychainWrapper
download it, it's very simple, just add the swiftfile to your project
allow keychain sharing under cabailities,
set your serviceName and accesgroup like this
KeychainWrapper.serviceName = "give it a name in here"
(servicename is neccessary for it to work)
KeychainWrapper.accessGroup = "write your accessgroup name here"
(accesgroup is optional, since you are setting it under Capabilities)
save a value to a key like this
KeychainWrapper.setString("2", forKey: "identityCode"
and retrieve with
KeychainWrapper.stringForKey("identityCode")