NSLocalizedString breaks webpage URL in string using Xcode - ios

I have a number of strings that have internet links embedded within them that worked fine until I applied NSLocalizedString to each of them for a localization in Spanish. Now the links in the strings are not recognized or operate as such in my app either for English (the base language) or Spanish.
I have been unable to determine why this is happening and haven't found any reference to this issue online. Is there some special formatting that I have to do to the URL part of my strings when using NSLocalizedString that I didn't have to when using NSString? I would greatly appreciate any help that anyone could offer with a solution to my issue?
Here is an example of one of my NSLocalizedStrings and its use in forming the contentString:
aboutContentText = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg\n", #"aboutContentText-2nd Joyful Mystery");
contentString = [[NSMutableAttributedString alloc]
initWithString: aboutContentText attributes: contentAttributes2];

Don't localize the URLs, localize only the text:
NSString *preamble = NSLocalizedString(#"\"The Visitation\", by 1737, Jerónimo Ezquerra (1660-1737)", #"preamble aboutContentText-2nd Joyful Mystery");
NSString *urlString = #"http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg";
NSString *aboutContentText = [NSString stringWithFormat:#"%#, %#\n", preamble, urlString];
NSLog(#"aboutContentText: %#", aboutContentText);
NSLog output:
aboutContentText: "The Visitation", by 1737, Jerónimo Ezquerra (1660-1737), http://commons.wikimedia.org/wiki/File:Jerónimo_Ezquerra_Visitation.jpg

Related

Handling Windows Hebrew Encoding in Objective-c

I am working on an ancient iOS app for a program that runs off VB6. It is passing strings over in a non unicode format including Hebrew characters which once they are parsed are displayed as "àáðø ãøåøé"
I am assuming it is being encoded in Windows Hebrew.
I can't seem to find anything in the apple documentation that explains how to handle this case. And most searches bring up solutions in Swift, no Obj-C. I tried this:
NSString *hebrewPickup = [pickupText stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:false];
But that just gave me this:
"ðø ַ̃øַ̊øֵ"
I am stumped.
EDIT: Based on JosefZ's comment I have tried to encode back using CP1252, but the issue is that CP1255 is not in the list of NSStringEncodings. But seems like it would solve my issue.
NSData *pickupdata = [pickupText dataUsingEncoding:NSWindowsCP1252StringEncoding];
NSString *convPick = [[NSString alloc] initWithData:pickupdata encoding:NSWindowsCP1254StringEncoding];
NSString *hebrewPickup = [convPick stringByApplyingTransform:NSStringTransformLatinToHebrew reverse:false];
Ok, if any poor soul ends up here, this is how I ended up fixing it. I needed to add some Swift into my Obj-C code. (If only I could magically just rebuild the whole project in Swift instead.)
Here is the info on that: https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/importing_swift_into_objective-c
Making use of this Swift Package: https://github.com/Cosmo/ISO8859
I added the following code to a new swift file.
#objc class ConvertString: NSObject {
#objc func convertToHebrew(str:String) -> NSString {
let strData = str.data(using: .windowsCP1252);
let bytes: Data = strData!;
if let test = String(bytes, iso8859Encoding: ISO8859.part8) {
return test as NSString;
}
let test = "";
return test as NSString;
}
}
Then in the Obj-C project I was able to call it like so:
ConvertString *stringConverter = [ConvertString new];
NSString *pickupTextFixed = [stringConverter convertToHebrewWithStr:pickupText];
NSString *deliverTextFixed = [stringConverter convertToHebrewWithStr:deliverText];

`NSLocale preferredLanguages` contains "-US" since iOS 9

We have code like the following to retrieved the user language preference:
NSString *language = [[NSLocale preferredLanguages] firstObject];
Before iOS 8.4, language is "zh-Hans", "de", "ru", "ja" and etc. But since iOS 9, I notice that there is additional three characters "-US" appended to language. For example, "zh-Hans" becomes "zh-Hans-US"
I can find any documentation about this change. I assume that I could do something like the following to workaround this issue.
NSRange range = [language rangeOfString:#"-US"];
if (range.location!=NSNotFound && language.length==range.location+3) {
// If the last 3 chars are "-US", remove it
language = [language substringToIndex:range.location];
}
However, I am not sure whether it is safe to do so. It seems that "-US" is the location where the user is using the app? But this doesn't really make sense because we are in Canada. Has any body from other part of the world tried this?
Apple has started adding regions onto the language locales in iOS 9. Per Apple's docs, it has a fallback mechanism now if no region is specified. If you need to only support some languages, here is how I worked around it, per Apple's docs suggestion:
NSArray<NSString *> *availableLanguages = #[#"en", #"es", #"de", #"ru", #"zh-Hans", #"ja", #"pt"];
self.currentLanguage = [[[NSBundle preferredLocalizationsFromArray:availableLanguages] firstObject] mutableCopy];
This will automatically assign one of the languages in the array based off the User's language settings without having to worry about regions.
Source: Technical Note TN2418
To extract the region I think this is a better solution:
// Format is Lang - Region
NSString *fullString = [[NSLocale preferredLanguages] firstObject];
NSMutableArray *langAndRegion = [NSMutableArray arrayWithArray:[fullString componentsSeparatedByString:#"-"]];
// Region is the last item
NSString *region = [langAndRegion objectAtIndex:langAndRegion.count - 1];
// We remove region
[langAndRegion removeLastObject];
// We recreate array with the lang
NSString *lang = [langAndRegion componentsJoinedByString:#"-"];
Swift 5: Remove region from preferred language
Using Locale.preferredLanguages.first gives you the preferred App language (which can be different than device language for the user).
In order to support the script code and language code (but to remove the region code) I think it is best to create a locale given the preferred language and grab the information we need from there.
if let pref = Locale.preferredLanguages.first {
let locale = Locale(identifier: pref)
let code = [locale.languageCode, locale.scriptCode].compactMap{$0}.joined(separator: "-")
print(code)
}
So first we get the preferred app language, Then create a locale from the language.
To get the language code we create an array with locale.languageCode and the locale.scriptCode (which may be nil), remove any nil values with compactMap and then join the values with a "-".
This should allow support for Simplified Chinese and Traditional, and let Apple handle the region instead of assuming it will always be there.

Localizable.strings in iOS and not localized languages

I'm building an application that will be localized in a future version, so I want to setup it to be ready for that.
At the moment I have only one language (French) and the fr.lproj folder contains the Localizable.strings with french translations for the related keys.
The problem is that If I set my device to English I don't receive the French default translations, but I see the Keys name that I use in NSLocalizedString.
For example if I try to get the title for a View Controller with:
NSLocalizedStrings(#"viewController_Title",nil);
The view controller, for device with English language shows "viewController_title" as title, while if I set the French language it works with no problem.
How can I deal with that?
Your problem is that you need a language to fallback to.
As far as I know, there is no official way around it, I've written methods like this in the past:
NSString * L(NSString * translation_key) {
NSString * s = NSLocalizedString(translation_key, nil);
if (![[[NSLocale preferredLanguages] objectAtIndex:0] isEqualToString:#"en"] && [s isEqualToString:translation_key]) {
NSString * path = [[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"];
NSBundle * languageBundle = [NSBundle bundleWithPath:path];
s = [languageBundle localizedStringForKey:translation_key value:#"" table:nil];
}
return s;
}
In this case, using L(#"viewController_Title"); would return the string for the default language, in this case being English.
Shameless self-citation
In this string file " Localizable.strings" you need to declare localization like this
French.strings
"viewController_Title" = "ViewController_Title_In_Frech";
English.strings
"viewController_Title" = "ViewController_Title_In_English";
You need to use the localized string like this
NSLocalizedStringFromTable(Key, LanguageType, #"N/A")
ex:
NSLocalizedStringFromTable("viewController_Title", English, #"N/A");
Note : Change the language type programmatically then you can get the respective Localized string. And localized declaration is must in the relevant strings file.
Your project is set to use English as the default language.
In your Info.plist file:
Set "Localization native development region" to French.
Missing translations will now fall back to French instead of English.
As mentioned in the other answers, By default English is used in case of missing language.
There are two solutions:
1. Add localization string file for english as well (with the same content as french localized string has)
2. Or add the following code in main method of main.m before calling UIApplicationMain
//sets the french as default language
NSArray *lang = [[NSUserDefaults standardUserDefaults] stringArrayForKey:#"AppleLanguages"];
if ([lang count] > 0 && (![[lang objectAtIndex:0] isEqualToString:#"fr"]) ) {
NSLog(#"language is neither de nor fr. forcing de");
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"fr", #"en", nil] forKey:#"AppleLanguages"];
}

iOS 7 contact number spaces are not spaces [duplicate]

This question already has answers here:
Remove white space from contact number fetched from phone book
(2 answers)
Closed 6 years ago.
In my app I am trying to retrieve the list of contact's number and try to do operations on them. I realized that whenever I have added new contacts (after updating to iOS 7) the new contacts formatting has changed, as there are spacings in the newly added numbers.
Using the ordinary replace methods does not remove the spaces.
Are these really spaces or what are these ? my objective is to get back the 'space' free number.
for example, if the number is 1 818 323 323 323, I want to get 1818323323323
I looked at this as not getting rid of 'spaces' but being left with only decimal characters. This code did that for me:
phoneNumberString = [[phoneNumberString componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""];
This takes out everything that's not a number 0-9.
Swift 4.1:
phoneNumberString = phoneNumberString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "")
Try this:
NSString *cleaned = [[phoneNr componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] componentsJoinedByString:#""];
This should work for any kind of space (of which there are many). It may seem somewhat inefficient, but for phone numbers, this should be ok.
Some iOS7 phone numbers are encoded with non-breaking space. Try this:
NSString* stringFormatted = [phoneNumber stringByReplacingOccurrencesOfString:#"\u00a0" withString:#""];
After way too much string cleaning I finally found an answer after printing the CFStringRef straight from the Address Book. Here's what's going on behind the scenes...
Add a contact in iOS7 and Apple stores this: (555).555-5555 (where . is actually U00A0 or &nbsp)
My app copies a contact's info in a CFStringRef from AddressBook (when NSLogged the . shows)
CFStringRef is cast into NSString (NSLog now shows 555\U00a0555-5555)
To remove the \U00A0 I tried 3 answers from this thread and [NSCharacterSet characterSetWithRange:(160,1)] which didn't work. What finally worked was this line of code:
phoneNumber = [phoneNumber stringByReplacingOccurrencesOfString:#"." withString:#""];
// where #"." was created by typing Option+Spacebar
Another (very flexible) option is to use a regular expression. This allows you to retain the + or any other characters you want to remain.
let numberFromAddressBook = "+1 818 323 323 323"
let cleanNumber = numberFromAddressBook.stringByReplacingOccurrencesOfString("[^0-9+]", withString: "", options: NSStringCompareOptions.RegularExpressionSearch, range:nil)
"+1818323323323"
The cleanest solution I'm using in my apps is:
NSMutableCharacterSet *phoneNubmerCharacterSet = [NSMutableCharacterSet characterSetWithCharactersInString:#"+"];
[phoneNubmerCharacterSet formUnionWithCharacterSet:[NSCharacterSet decimalDigitCharacterSet]];
NSString* phoneString = [[phoneString componentsSeparatedByCharactersInSet:[phoneNubmerCharacterSet invertedSet]] componentsJoinedByString:#""];
No "if" logic, keeps the + in number, removes all kind of random unwanted characters
I made a small adjustment to the poster's answer in case someone wants to maintain the + at the begining of the number.
I made this small adjustment if you want to keep the plus after removing the spaces.
Boolean shouldAddPlus = NO;
if([[phoneNumber substringToIndex:1] isEqualToString:#"+"])
{
shouldAddPlus = YES;
}
phoneNumber = [[phoneNumber componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:#""];
if(shouldAddPlus)
phoneNumber = [base stringByAppendingString:phoneNumber];
The correct solution is to replace the occurences with a valid space
NSString *clean = [dirty stringByReplacingOccurrencesOfString:#"\u00a0" withString:#" "];
So you dont loose the space and the user sees what sees in other apps.

Compare Static String and String from webview

My App sends html to a Arduino with an Ethernet Shield. The Ethernet shield acts as a webserver and sends a simple message back to a UIWebview in the App. I'm using
NSString *myText = [myWebView2 stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
If I ask NSLog to print my "myText" It prints out
<h2>Relay1 ON</h2>
Which is what is sent to the webview. Now if I try to Compare myText with a static string that matches exactly, I get no result.
Heres the entire code block.
- (void)webViewDidFinishLoad:(UIWebView *)myWebView2;
{
NSString *myText = [myWebView2
stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"];
NSLog(#"my Text=%#",myText);
if ([myText isEqualToString:#"<h2>Relay1 ON</h2>"]) {
NSLog (#"If statement was triggered");
}
}
If I look at the value of myText in NSLog it exactly matches yet the if statement is never triggered.
What am I missing in that if statement?
Thanks!!
Not Really Solved but I used NSRange to search myText for "Relay1 ON" and that works more efficiently than dealing with hidden Characters. Thanks so Much for your help.

Resources