iOS - How to set storyboard/interface builder preview Right to Left? - ios

I am Developing an app which supports two languages i.e English and Arabic. I have done mostly all tasks i.e localisation within app + handle UI LTR (english language) , RTL (Arabic language).
Now I want to see preview for a UI in RTL in storyboard. By default it is LTR.
What I have done till now:
+(void)initialize {
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:#"AppleLanguages"];
NSString *current = [languages objectAtIndex:0];
[self setLanguage:current];
}
+(void)setLanguage:(NSString *)l {
NSLog(#"\n\n\t ***** Hint Lang. selected by user: %# ****\n\n", l);
NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:#"lproj" ];
bundle = [NSBundle bundleWithPath:path];
}
+(NSString *)get:(NSString *)key alter:(NSString *)alternate {
return [bundle localizedStringForKey:key value:alternate table:nil];;
}
For handle UI LTR OR RTL. For example when user selects english language I set UI as
[UIView appearance].semanticContentAttribute = UISemanticContentAttributeForceLeftToRight;
and when user selects Arabic language then I set UI as
[UIView appearance].semanticContentAttribute = UISemanticContentAttributeForceRightToLeft;
But I have to check every and run app iPhone UI screen whether it is fine or not for both LTR as well as RTL.
Is there any way by which we can see preview UI as RTL in storyboard (without to run in iPhone/simulator). Any suggestion will be Great!! Thanks in advance!!

I found a useful way to quickly preview the RTL layout while editing a storyboard/xib, but only for one view (like a UIView parent container). This is not a good approach, but can save you some time and does not need to run the app.
While on the editor, you can select any View and in the inspector change the Semantic property to Force Right to Left. This will preview your layout in RTL for the selected view.
This is just a quick way to test a single container or control, the major drawback is that to preview the whole layout in RTL (including child views) you would need to go one by one and change this property.

Related

Swift iOS Programmatically RTL the layout of my App

I am creating an app that would allow users to select 2 languags, English and Arabic.
So when the user selects Arabic, i want my app to have a RTL layout.
Question is how would i do that? I've tried doing it this way: Settings>General>Language Region . If I select Saudi Arabia as the Region, and select Arabic as the Language, my app automatically does RTL.
As you can see that method is through Phone Settings and affects your Phone's overall layout.
Now, what i really want to accomplish is just to make my APP RTL without going to Settings>General>Language Region and affect my Phone's layout. So when i click the button in my app "Arabic", my App will change its layout into RTL.
Any help please, your help will be greatly appreciated!
Thanks!
Please avoid doing this. In-app language switchers are a confusing experience as your users expect their apps to follow the configuration in the Settings app–not some thing of your own.
Contrary to some answers here, your layout will not automatically become right-to-left if you choose to go down this path, and you will also run into issues like any number or date formatters you're using, and any system UI you present (like UIActivityViewController) will also not follow this override.
You should instead stick to using as much of the API as possible–UIKit, NSLocalizedString and Auto Layout make it seamless for you to follow the system UI language without having to resort to undocumented hacks on NSUserDefaults.
To add right to left support refer - https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/SupportingRight-To-LeftLanguages/SupportingRight-To-LeftLanguages.html
You need to build your own mechanism here. as you wanted button to change your language. Im using following code on my views:
+ (BOOL)isEnglishLanguage
{
return !language;
}
+ (void)setLanguage:(Language)lang
{
language = lang;
[GeneralUtilities storeObjectInUserDefaults:#(language) WithKey:#"language"];
}
+ (NSString *)currentLanguage
{
if(language == ENGLISH)
{
return kLanguageEnglish;
}
else if(language == ARABIC)
{
return kLanguageArabic;
}
return #"";
}
+ (NSString *) NSLocalizedStringCustom:(NSString*) key
{
NSString *path;
if([[LanguageUtilities currentLanguage] isEqualToString:kLanguageEnglish])
path = [[NSBundle mainBundle] pathForResource:kLanguageEnglish ofType:#"lproj"];
else if([[LanguageUtilities currentLanguage] isEqualToString:kLanguageArabic])
path = [[NSBundle mainBundle] pathForResource:kLanguageArabic ofType:#"lproj"];
NSBundle* languageBundle = [NSBundle bundleWithPath:path];
NSString* str=[languageBundle localizedStringForKey:key value:#"" table:nil];
return str;
}
+ (NSTextAlignment) NSLocalizedTextFieldAllingment
{
if([[LanguageUtilities currentLanguage] isEqualToString:kLanguageEnglish])
return NSTextAlignmentLeft;
else if([[LanguageUtilities currentLanguage] isEqualToString:kLanguageArabic])
return NSTextAlignmentRight;
else return NSTextAlignmentLeft;
}
i hope it will work for you too.

Changing overlaying labels text on a ScrollView

This is sort of hard to explain so I'm including a picture.
So I have a scrollview (the yellow part) and then an overlaying box with score and how many upgrades the player purchased, etc. The green box with the labels stays in the same position while the yellow part scrolls. That works fine, except I am trying to get the labels to change when the player purchases an item. So lets say the player purchases a pickaxe. The upgrades owned should change from "0/20" to "1/20".
This is my setup. I am using SpriteBuilder by the way. I have a class that handles the scrollview, like the buy buttons and descriptions, etc... Then I have another class just for the overlay on the side, and this is basically the only method in it:
- (void)didLoadFromCCB {
if (_doge < 1000000000000) {
balanceLabel.string = [NSString stringWithFormat:#"%.2Lf", _doge];
} else {
balanceLabel.string = #"A lot!";
}
upOwnedLabel.string = [NSString stringWithFormat:#"%d", _upOwned];
upMaxedLabel.string = [NSString stringWithFormat:#"%d", _upMaxed];
NSLog([NSString stringWithFormat:#"%d", _upOwned]);
}
I've tried a few things and this is the one that I think is "most correct". In the didLoadFromCCB on the scroll class, I have this:
UpgradesScene *upgradesScene = [[UpgradesScene alloc] init];
[upgradesScene didLoadFromCCB];
It's in the correct place (under buy button) but for some reason it doesn't update the label. I do get an NSLog message telling me the level, but for some reason the label doesn't work.
I'm very new to this language so please go easy on me :) Thank you
The problem is that you're creating a new upgradesScene with alloc init rather than getting a reference to the one that's in your scroll view. You should have a property (or IBOutlet if you're making this in IB) that points to that view.

Localizing attributed UITextView from storyboard

I am using the storyboard and have a view where I have subclassed some UITextViews.
My problem is that I am using ibtool --generate-strings-file to extract strings from the storyboard for localization and afterwards use ibtool -write on another storyboard file to apply the translated strings.
When I use ibtool any UITextViews that have attributed text is ignored by the ibtool --generate-strings-file command and omitted from the resulting strings file.
Is it possible to extract attributed text from a storyboard for localization?
on Xcode 6.1, the best way is to copy the attributed text of a text view into a “BASE” RTF text ( using TextEdit for example or directly from XCode > New File > ressources > RTF ).
Going through the TextEdit way, you need to import your text into your project. Obviously, if you have done it through Xcode, nothing to import.
then just you use the utilies panel to find the “localize..." button which will do it's deed for you.
to import the correct version just do ( in viewWillAppear for ex. ),
NSURL *url = [[NSBundle mainBundle] URLForResource:[fileName stringByDeletingPathExtension] withExtension:[fileName pathExtension]];
NSError *error;
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithFileURL:url
options:#{NSDocumentTypeDocumentAttribute:NSRTFTextDocumentType}
documentAttributes:nil
error:&error];
[_originalMessage setAttributedText:attributedString];
Update for Swift 4:
var attrString: NSAttributedString?
let fileUrl: URL = Bundle.main.url(forResource: "mytextfile", withExtension: ".rtf")!
do {
attrString = try NSAttributedString(url: fileUrl, options: [.documentType:NSAttributedString.DocumentType.rtf], documentAttributes: nil)
} catch {
// Somebody do something!!
}
I ended up concluding that it couldn't be done using ibtool in the present version.
Instead I let the Textview be a plain text view and, using my subclass, parsed its text property so I could make a NSMutableAttributedString and set the needed properties.
That enabled me to use ibtool to extract the strings and still have an attributed textview.
It wouldn't make sense to localize attributed text from the storyboard as you would need to know where to apply the attributes after the translation. The word order might have changed and where you would have specified some blue bold text for instance might no longer make sense.
You can of course still do it via code where you can split up your string in multiple ones and localize them individually. Then you can specify setAttributes:range: so that you know that the right attributes will always be applied on the right range of the string.
Here's a workaround which I find quite useful: just create a ViewController with the translated TextView. In details (here I just translate the attributed text into english):
1) Crete a new Controller with "New File" -> "UIViewController with Xib". Name it "AttributedTranslated" and fill it with just a TextView with the attributed text being translated, using Interface Builder.
2) In your main controller .m file, write down the following method:
- (BOOL)isEng {
return [[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:#"en"];
}
3) Define an "AttributedTranslated" object and a View in your .h file
IBOutlet UIView *attrView;
AttributedTranslated *attr;
4) On the xib file (or storyboard) of your main controller, create a View containing just the attributed textView (in the original language) and link it to "attrView".
5) On you viewDidLoad do something like the following:
if ([self isEng]) {
desc = [[Description alloc] init];
[attrView addSubview:attr.view];
}
Maybe it's not the best way to do it, but it does allow one to translate the attributed text in Interface Builder, easily!

UISegmentedControl and localization

I have a .xib file, with accompanying .strings files for different languages. The .xib file contains a label, and a UISegmentedControl.
When asking IB to localize the .xib file, I get the following .strings file:
"6.segmentTitles[0]" = "title1";
// ...More strings related to the segmented control...
"11.text" = "bla";
The 'bla' string belongs to the label.
Changing the 'bla` string is reflected in runtime, while changing the 'title1' string does not. Anyone knows why?
This question is not new, but as it is still without any answers I will add my solution as it may help others.
Generally, as it's mentioned above, it is an open bug that UISegmentedControl segment titles do not pick up localization strings.
- (void)viewDidLoad
{
...
// Locale will be picked automatically by NSBundle.
NSString *resourcePath =[[NSBundle mainBundle] pathForResource:#"MainStoryboard" ofType:#"strings"];
NSDictionary *resourceDict = [NSDictionary dictionaryWithContentsOfFile:resourcePath];
[self.segmentedControl setTitle:[resourceDict objectForKey:#"COo-BO-Ryl.segmentTitles[0]"] forSegmentAtIndex:0];
[self.segmentedControl setTitle:[resourceDict objectForKey:#"COo-BO-Ryl.segmentTitles[1]"] forSegmentAtIndex:1];
}
Where COo-BO-Ryl is the Object ID of segmentedControl.
Not very pretty, but does the job.

Program crashes when adding NSMutableArray of strings to a UILabel

When I add this array of strings to the summaryText UILabel it crashes. Please let me know how to fix this.
NSMutableArray *arr = [[NSMutableArray alloc]init];
arr = [Singleton getArray];
NSString *str = [arr componentsJoinedByString:#"\n"];
summaryText.text = str;
This is what was brought up when i command clicked summaryText
#implementation TotalViewController
#synthesize tax,taxLabel,total,totalLabel,final,finalLabel,fiveLabel,threeLabel,twoLabel,five,three,two, points, pointsLabel,summaryText;
I had suggested initWithArray, but not clear why you don't replace entire above snippet with:
summaryText.text = [[Singleton getArray] componentsJoinedByString:#"\n"];
But as others pointed out, your crash isn't here, this just simplifies your code. The problem has to rest elsewhere, probably related to the definition/creation of summaryText. Hard to say without seeing crash log or more code.
Update:
You said that you created this control in Interface Builder. You might want to double check your "connections inspector" for that control and make sure your outlet is set up correctly. This sounds a lot like a control that hasn't been set up correctly in Interface Builder. Or you can look at you .h file in Xcode and it will tell you if it's successfully linked to a control in Interface Builder. You'll see a little "circle" to the left of the source code, a solid dot in the circle means that your outlet is hooked up correctly, and empty circle means that it's not (e.g. in this example below, contactName, contactAddress, and contactPhone are all linked up correctly, but myLabel is not):

Resources