Xcode 4.6 localization within plist file - objective-c

I have started adding more languages to a project of mine and got strings & graphics localized without much trouble.
I have one last problem and it is with a plist file.
This plist file holds default category names for the app and is filled with English strings in a dictionary.
My question is: is there a way to localize a plist file? I though about adding localized strings to the plist but could not figure out how.
I dont want to have to decide in code what plist file to take since the default plist file gets overwritten by the user upon first use.

Localized Plist files
Easier solution here would be to localize the entire plist. By doing so, you will have a different plist file for each supported language.
Select the plist file in your project, and select Localize in the File Inspector menu.
It will create a new folder containing a Plist file for each supported language.
From:
dummy.plist
To:
> en.lproj
> > dummy.plist
> es.lproj
> > dummy.plist
> de.lproj
> > dummy.plist
Localized Plist contents
Another solution would be to use localized strings inside the plist, and simply call NSLocalizedString before printing out the extracted string.
Imagine you had a Plist like this:
You can simply localize its strings by adding the keys to your Localizable.strings file. For example, in Spanish:
"My menu title" = "Mi título del menú";
"My menu description" = "Mi descripción del menú";
Or, my recommendation, move also your native language strings out of the Plist to a string file and replace the Plist strings with a localizable key:
And your Localizable.strings for Engligh:
"MY_MENU_TITLE" = "My menu title";
"MY_MENU_DESCRIPTION" = "My menu description";
and Spanish:
"MY_MENU_TITLE" = "Mi título del menú";
"MY_MENU_DESCRIPTION" = "Mi descripción del menú";
I've found the latest easier to maintain and easier to localize for new languages, as all the required strings are in the same file.
And finally change your code to use NSLocalizableString instead of the plain string read from the Plist file. For example, imagine you have the code:
NSDictionary* plistDict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"menuElements" ofType:#"plist"]];
menuTitleLabel.text = plistDict[#"menuTitle"];
menuDescriptionLabel.text = plistDict[#"menuDescription"];
Simply change it to:
NSDictionary* plistDict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"menuElements" ofType:#"plist"]];
menuTitleLabel.text = NSLocalizedString(plistDict[#"menuTitle"], nil);
menuDescriptionLabel.text = NSLocalizedString(plistDict[#"menuDescription"], nil);
If this is your case you could get rid of the plist file completely:
menuTitleLabel.text = NSLocalizedString(#"MY_MENU_TITLE", nil);
menuDescriptionLabel.text = NSLocalizedString(#"MY_MENU_DESCRIPTION", nil);

Related

Objective c save to my plist

I have the plist file under the resources folder which is name is logical-app.plist
In ios8 if you want Gps will work then NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys should be added into the Info.plist
I want to add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription keys in code in my appdelegate class.
Im trying to add the following code for solving this issue:
//write
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
[plistDict setValue:#"1.1.1" forKey:#"NSLocationWhenInUseUsageDescription"];
[plistDict writeToFile:filePath atomically: YES];
//endwrite
//read plist
filePath = #"/System/Library/CoreServices/SystemVersion.plist";
plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:filePath];
value = [plistDict objectForKey:#"NSLocationWhenInUseUsageDescription"];
im trying to get
filePath = [[NSBundle mainBundle] pathForResource:#"ClickMobileCDV-Info" ofType:#"plist"];
and it is nil too....
But with no success.... when i read it from the plist it was nil...
How can i solve this issue?
You've completely got the wrong end of the stick. In order to add NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription, you edit the app's plist file within Xcode and it's included in the app bundle.
There is no code needed to read/write system .plist files at runtime (the writing of which would fail anyway, due to permission errors).

Create plist first in Xcode?

I've read conflicting views on this
http://ipgames.wordpress.com/tutorials/writeread-data-to-plist-file/
If I want to use a plist to hold my tile map objects game data, do I have to create a plist with xcode first? and then update that? or do I not need to do that and I can just create it from scratch with code when the game runs?
If I don't have to create one with xcode first, what would be the benefit of doing that?
The code from your link is useful if you want some default data in the property list when the application is started for the first time.
If you don't need default data, don't have to create a property list in Xcode and include it in your application.
NSString *path = ... // path to plist file in Documents directory
NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:path];
if (plistDict == nil) {
// No plist present (or invalid contents), start with empty dictionary:
plistDict = [[NSMutableDictionary alloc] init];
}
Now you can add/modify/remove items in plistDict and save it later.

Reading Text File from Xcode Bundle

Why can't I read the content of foo.rtf? I've already put it in Xcode bundle. fileRoot still contains null.
NSString* filePath = #"foo";
NSString* fileRoot = [[NSBundle mainBundle] pathForResource:filePath ofType:#"rtf"];
NSLog(#"File root contains %#", fileRoot);
#TheAmateurProgrammer, Thank you for the diagram. I just added foo.rtf into the bundle resources. The result for fileRoot is still null. What step am I still missing?
Target's "Copy Bundle Resources" in Build Phases now contains foo.rtf. (I can't insert picture as I'm still a newbie).
(I will add the content reading after I can get fileRoot to point correctly).
You added the file, but is it really copied to your application bundle?
Make sure your rtf file is copied into your resource.
Secondly, you're only getting the path of the rtf, and not the contents of the rtf.
NSString *fileRoot = [[NSBundle mainBundle] pathForResource:filePath ofType:#"rtf"];
NSString *contents = [[[NSAttributedString alloc] initWithRTF:[NSData dataWithContentsOfFile:fileRoot] documentAttributes:NULL] string];
That will get the contents of the rtf.
First check that your file is present inside the bundle or not and if it present it must have same name as "foo.rtf".
You are getting nil because your file is not present directly inside in the bundle.
once you get the right file path you can get the content of your text file as a string by calling initWithContentsOfFile method on NSString class.

How to change localized images at run time

I have created two localized directories named with en.lproj and fr.lproj. I put two different images with same name like.png in those localized directories.
Now i have created a table View Controller with two rows "English" and "French" text respectively.
After selecting first or second row i am fetching the bundle path and changing the whole localized text of my app at run time.
Code:
-(NSString*) languageSelectedStringForKey:(NSString*) key
{
NSString *path;
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
if([[userDefault valueForKey:#"language_Selected"] intValue] == 0)
path = [[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"];
else if([[userDefault valueForKey:#"language_Selected"] intValue] == 1)
path = [[NSBundle mainBundle] pathForResource:#"fr" ofType:#"lproj"];
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str=[[languageBundle localizedStringForKey:key value:#"" table:nil] retain];
return str;
}
Through above code dynamically i can change the language of running app.
But how to get images from that bundle?
Any Idea?
Thanks
Presumably, you don't want to change every image, only the images that contain text or other culture-dependent content. For these images, you could add an entry to the localizable.strings file that contains the image path for a give language, and use this path instead of a hard-coded path.
That said, in many cases you'll have images included in the UI as part of a .xib. All you need to do in these cases is localize the xib (i.e. make a different version of the .xib per language--you can do this in XCode through the Languages control in the properties panel) and simply change the image in each language version of the .xib using Interface Builder.

Accessing a plist with a console application - Xcode 4

I've created a plist (File->New File->Resource plist) file that has a dictionary that stores floating point numbers for a console application. I've pretty much created this plist to store a few numbers to be returned by class methods, but could change so hardcoding isn't really that great of an idea. However, when I try to access the plist file, I always get "nil" for the file path and I'm not sure what I'm doing wrong.
<plist version="1.0">
<dict>
<key>minFloatNumber</key>
<real>520.0</real>
</dict>
</plist>
+ (double) minFloatingPointNunber
{
NSString *path = [[NSBundle mainBundle] pathForResource: #"FloatDictionary"
ofType: #"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile: path];
[path release];
double f = [[dict objectForKey: #"minFloatNumber"] doubleValue];
[dict release];
return f;
}
I've read various articles discussing looking at the project's "Build Phases" and looking at "Copy Bundle Resources," but I don't see any of that anywhere. I'm pretty sure there has to be something wrong with my setup, but not sure what I'm missing, or the steps I need to take to remedy the situation. Thanks in advance for the tips.
The "Console Application" template will be set up to produce a single binary — not included inside a proper bundle, so you can't use the NSBundle APIs to access files. If you want to include a file, you could make an actual application (where you'll be able to use [NSBundle mainBundle]), or you could include the data inside the binary (as a compile-time constant or some such).