I have a working ios app in my hand. My company wants me to provide a "Translate" button in the app that would make it Arabic. Can I do this with iOS Localisation? The app is live in app store and I have to start with Localisation work now
You can access to localization strings in specific language, but in this case you need to implement your own function instead of NSLocalizedString. Here is an example:
NSString *Localized(NSString *key) {
static NSBundle *localizationBundle = nil;
static dispatch_once_t onceToken1;
dispatch_once(&onceToken1, ^
{
NSString *languageCode = [[NSLocale currentLocale] objectForKey:NSLocaleLanguageCode]; //The language code you need
localizationBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:languageCode ofType:#"lproj"]];
});
NSString *string = [localizationBundle localizedStringForKey:key value:nil table:nil];
return string; }
Just reload localizationBundle every time user switches language by translate button
Related
This is likely not limited to iOS Universal Frameworks but all xxx.framework files. However I can't seem to find documentation on how to get the current version and build of a framework within the client application. Within an app you'd use something like:
NSString *name = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleDisplayName"];
NSString *build = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleVersion"];
NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"];
That would give you the current information stored in the Info.plist for the app. But how to we find that information for a framework. And in my case, specifically an embedded framework.
Here's a solution that does work with Universal Frameworks. Just replace SomeFrameworkClass with a class from the desired framework.
if let sdkVersion = Bundle(for: SomeFrameworkClass.self).infoDictionary?["CFBundleShortVersionString"] {
// sdkVersion is available here
}
I have found that Apple's new Cocoa Touch frameworks supported in Xcode 6, offer an easy answer to this problem. In the default header file created for you, something like Framework.h, you'll see two constants declared for you. These are defined later presumably at runtime by internal framework logic. But I have confirmed they're pulled from the plist for the framework.
//! Project version number for LocalSearch.
FOUNDATION_EXPORT double FrameworkVersionNumber;
//! Project version string for LocalSearch.
FOUNDATION_EXPORT const unsigned char FrameworkVersionString[];
Let's say Foo is a class from the given framework, you can use something like :
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [Foo class]] infoDictionary];
NSString *name = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleNameKey];
NSString *version = [infoDictionary valueForKey:(__bridge NSString*)kCFBundleVersionKey];
NSLog(#"%# version %#", name, version);
In Swift :
// `Foo` is a type defined in the framework
if let infos = Bundle(for: Foo.self).infoDictionary,
let name = infos[kCFBundleNameKey as String],
let version = infos[kCFBundleVersionKey as String] {
print("Using \(name) version \(version)")
if let shortVersion = infos["CFBundleShortVersionString"] as? String {
print("Short version : " + shortVersion)
}
}
Note : For some reason, "CFBundleShortVersionString" is not defined in a constant, cf Is there a constant defined for CFBundleShortVersionString in iOS/MacOS framework
This is for who may want to have a function on your framework that returns or print on the console it's version with build number. Just make sure you are using the class you are sharing on your Framework.h when declaring the *infoDictionary. In my example I'm using a class named cloud
+(NSString *)frameWorkVersion {
NSDictionary *infoDictionary = [[NSBundle bundleForClass: [cloud class]] infoDictionary];
NSString *version = [infoDictionary objectForKey:#"CFBundleShortVersionString"];
NSString *build = [infoDictionary objectForKey:(NSString *)kCFBundleVersionKey];
NSString *fVersion = [NSString stringWithFormat:#"%#.%#",version,build];
NSLog(#"Framework Version %#",fVersion);
return fVersion; }
Let say I already put everything on Localizable.strings for several language. As for now I use NSLocalizedString and it return the text based on [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"] setting. Now I need to get specific string for each language.
Let say I want to put it on select language setting and show it when user press Submit button. So it will show a dialog with a message "Select this language?" on respective language that user select.
You can get any translation from any language file by loading it manually:
- (NSString *)localizedString:(NSString *)string forCountry:(NSString *)countryCode {
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"Localizable" ofType:#"strings" inDirectory:nil forLocalization:countryCode];
NSBundle *dataBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
return NSLocalizedStringFromTableInBundle(string, #"Localizable", dataBundle, nil); }
Does this help?
I am looking to get the base value or english value for a localized string from a .string file. I am showing the user in the view controller the localized string but my function uses the base value or english value. I have searched everywhere but I cannot find a solution for this.
It depends on how you show your localized string. If you are using something as below you can update code:
-(NSString *)languageSelectedStringForKey:(NSString *) key showKey: (BOOL) show
{
NSString *language = [[NSString alloc] init]
if (!show)
language = [[NSUserDefaults standardUserDefaults] stringForKey:#"Language"];
else
return key;
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:#"lproj"];
if ( !path )
return NSLocalizedString(key, nil);
return [[NSBundle bundleWithPath:path] localizedStringForKey:(key) value: #"" table:nil];
}
So where you need, you can show only key (your base value)..
I want to use iOS 7 new speech synthezis API, and my application is localized in french & english.
For this to work, 2 things have to be localized :
speech text : I put it in usual localizable.string file, and retrieve it in code using NSLocalizedString macro.
speech language : AVSpeechSynthesisVoice has to be chosen for corresponding language.
Class instanciation method is AVSpeechSynthesisVoice voiceWithLanguage:(NSString *)lang.
I'm currently using [NSLocale currentLocale].localeIdentifier as parameter for this method.
Problem : if user's device language is Portuguese, [NSLocale currentLocale] select portuguese prononciation, while text resolved by NSLocalizedString is english.
How can I know which locale is currently read by NSLocalizedString ?
Ok, I finally managed to make sense of Apple APIs :
[NSLocale currentLocale] : DOESN'T return current language picked by User in Settings > General > international, but returns the region code selected by user in same screen.
[NSLocale preferredLanguages] : This list DOES give device language, it's the first string in this list
[[NSBundle mainBundle] preferredLocalizations] return language bundle resolved by application. I guess this is what NSLocalizedString uses. It only has 1 object in my case, but I wonder in which cases it can have more than one.
[AVSpeechSynthesisVoice currentLanguageCode] returns the system predefined language code.
[AVSpeechSynthesisVoice voiceWithLanguage:] class instanciation method needs complete language code : with language AND region. (e.g. : passing #"en" to it will return nil object, it needs #"en-US", or #"en-GB"... )
[AVSpeechSynthesisVoice currentLanguageCode] gives default voice, determined by OS.
So this is what my final code looks like
// current user locale (language & region)
NSString *voiceLangCode = [AVSpeechSynthesisVoice currentLanguageCode];
NSString *defaultAppLang = [[[NSBundle mainBundle] preferredLocalizations] firstObject];
// nil voice will use default system voice
AVSpeechSynthesisVoice *voice = nil;
// is default voice language compatible with our application language ?
if ([voiceLangCode rangeOfString:defaultAppLang].location == NSNotFound) {
// if not, select voice from application language
NSString *pickedVoiceLang = nil;
if ([defaultAppLang isEqualToString:#"en"]) {
pickedVoiceLang = #"en-US";
} else {
pickedVoiceLang = #"fr-FR";
}
voice = [AVSpeechSynthesisVoice voiceWithLanguage:pickedVoiceLang];
}
AVSpeechUtterance *mySpeech = [[AVSpeechUtterance alloc] initWithString:NSLocalizedString(#"MY_SPEECH_LOCALIZED_KEY", nil)];
frontPicUtterance.voice = voice;
This way, a user from NewZealand, Australien, GreatBritain, or Canada will get the voice that correspond most to his usual settings.
Vinzzz's answer was a great start -- I've generalised it to work with any language:
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
NSString *voiceLangCode = [AVSpeechSynthesisVoice currentLanguageCode];
if (![voiceLangCode hasPrefix:language]) {
// the default voice can't speak the language the text is localized to;
// switch to a compatible voice:
NSArray *speechVoices = [AVSpeechSynthesisVoice speechVoices];
for (AVSpeechSynthesisVoice *speechVoice in speechVoices) {
if ([speechVoice.language hasPrefix:language]) {
self.voice = speechVoice;
break;
}
}
}
There are some features within my application that are supposed to be based on the language settings of the device where it's running.
I want to get the actual language and not some country settings. Foe example, if the language is English, I don't care if it's US, UK, Australia, etc...
I'm familiar with the NSLocale object, but it seems to relate to the Region Format setting and not to the Language setting (see screen shot below) so when I try to retrieve the language out of it using [locale displayNameForKey:NSLocaleIdentifier value:[locale localeIdentifier] I get things like English (United States) instead of English; also, I think that what I need is the Language data and not the Region Format (am I right?).
Can anyone direct me to how to retrieve the language setting?
User preferred languages are stored can be retrieved from locale as array and current language identifier is the first object in that array:
NSString *currentLanguage = [[NSLocale preferredLanguages] objectAtIndex:0];
If you want language in more readable form then use displayNameForKey:value: method of NSLocale:
NSString *langID = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *lang = [[NSLocale currentLocale] displayNameForKey:NSLocaleLanguageCode value:langID];
Try this:
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
NSArray* arrayLanguages = [userDefaults objectForKey:#"AppleLanguages"];
NSString* currentLanguage = [arrayLanguages objectAtIndex:0];
Getting language and region in Swift:
LF.log("language", NSLocale.preferredLanguages())
LF.log("locale", NSBundle.mainBundle().preferredLocalizations)
In my case I'm getting:
language: '(
"zh-Hans"
)'
locale: '(
en
)'
In Swift 4:
let currentLanguage = Locale.current.languageCode
It will give you just the language code, no country code.
Swift:
let language = NSBundle.mainBundle().preferredLocalizations[0] as NSString
Working solution:
let language = NSLocale.preferredLanguages()[0]
let languageDic = NSLocale.componentsFromLocaleIdentifier(language) as NSDictionary
//let countryCode = languageDic.objectForKey("kCFLocaleCountryCodeKey")
let languageCode = languageDic.objectForKey("kCFLocaleLanguageCodeKey") as! String
print(languageCode)
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
Find the solution in XCode's helper document, it wrote:
Getting the Current Language
To get the language that the app is using from the main application bundle, use the preferredLocalizations method in the NSBundle class:
NSString *languageID = [[NSBundle mainBundle] preferredLocalizations].firstObject;
Use below code to fetch Localised language without having trouble to the en-india, en-us etc..
NSString *Ph = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
In and After ios9 this code need to take in cosideration
To know the current language selected within your localizations use
[[NSBundle mainBundle] preferredLocalizations]
Example:
NSString *language = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];
To get two letter word
NSString *language = [[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0] substringToIndex:2];
Swift:
let language = NSBundle.mainBundle().preferredLocalizations.first as NSString