I have a project divided in layers, and the bottom one is included in the top one as a static lib.
The thing is that I need to localize a string in the static lib, using the translations present in my app (upper layer).
Is this possible somehow?
The way I managed to do this is loading the strings from a bundle instead of using NSLocalizedString:
+ (NSString *)getTranslationFromAppBundleForString:(NSString *)originalText {
NSString * lang = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString * bundlePath = [[NSBundle mainBundle] pathForResource:lang ofType:#"lproj"];
NSBundle * bundle = [NSBundle bundleWithPath:bundlePath];
return [bundle localizedStringForKey:originalText value:originalText table:nil];
}
You can create an LanguageAgent in your static library, add a bundle ressource in that library. Then use a function like this to get localizedString. In my application, I separate language by different table (see picture below for a table named 'Dictionaire'. You can have more than 1 table in your languages bundle.
-(NSString*) myLocalizedStringForKey:(NSString*) key ofTable:(NSString*)tableName {
//I save selected language in my NSUserDefaults.
NSString *selectedLanguage = [[NSUserDefaults standardUserDefaults] stringForKey:#"DefaultLanguage"];
if (selectedLanguage == nil) {
[[NSUserDefaults standardUserDefaults] setValue:#"en" forKey:#"DefaultLanguage"];
[[NSUserDefaults standardUserDefaults] synchronize];
selectedLanguage = [[NSUserDefaults standardUserDefaults] stringForKey:#"DefaultLanguage"];
}
NSString *langBundleNew = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingFormat:#"/langs/Languages.bundle/%#.lproj/",selectedLanguage]; //use your path to the Languages.bundle here.
if ([[NSFileManager defaultManager] fileExistsAtPath:langBundleNew]) {
NSBundle *aBundle = (NSBundle*)[self.dictLangueBundle objectForKey:selectedLanguage];
NSString* str=[aBundle localizedStringForKey:key value:#"[string not defined]" table:tableName];
return str;
} else {
return #"[]";
}
}
My language bundle is similar like this: ('Dictionaire' = name of the table)
Here is a sample of content in my Dictionnaire.strings for 'en.lproj':
Related
This question already has answers here:
Change Language in the app programmatically in iOS
(3 answers)
Closed 6 years ago.
In my iOS app I need an option to change language. Can we change it without changing the language in the device settings
You can use following code to set the language
- (void) setLanguage:(NSString*) lang {
NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:#"lproj"];
if (path == nil) {
myBundle = [NSBundle mainBundle];
} else {
myBundle = [NSBundle bundleWithPath:path];
}
if (myBundle == nil) {
myBundle = [NSBundle mainBundle];
}
}
And after that you can get the localizations with
- (NSString*) localizedStringForKey:(NSString*) key {
return [myBundle localizedStringForKey:key value:#"" table:nil];
}
For example store different static json/plist and etc in your app with different languages strings and when you switch option parse this and set to labels.
i am not sure but try this code once using NSUserDefaults
NSUserDefaults* userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray* languages = [userDefaults objectForKey:#"AppleLanguages"];
[languages insertObject:#"de" atIndex:0]; // ISO639-1
[[NSUserDefaults standardUserDefaults] synchronize];
So when I click "View User Record" button I want to display whatever value of Score and Live of a view controller and store it in a plist as an array. And then those values from the plist will be displayed into the table view
try this for adding value in plist file .
NSString* plistPath = nil;
NSFileManager* manager = [NSFileManager defaultManager];
if (plistPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"Contents/Info.plist"])
{
if ([manager isWritableFileAtPath:plistPath])
{
NSMutableDictionary* infoDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
[infoDict setObject:[NSNumber numberWithBool:hidden] forKey:#"LSUIElement"];
[infoDict writeToFile:plistPath atomically:NO];
[manager changeFileAttributes:[NSDictionary dictionaryWithObject:[NSDate date] forKey:NSFileModificationDate] atPath: [[NSBundle mainBundle] bundlePath]];
}
}
And This is for Get Value from plist file.
NSBundle* mainBundle = [NSBundle mainBundle];
// Reads the value of the custom key I added to the Info.plist
NSString *value = [mainBundle objectForInfoDictionaryKey:#"key"];
//Log the value
NSLog(#"Value = %#", value);
// Get the value for the "Bundle version" from the Info.plist
[mainBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
// Get the bundle identifier
[mainBundle bundleIdentifier];
i hope this code is useful for you.
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'm trying to use NSLocalizedStringFromTable but with no results. I've got created Profile.strings file, clicked localized, in project settings I add Polish and English languages, so my file has 2 "files" inside and I typed the same strings with other values but when I switch languages and restart app there is still one localization used (Polish).
Profile.strings in Xcode:
Profile.strings
Profile.strings (Polish)
Profile.strings (English)
Polish:
"fullName.placeholder" = "Imie i nazwisko";
"emailAddress.placeholder" = "Adres email";
"phoneNumber.placeholder" = "Numer telefonu";
English:
"fullName.placeholder" = "Full name";
"emailAddress.placeholder" = "Email address";
"phoneNumber.placeholder" = "Phone number";
To get value I call:
NSLocalizedStringFromTable(#"fullName.placeholder", #"Profile", #"");
Any time I call this I've got value from Profile.strings (Polish)
What I'm doing wrong?
try to Reset Content and Settings of simulator it will work (:
Maybe you're not changing the language correctly. Try doing it in code. Like this:
- (void) setLanguage:(NSString*) l{
for (NSString *language1 in [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"]) {
NSBundle *bundle1 = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language1 ofType:#"lproj"]];
NSLog(#"%#: %#", language1, NSLocalizedStringFromTableInBundle(#"left", #"Localizable", bundle1, nil));
}
NSBundle *bundle1 = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:l ofType:#"lproj"]];
/*
if ([l isEqualToString:#"en"]) {
bundle1 = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:#"English" ofType:#"lproj"]];
}
*/
if (bundle1 == nil)
//in case the language does not exists
[self resetLocalization];
else
bundle = bundle1;
NSMutableArray *langs = [NSMutableArray arrayWithArray: [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"]];
[langs removeObject:l];
NSMutableArray *newLangs = [NSMutableArray arrayWithObject:l];
[newLangs addObjectsFromArray:langs];
[[NSUserDefaults standardUserDefaults] setObject: newLangs forKey:#"AppleLanguages"];
}
And then you can do
[self setLanguage:#"en"];
I am implementing a application based on web services. In that I need to add a string as property in .plist and I need to get the value from the .plist whenever I need in the code.
Here is a code sample:
NSString *path = [[NSBundle mainBundle] pathForResource: #"YourPLIST" ofType: #"plist"];
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile: path];
id obj = [dict objectForKey: #"YourKey"];
NSBundle* mainBundle = [NSBundle mainBundle];
// Reads the value of the custom key I added to the Info.plist
NSString *value = [mainBundle objectForInfoDictionaryKey:#"key"];
//Log the value
NSLog(#"Value = %#", value);
// Get the value for the "Bundle version" from the Info.plist
[mainBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
// Get the bundle identifier
[mainBundle bundleIdentifier];
NSURL *url = [[NSBundle mainBundle] URLForResource:#"YOURPLIST" withExtension:#"plist"];
NSArray *playDictionariesArray = [[NSArray alloc ] initWithContentsOfURL:url];
NSLog(#"Here is the Dict %#",playDictionariesArray);
or you can use following also
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"Sample.plist"];
Get from plist is very simple.
NSString *path = [[NSBundle mainBundle] pathForResource:#"SaveTags" ofType:#"plist"];
if (path) {
NSDictionary *root = [NSDictionary dictionaryWithContentsOfFile:path];
}
If you want to add something to a plist, maybe you can find the answer here:
How to write data in plist?
But if you only want save some message in you app, NSUserDefaults is the better way.
You can not do this. Any Bundle wether it is iOS or Mac OS is readonly, you can only read to it and you can't create files, write or do anything with the files in a bundle. This is part of the Security features of apple. You can use the NSDocumentsDirectory to writr and read your stuff you need for your app
Swift
I know this was asked 12+ years ago. But this was the first SO question to come up via google. So to save time for everyone, here is how to do this in swift:
struct Config {
// option 1
static var apiRootURL: String {
guard let value = (Bundle.main.object(forInfoDictionaryKey: "BASE_URL") as? String), !value.isEmpty else {
fatalError("Base URL not found in PLIST")
}
return value
}
// option 2
static var databaseName: String {
guard let value = (Bundle.main.infoDictionary?["DB_NAME"] as? String), !value.isEmpty else {
fatalError("DB NAME not found in PLIST")
}
return value
}
}
Notice the 2 functions use slightly diffrent methods to access the plist. But in effect they are almost the same.
In theory there might not be a plist. Hence infoDictionary is optional. But in this case the first method will also return an unexpected value, resulting in an error.
One actual difference as noted by Apple:
Refering to Bundle.main.object(forInfoDictionaryKey: "BASE_URL")
Use of this method is preferred over other access methods because it returns the localized value of a key when one is available.