ios9 : NSLocalizedString inside framework - ios

I had create a framework that send data to server. Whenever I get response from the server I translate it using NSLocalizedString but it not working.
I tried to change Main Bundle to my Framework Bundle like this :
NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath];
NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:#"Frameworks/MYFRAMEWORK.framework"];
NSBundle *bundle = [NSBundle bundleWithPath:frameworkBundlePath];
[bundle localizedStringForKey:#"Message" value:#"" table:nil];
But still not working. is there any way to localized message when the Localizable.string is inside the framework ?
Thanks

Finally, I tried to recreate Localizable.string and whenever I want to localize I use this :
NSString *message = [[NSBundle bundleForClass:self.class] localizedStringForKey:#"MESSAGE" value:nil table:nil];
I put this code inside class of framework, so bundle of self.class is direct to framework bundle. Thank's for everybody help.

Try to use [NSBundle bundleForClass:self.class].

Related

Error when integrating with youtube-ios-player-helper third party library on iOS

I am trying to play a YouTube video with the youtube-ios-player-helper library, but I am encountering an error at runtime:
Received error rendering template: Error Domain=NSCocoaErrorDomain Code=258 "The operation couldn't be completed. (Cocoa error 258.)"
In YTPlayerView.m
Edit:
NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player"
ofType:#"html"
inDirectory:#"Assets"];
To:
NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player"
ofType:#"html"];
Hope to help you!
You need copy Assets/YTPlayerView-iframe-player.html to main bundle to fix this issue.
or just put into bundle, and replace where App starts to look for
/*NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player"
ofType:#"html"
inDirectory:#"Assets"];*/
NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player" ofType:#"html"];
Drag and drop
YTPlayerView-iframe-player.html
YTPlayerView.h
YTPlayerView.m
files in your project.
Add bridging header and use this:
#import "YTPlayerView.h"
Go to YTPlayerView.m file :
Find :
NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player"
ofType:#"html"
inDirectory:#"Assets"];
Change to :
NSString *path = [[NSBundle mainBundle] pathForResource:#"YTPlayerView-iframe-player"
ofType:#"html"];
In your View Controller:
use :
class ViewController:UIViewController,YTPlayerViewDelegate {
var playerView = YTPlayerView()
fetch videoID and load :
self.playerView.load(withVideoId: videoID)
self.playerView.playVideo()
}
You didn't give a version of the plugin you have a problem with.
In case this is 1.5, there is a bug discussed here: https://github.com/youtube/youtube-ios-player-helper/issues/160.
It is already fixed in master, so, assuming you are using Cocoapods, you may do this:
pod 'youtube-ios-player-helper', :git=>'https://github.com/youtube/youtube-ios-player-helper', :commit=>'head'

Find out if XIB exists at runtime

Is there anyway to do it?
I've tried pathForResource:ofType: on NSBundle and it can't find the xib when it's really there. If I try to load it and it doesn't exist loadNibNamed:owner:options: crashes and so does nibWithNibName:bundle:
Basically, I want to know at runtime whether I should register a xib or just a class for a given cell type on a collection view.
Are you sure pathForResource:ofType: is not working? It's not just the common xib / nib confusion?
(.xib-files are ofType:#"nib")...
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *path = [mainBundle pathForResource:#"crapXib" ofType:#"nib"]; // file is called crapXib.xib
if (path){
// whatever...
} else{
// whatever else
}
You can try to use NSFileManager to check if file exists, if application is not localized all .nibs live in root directory of .ipa, for example:
NSString * root = [[NSBundle mainBundle] resourcePath];
if ([[NSFileManager defaultManager] fileExistsAtPath: [root stringByAppendingPathComponent:#"MainViewController.nib"]])
{
// exisits
}

Multiple Localized .strings Files in iOS App Bundle

I have a fairly complicated project, consisting of several large localized sub-projects.
Most of my sub-projects are localized through a single Localizable.strings file. This file is copied into a SubProjectName.bundle target, which is used in conjunction with a SubProjectName.a static library in the main project. This works fine.
However, one of my sub-projects contains many localized .strings files. This project fails to read strings in any language other than English, regardless of how the device (or simulator) is configured.
For example, this line of code always returns the English string:
[[NSBundle myResourcesBundle] localizedStringForKey:#"MY_TEST_STRING" value:#"" table:#"MyTable"]
Where MyTable corresponds to a MyTable.strings file localized into several languages. When I peek into the .app package, all the localizations are there, sitting inside the "MyBundle.bundle" resource within the app.
The following code, however, correctly finds the translations for a given string in all localizations:
for (NSString *language in [[NSUserDefaults standardUserDefaults] objectForKey:#"AppleLanguages"])
{
NSBundle *bundle = [NSBundle bundleWithPath:[[NSBundle myResourcesBundle] pathForResource:language ofType:#"lproj"]];
NSLog(#"%#: %#", language, NSLocalizedStringFromTableInBundle(#"MY_TEST_STRING", #"MyTable", bundle, nil));
}
So when the bundle is the actual MyBundle.bundle/<LanguageCode>.lproj folder, the string lookup works. But obviously this defeats the purpose of the automatic lookup provided by iOS.
(Note that [NSBundle myResourcesBundle] above is simply a static convenience method to fetch my custom bundle for the sub-project).
--
Edit: I've been experimenting with this some more, and if I delete the en.lproj folder from my sub-project's bundle, then it correctly uses the locale of the device or simulator.
For example, I have:
MyApp.app/
|
- MyResources.bundle/
|
- en.lproj/
|
- zh-Hans.lproj/
When I set the simulator (or device) to Chinese Simplified it looks up strings in en.lproj even though the locale is zh-Hans. If I delete the en.lproj folder and restart the app it correctly uses the zh-Hans localization.
I was able to reproduce and fix the issue, though the solution does imply there's a bug in NSBundle.
I reproduced it with the following bundle structure:
MyApp.app/
|
- MyResources.bundle/
|
- en.lproj/
|
- fr.lproj/
and code:
NSLog(#"A key: %#", NSLocalizedString(#"A key", nil));
NSBundle *bundle = [NSBundle bundleWithPath: [[NSBundle mainBundle] pathForResource: #"MyResources" ofType: #"bundle"]];
NSLog(#"Current locale: %#", [[NSLocale currentLocale] localeIdentifier]);
NSLog(#"Bundle localizations: %#", [bundle localizations]);
NSLog(#"Key from bundle: %#", [bundle localizedStringForKey: #"A key" value: #"Can't find it." table: nil]);
NSLog(#"Key using bundle macro: %#", NSLocalizedStringFromTableInBundle(#"A key",
nil,
bundle,
nil));
With the locale set to fr_FR (i.e. French) the bundle picked the string from the English strings table - even the string "can't find it" doesn't appear.
Without changing the code, I was able to get the French string using the following structure for the bundle instead:
MyApp.app/
|
- MyResources.bundle/
|
- Resources/
|
- en.lproj/
|
- fr.lproj/
It looks like NSBundle still expects the old Mac OS X bundle structure instead of what iOS is supposed to use. So a simple change of bundle structure should solve the problem...
To add to what David Doyle said.
Make sure you set the available languages in the info section of your project in both the bundle and the application itself. So for instance, if you support french and english in your app, make sure both your bundle and your app have the French and English languages defined in the available localizations for your projects.
I now have a hacky solution to this, but would appreciate if someone has a better answer (or explanation for why the above doesn't work).
I expanded my NSBundle category to include a preferred language resource:
Header
#interface NSBundle (MyBundle)
+ (NSBundle*) myResourcesBundle;
+ (NSBundle*) myPreferredLanguageResourcesBundle;
#end
Implementation
#implementation NSBundle (MyBundle)
+ (NSBundle*) myResourcesBundle
{
static dispatch_once_t onceToken;
static NSBundle *myLibraryResourcesBundle = nil;
dispatch_once(&onceToken, ^
{
myLibraryResourcesBundle = [NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:#"MyResources" withExtension:#"bundle"]];
});
return myLibraryResourcesBundle;
}
+ (NSBundle*) myPreferredLanguageResourcesBundle
{
static dispatch_once_t onceToken;
static NSBundle *myLanguageResourcesBundle = nil;
dispatch_once(&onceToken, ^
{
NSString *language = [[[NSBundle myResourcesBundle] preferredLocalizations] firstObject];
myLanguageResourcesBundle = [NSBundle bundleWithPath:[[NSBundle myResourcesBundle] pathForResource:language ofType:#"lproj"]];
if( myLanguageResourcesBundle == nil )
{
myLanguageResourcesBundle = [NSBundle myResourcesBundle];
}
});
return myLanguageResourcesBundle;
}
#end
I then have a simple macro for getting my localized strings:
#define MyLocalizedDocumentation(key, comment, chapter) \
NSLocalizedStringFromTableInBundle((key),(chapter),[NSBundle myPreferredLanguageResourcesBundle],(comment))
This solution simply gets the preferred language code from NSLocale and then checks to see if a bundle exists for that language. If not, it falls back to the main resource bundle (perhaps it should iterate through the NSLocale preferredLanguage indices to check if a bundle exists? Does anyone know?)
Not clearly understand your question, but I use this macro to use multiple localized string files:
#define CustomLocalizedString(key, comment) \
[[[NSBundle mainBundle] localizedStringForKey:(key) value:nil table:nil] isEqualToString:(key)] ? \
[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:#"MyTable"] : \
[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:nil]
or you can try
[[NSBundle mainBundle] localizedStringForKey:(key) value:[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:#"MyTable"] table:nil]
This'll check Localizable.strings first, if the key does not exist, it'll return the key itself, then check and use MyTable.strings. Of course, you'd better name your key with a prefix. e.g. "KYName" = "Name";.
If it is what you want, feel free to check THIS question I've asked before. ;)
I have another solution.
#define localizedString(key) [NSLocalizedString(key, nil) isEqualToString:key] ? \
[[NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"]] localizedStringForKey:key value:#"" table:nil] : \
NSLocalizedString(key, nil)
so for instance if we're going to find a key "title" = "Manager"; in Localizable.strings (fr) and if not there then the result for the key "title" will be just same as the key.
In this case we can find the key "title" in localizable.string (en) but if can find in (fr) we can just use it.

Localization doesn't affect some .strings files

I use SORelativeDateTransformer in my project.
I localized my project (translated storyboard and created Localizable.strings(I used NSLocalizedString)) and that part translates perfect.
The problem is that SORelativeDateTransformer uses it's own SORelativeDateTransformer.strings(uses NSLocalizedStringFromTable),
which works in demo, but not in my project.
Upd.: Found also that some labels, that I translated to Norwegian localization keep English words. Oughh!
Any ideas?
I know this question is quite old but here is a solution I used. There is a way to force SORelativeDateTransformer to load a particular Localisation string base on your preference. If you did manual installation instead of using pod then you can edit the .m base on your preference. For instance this is how I am implementing it in the + (NSBundle*) bundle method
+ (NSBundle *)bundle {
static NSBundle *bundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *systemLanguage = [[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0];//you can use conditional statement after here to load a specific bundle since you now have you language codes here (e.g. 'en' for English, 'zh-Hans' for Chinese (Simplified) etc)
NSURL *url = [[NSBundle mainBundle] URLForResource:#"SORelativeDateTransformer" withExtension:#"bundle"];
bundle = [[NSBundle alloc] initWithURL:url];
NSString *path = [bundle pathForResource:systemLanguage ofType:#"lproj"];
bundle = [NSBundle bundleWithPath:path];
});
return bundle;
}
This should do the trick.

iPhone : Get the file path which is within subfolder of Resource folder

I am new to iPhone programming. I want to read the content of a text file located in a subfolder of the Resource folder.
The Resource folder structure is the following:
Resource
Folder1---->Data.txt
Folder2---->Data.txt
Folder3---->Folder1---->Data.txt
There are multiple files named "Data.txt", so how can I access the files in each folder? I know how to read the text file, but if the Resource structure is similar to the above structure then how can I get the path?
For example, if I want to access the "Data.txt" file from Folder3, how can I get the file path?
Please suggest.
Your "resource folder" is actually the contents of your main bundle, also know as the application bundle. You use pathForResource:ofType: or pathForResource:ofType:inDirectory: to get the full path for a resource.
Loading the contents of a file as a string is done with the stringWithContentsOfFile:encoding:error: method for an autoreleased string of with initWithContentsOfFile:encoding:error: if you want a retained string.
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"Data"
ofType:#"txt"
inDirectory:#"Folder1"];
if (filePath != nil) {
theContents = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:NULL];
// Do stuff to theContents
}
This is almost the same answer as given by Shirkrin previously, but with the slight difference that it works on target. This is because initWithContentsOfFile: is deprecated on Mac OS X, and not available at all iPhone OS.
To continue psychotiks answer a full example would look like this:
NSBundle *thisBundle = [NSBundle bundleForClass:[self class]];
NSString *filePath = nil;
if (filePath = [thisBundle pathForResource:#"Data" ofType:#"txt" inDirectory:#"Folder1"]) {
theContents = [[NSString alloc] initWithContentsOfFile:filePath];
// when completed, it is the developer's responsibility to release theContents
}
Notice that you can use -pathForResource:ofType:inDirectory to access ressources in sub directories.
Shirkrin's answer and PeyloW's answer above were both useful, and I managed to use pathForResource:ofType:inDirectory: to access files with the same name in different folders in my app bundle.
I also found an alternative solution here that suited my requirements slightly better, so I thought I'd share it. In particular, see this link.
For example, say I have the following Folder References (blue icons, Groups are yellow):
Then I can access the image files like this:
NSString * filePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"pin_images/1/2.jpg"];
UIImage * image = [UIImage imageWithContentsOfFile:filePath];
As a side note, the pathForResource:ofType:inDirectory: equivalent looks like this:
NSString * filePath = [[NSBundle mainBundle] pathForResource:#"2" ofType:#"jpg" inDirectory:#"pin_images/1/"];
NSBundle* bundle = [NSBundle mainBundle];
NSString* path = [bundle bundlePath];
This gives you the path to your bundle. From there on, you can navigate your folder structure.

Resources