I have a project that uses a static library (SL). In that SL, there are a couple of strings I'd like to localize and the project includes all of the localization files. The localization works just fine when storing all text translations in the same file. The thing is that I'd like to separate the SL strings from the other strings. I have tried to put two different *.strings files (Localizable.strings and Localizable2.strings) in the language folder of interest but that did not work. I have also tried to use two *.strings file with the same name (Localizable.strings) but with different paths. It didn't work either. It seems that only one localization file is supported, right? Could anyone suggest a good way of doing this? I'm using SDK 3.2 beta 2.
It is not possible to bundle it in a static lib, but you can create new bundle like "MyStaticLibraryName.bundle", put inside all localizations and use the code below instead "NSLocalizedString()". All you need to do: add a static library and resource bundle.
NSString *MyLocalizedString(NSString* key, NSString* comment) {
static NSBundle* bundle = nil;
if (!bundle) {
NSString* path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"MyStaticLibraryName.bundle"];
bundle = [[NSBundle bundleWithPath:path] retain];
}
return [bundle localizedStringForKey:key value:key table:nil];
}
Putting files with the same name intro one project never works, because in the resulting app they end up all in the same location. (Xcode doesn't preserve your directory structure.)
But you can put part of your localization into Localizable2.strings and then use:
NSLocalizedStringFromTable(#"key", #"Localizable2", #"")
Make the localizable string for the static library, then place that string file in a folder "YourLibraryResource".
Rename the folder "YourLibraryResource.bundle".
Now you include this bundle also in the project along with the library. Then use the code given by abuharsky.
Related
I am loading text resources in different languages from text files using:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"myfile" ofType:#"txt"];
if(filePath) {
NSString *myText = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
}
Works very well with my language specific resources in English, German etc.
But I do also have some country-specific resources, like an English text for United Kingdom, an English text for USA, a German text for Austria etc.
I would expect these resources to be loaded if the phone is set to the specific country (Region Format), but they don't. The filepath will always be set to the file in the "pure" language folder.
So for example I have myfile.txt in the folders:
en.lproj
en-GB.lproj
en-US.lproj
but it always loads the one in en.lproj
Folders have been created using the localization function in Xcode and are all located in the same folder.
What is a bit odd is that these folders created by Xcode do seperate language and country by a hyphen, but according to the documentation it should be an underscore. I have tried to copy folders (with underscores) into the project manually, but it still doesn't work.
How do I manage to load the country-specific files?
Thanks.....
I created a "dutch-netherlands" translation of Localisations.string and set iPhone language to dutch, but NSLocalizedString always returned the English translation. The solution was to create a "dutch" translation (nl.lproj) instead of "dutch-netherlands" (nl-NL.lproj).
In the settings screen of iOS4 or iOS5, you can select Dutch language but there's no subselection for Dutch-Netherlands or Dutch-Belgium, even though these are available in XCode. It seems to me that XCode offers more translation options than that are actually supported by iOS.
I mean there's no way to make your app use "nl-NL" resources. I guess the same problem goes for German and Austria ("de-DE" and "de-AT").
Note: Your code sample is a complicated way of loading text resources. It's fine if you are loading non-string resources such as images or media files, but for simple strings it's much easier to just use one .strings file per language (containing multiple localized strings) and call NSLocalizedString to get the relevant language version of a given string.
Answer: The iOS setting under "Region Format" does not affect resource loading. Instead it controls how the system performs locale-dependent functionality (such as date/number formatting and parsing). The iOS setting that controls which language version of your localized resources gets loaded is the Language setting (General > International > Language). Currently, it includes only two English variants: "English" and "British English".
I have the same problem with nl-NL.lproj (Netherland) and ca-ES.lproj (Catalan). The solution for me is add the language using Xcode. Go to Xcode Project, and then in Info Tab add the langugages. Automatically will create the folders nl-NL.lproj and ca-ES.lproj.
Then you can try this on Simulator (Xcode version 4.6) and these languages don't word, instead will load English language.
First rename manually the folder nl-NL.lproj to nl.lproj.
Finally go to file {MY_PROJECT}.xcodeproj/project.pbxproj and replace the PATH of the following lines:
C3D2888817108DDA00CE8AC2 /* nl-NL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nl-NL"; path = "nl.lproj/Localizable.strings"; sourceTree = "<group>"; };
C3D2888917108DE500CE8AC2 /* nl-NL */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "nl-NL"; path = "nl.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
That's all, now I can get these languages settings correctly.
i want to find the path of the file which is not in my bundle..
NSString *path = [[NSBundle allBundle] pathForResource:nm ofType:#"jpg" inDirectory:nil];
but it gives warning that NSArray may not respond..
is there any way to find the path of file any other folder.
allBundle returns an NSArray of all the bundles. You mean to use the method mainBundle.
If you can't find your resource then this is most likely a problem with the name of the resource you're looking for (have you checked the value of nm is correct?) Also check in your Target under the "Copy resources" section that your .jpg file is listed there. If it's not then you should drag it there to ensure that the file is copied into your bundle when you build it.
If you really want to search through all the available bundles for your resource, then you can loop through the array of bundles that allBundle returns as follows:
NSString* pathForResource = nil;
for (NSBundle currentBundle in [NSBundle allBundle])
{
pathForResource = [currentBundle pathForResource:nm ofType:#"jpg"];
if (pathForResource)
{
break; // Found resource, no longer need to search through bundles.
}
}
Note: You also don't need to use the "inDirectory:" part of the method (see the docs).
I'm trying to read files stored in assets folder and its subfolders using std::ifstream in an iOS app written mostly in C++ (The same code is also used in other, non-iOS projects), but they're not found. Example: there is a file assets/shaders/ortho2d.vert and I'm trying to load it like this:
std::ifstream vertFStream( vertFile ); // vertFile's contents is "assets/shaders/ortho2d.vert"
if (!vertFStream) {
std::cerr << vertFile << " missing!" << std::endl;
exit( 1 );
}
I've added the assets folder to the XCode project as a blue folder and it shows up in Targets->Copy Bundle Resources.
Try this:
NSBundle *b = [NSBundle mainBundle];
NSString *dir = [b resourcePath];
NSArray *parts = [NSArray arrayWithObjects:
dir, #"assets", #"shaders", #"ortho2d.vert", (void *)nil];
NSString *path = [NSString pathWithComponents:parts];
const char *cpath = [path fileSystemRepresentation];
std::string vertFile(cpath);
std::ifstream vertFStream(vertFile);
You may need to check the relative path from where the application is running and probably use a full path to ensure the file is found.
The fact that the open failed does not necessarily mean the file is not found, it just might not be readable at this moment. (Incorrect permissions or file locked).
exit(1) is rather drastic.
sorry but some punctuations:
on iOS using file system calls from C++ is highly discouraged for security issues and limited support from a security point of view.
calls to file system should be done afer you know decently iOS app
folder layout. (bundles, resources, Documents folder" and so on..)
otherwise it will fail. c) you can mix c++ and objC but definitively
is not a correct approach.
under iOS you must use swift or objC (excect in very limited cases)
use iOS APIs, exactly as under android you would use java
i'm new as an iphone developer, as a hobby i'm writting a small game (just for fun).
i would like to store the default configuration inside a xml file. I have the xml file, I know about how to parse the xml document, but.. what i do not know, and that's why i'm here is:
is there a way to say to Xcode: imagine this (xml) file is stored on /documents/ ? or the unique way is to copy&paste the (xml) file here:
~/Library/Application Support/iPhone Simulator/4.1/Applications//documents/
thanks!
fyi: the xml will always be together with the app.
just drag the xml into the file tree (solution explorer) in xcode
then to get the root directory path, just call
[[[NSBundle mainBundle] bundlePath] UTF8String]
that gets it as a char*, for c style string stuff. otherwise just leave out the UTF8String
[[NSBundle mainBundle] bundlePath] to get the NSString. just add your file name to the end
in my experience, it doesn't matter where you dump your xml in the 'solution explorer' it always ends up in the root directory.
better to use plist instead of xml . if u use plist then there is no need to parse it again.
end then use
NSString *theFolderPath = [NSHomeDirectory() stringByAppendingPathComponent:#"documents/YOUR FILE NAME"]
in the current project I have a number of folders, with subfolders, and these contain images: 01.png, 02.png.
Folder1/FolderA/f1.png
Folder1/FolderB/F1.png
When I compile the app, I looked inside the the .app and noticed that all the images are placed in the top level, with no sub-folders.
So clearly when trying to load the image this doesn't work:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"f1"
ofType:#"png"
inDirectory:#"Folder1/FolderA"];
But even more strangely, when loading image "f1", the image actually loads "F1"
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"f1.png"]];
Anyone have ideas on how to get around this problem?
Is there a compile option to create the folders in the app bundle?
TIA.
To create the subfolders inside the .app bundle, you should check the option "Create folder references for any added folders" rather than the default "Recursively create groups for any added folders"
Now in XCode, your imported folder appears blue rather than yellow. Build and go and you should see folders in your .app file.
First of all the folders you create in Xcode are simply organizational structures without any counterpart on the filesystem level. In other words all folders except for the "Classes" folder gets flatten out at the filesystem level. Therefore, even if you put your image file in the following location within xcode, it would still exist at the top-level in the filesystem: f1/f2/f3/f4/f5/image.png. Thus, in pathForResource method, you should not include the inDirectory argument.
As for the second issue, mac osx doesn't recognize case-sensitive file names. Therefore, f1 and F1 are equivalent to mac osx and will reference the same file. You can easily see this by executing the following 2 commands at a terminal session:
touch f
touch F
you'll notice that only 1 file exists after this: namely f. If you reverse the 2 commands, you still get one file, but it is named F.
ennuikiller is right. I think you can organize your images via Finder in subfolder and then refresh the image location in XCode by right clicking your image and selecting "Get Info" option. Then set the new directory.
Cheers.
Just wanted to add to Mugunth's answer, to follow up on part of the original question which was trying to use:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"f1" ofType:#"png" inDirectory:#"Folder1/FolderA"];
... to access files added using folder references. The above 'pathForResouce' call will work on simulators but not on actual iPhones (nil will be returned), because they don't seem to recognize subfolders in the 'inDirectory' part of the method. They do recognize them in the 'pathForResource' part, though. So the way of rephrasing the above so that it works on iPhones is:
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"FolderA/f1" ofType:#"png" inDirectory:#"Folder1"];
I've followed your answer but it seams all files are stored flat on the root. If I use the code below to get the full path
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef url = CFBundleCopyResourceURL(mainBundle, CFSTR("About"), CFSTR("png"), NULL);
UInt8 filePath[PATH_MAX];
CFURLGetFileSystemRepresentation(url, true, filePath, sizeof(filePath));
I get as a result: /Users/iosif/Library/Application Support/iPhone Simulator/6.1/Applications/33FB4F79-999C-4455-A092-906A75226CDB/Arithmetics.app/About.png