Swift iOS Programmatically RTL the layout of my App - ios

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.

Related

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

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.

iOS Programming:Correcting Text

So I've been developing an iOS application, and one part of it involves the user entering a paragraph of text, and I need my app to filter the text, and use Apple's autocorrect function, to rectify mistakes in the text. For example, if the text is-
The quick brown fox jumpet over the lazy dog
Then it should be able to take the word 'jumpet' and change it to jumped. Does anyone know how this can be done? And I don't have to prompt the user, I'm planning to run this code in a background thread, while an activity indicator spins.
Thanks A Lot!
Raghav
P.S. - The text is in an NSString...
You can manually check spelling in a string using UITextChecker.
I haven't used it myself but it looks pretty straightforward.
Seems Apple doesn't give a public API for autocorrections,
So you should do this with some tricks and hacks.
This article should be useful.
http://blog.persistent.info/2013/10/programmatically-accepting-keyboard.html
Copied From here
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
// Turn spell check on
textView.autocorrectionType = UITextAutocorrectionTypeYes;
return YES;
}
- (BOOL)textViewShouldEndEditing:(UITextView *)textView
{
// Turn spell check off and clean up red squiggles.
textView.autocorrectionType = UITextAutocorrectionTypeNo;
NSString *currentText = textView.text;
textView.text = #"";
textView.text = currentText;
return YES;
}

Xcode 5 use different image depending on if using iOS 7 or lower

Is there a clever way now with Xcode 5 to load different images in your app depending whether it is iOS7 or not?
the best solution i can come up with is having "_7" appended on the end of the images needed for iOS7 and then when using images in the app i can go:
NSString *OSSuffix = OSVersion == 7 ? #"_7" : #""; //would be define globally, also pseudo syntax
[UIImage imageNamed:[NSString stringWithFormat:#"imageName%#", OSSuffix]]; //can make a macro for this probably
but is there a better more 'built in' way of doing this with the new asset catalog or something?
I was wondering about a similar use case, loading the 568-pixels-high images automatically based on the device type. Since the functionality was not offered, I came up with a patch to UIImage, there’s a sample project here on GitHub:
+ (void) load
{
if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPhone) {
// Running on iPad, nothing to change.
return;
}
CGRect screenBounds = [[UIScreen mainScreen] bounds];
BOOL tallDevice = (screenBounds.size.height > 480);
if (!tallDevice) {
// Running on a 320✕480 device, nothing to change.
return;
}
method_exchangeImplementations(
class_getClassMethod(self, #selector(imageNamed:)),
class_getClassMethod(self, #selector(imageNamedH568:))
);
}
// Note that calling +imageNamedH568: here is not a recursive call,
// since we have exchanged the method implementations for +imageNamed:
// and +imageNamedH568: above.
+ (UIImage*) imageNamedH568: (NSString*) imageName
{
NSString *tallImageName = [imageName stringByAppendingString:#"-568h#2x"];
NSString *tallImagePath = [[NSBundle mainBundle] pathForResource:tallImageName ofType:#"png"];
if (tallImagePath != nil) {
// Tall image found, let’s use it. We just have to pass the
// image name without the #2x suffix to get the correct scale.
imageName = [imageName stringByAppendingString:#"-568h"];
}
return [UIImage imageNamedH568:imageName];
}
You could use the same trick to automatically load iOS 7 resources based on some custom name tag. Also the same caveat applies: the UIImage trick uses method swizzling and may be too much magic to have in production. Your call.

ios apps can download the following fonts if necessary

In the iOS 7 font list located here, http://support.apple.com/kb/HT5878, there is a section at the bottom with the heading "apps can download the following fonts if necessary".
What does this mean?
How does one include these fonts, and how is this different than including custom fonts?
This is interesting, it's an almost undocumented feature, but it seems ok to use and won't get your app rejected. Just trying to research this myself brought me to this question and not much else. All I could find that was documented is sample code showing how to use it: DownloadFont.
Demonstrates how to download fonts on demand on iOS 6 and later.
On iOS 6, we have added the capability for applications to download fonts on demand. Besides the fonts installed with iOS 6, applications can install a list of additional fonts as necessary.
The fonts listed are already licensed by Apple for use in iOS, however they aren't bundled with the standard iOS firmware due to the extra disk space usage. I would assume that this will continue to be how Apple provides new fonts (unless a part of the OS's UI uses it). Additionally, unlike adding fonts using the UIAppFonts key in your Info.plist, after the font is downloaded, it is available for all apps to use.
Here's a simple example on how to asynchronously download a font and set it to a UITextView.
- (void)asynchronouslySetFontName:(NSString *)fontName toTextView:(UITextView *)textView {
CGFloat size = 24.0f;
UIFont *font = [UIFont fontWithName:fontName size:size];
if (font && ([font.fontName compare:fontName] == NSOrderedSame || [font.familyName compare:fontName] == NSOrderedSame)) {
textView.font = font;
return;
}
NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithObject:fontName forKey:kCTFontNameAttribute];
CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((__bridge CFDictionaryRef)attrs);
NSMutableArray *descs = [NSMutableArray array];
[descs addObject:(__bridge id)desc];
CFRelease(desc);
__weak UITextView *weakTextView = textView;
CTFontDescriptorMatchFontDescriptorsWithProgressHandler((__bridge CFArrayRef)descs, NULL, ^(CTFontDescriptorMatchingState state, CFDictionaryRef progressParameter) {
if (state == kCTFontDescriptorMatchingDidFinish) {
dispatch_async(dispatch_get_main_queue(), ^{
weakTextView.font = [UIFont fontWithName:fontName size:size];
});
}
return YES;
});
}
And here's a list of all the downloadable fonts. http://iosfontlist.com

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.

Resources