Concatenating Two strings in Localization Objective-c - ios

My Previous Code without Localization. It worked perfect.
case LOGIN_LOGOUT: ((Cell*)cell).lbl.text = [self isLoggedIn] ?
[NSString stringWithFormat:#"Logout %#", email]
:NSLocalizedString(#"Login", #"Message");
break;
But when I implement Localization in Logout the email will not show.
case LOGIN_LOGOUT: ((Cell*)cell).lbl.text = [self isLoggedIn] ?
[NSString stringWithFormat:NSLocalizedString(#"Logout", #"Message") ,"%#",
email] :NSLocalizedString(#"Login", #"Message");
break;
I know I am missing some basics in stringWithFormat but can anyone offer some guidance to me?

Let's assume, that you have .strings file and it contains entry named "Logout". You have:
[NSString stringWithFormat:NSLocalizedString(#"Logout", #"Message") ,"%#", email]
here you try to load format string via NSLocalizedString and use it with NSString. That means that you have to put correct format string into your .strings file, so, if currently you have:
"Logout" = "Logout";
In order to make it just like before localization, you need:
"Logout" = "Logout %#";
If you don't have a .strings file or don't have entry named "Logout", NSLocalizedString will return the key, i.e.
NSLocalizedString(#"key", #"comment") // returns "key"
That means, that your NSLocalizedString(#"Logout", #"Message") may return "Logout" if NSLocalizedString can't find correct entry in your .strings file.
There are more things that may go wrong, if you want some deeper insides on that, I have written great article on the whole topic: Understanding iOS internationalization.
Also I'd suggest to use +localizedStringWithFormat: instead of just plain +stringWithFormat:, because the former uses current locale.

You are looking up the localisation of "Logout". You are using that as a format string. That's not likely to work. Don't make statements that are too complex, it makes it impossible to debug.
I'd write
case LOGIN_LOGOUT: {
NSString* labelText;
if ([self isLoggedIn]) {
NSString* formatString = NSLocalizedString(#"Logout", #"Message");
labelText = [NSString stringWithFormat:formatString, "%#", email];
} else {
labelText = NSLocalizedString(#"Login", #"Message");
}
((Cell*)cell).lbl.text = labelText;
break;
}
And now you can actually debug that whole mess. The stringWithFormat parameters look very, very dodgy.

Related

How to combine 2 key for localizable

I have a localizable string file that contains
"please" = "Please";
"try.again" = "try again.";
Inside my application, i would like to use
"please" = "Please";
"try.again" = "try again.";
at the same time for making one sentence = $please + $try.again = Please try again.
So, I have tried this approach
+ (NSString *)pleaseLocalizedString {
return NSLocalizedStringFromTableInBundle(#"please", #"Localizable",[Bundle bundle], #"Please button");
}
+ (NSString *)tryAgainLocalizedString {
return NSLocalizedStringFromTableInBundle(#"try.again", #"Localizable",[Bundle bundle], #"try again button");
}
But with this way again I have to use stringWithFormat to combine these two methods to make one sentence...
How can I make this in an easy way? Any idea?
Do not attempt to combine two separate individually localized strings into one string. Correct sentence formation is not easily generalized across languages. Some languages are right-to-left, while others are left-to-right. Also, certain words may have different meaning when combined, especially in languages like Chinese.
If you need "please" separately in some places and you need "try again" separately in some other places, and you need "please try again" separately in other different places then use three different keys for the three different strings.
If you only need "please try again" and you don't need "please" or "try again" separately, then only have the one key for "please try again".
Having said that, the solution to your question as asked would be to define a third string as:
"p.t.a" = "%1$# %2$#";
Then in some other localization the right side could be something like "%2$#, %1$#";.
Then you would have:
+ (NSString *)pleaseTryAgainLocalizedString {
NSString *format = NSLocalizedStringFromTableInBundle(#"p.t.a", #"Localizable",[Bundle bundle], #"Please Try Again");
return [NSString stringWithFormat:format, [self pleaseLocalizedString], [self tryAgainLocalizedString]];
}
But again, this is just silly. Simply define:
"please.try.again" = "Please try again.";
and:
+ (NSString *)pleaseTryAgainLocalizedString {
return NSLocalizedStringFromTableInBundle(#"please.try.again", #"Localizable",[Bundle bundle], #"Please Try Again");
}
This gives you the most flexibility for translating this string into any other language.

What is wrong with this NSLocalizableString code?

I have this code on Viewcontroller.m, on Xcode:
NSString *language = NSLocalizedString(#"es", #"language");
NSString *connector = NSLocalizedString(#"de", #"connector to link words");
And this one on the "Localizable.strings (English)":
"language" = "en";
"connector to link words" = "of";
The problem is that with every language I change on the iOs Simulator, I always get the first value, the value of the Viewcontroller.m, instead of get the strings values.
Does anyone know what is wrong?? Thank you so much!
UPDATE:
I have this:
NSString *language = NSLocalizedString(#"es", #"language");
NSString *connector = NSLocalizedString(#"de", #"connector to link words");
But it still doesn't work!! Why????
It only shows the key values!! In the strings I have:
"es" = "en";
"de" = "of";
on the english file, and on the spanish file:
"es" = "es";
"de" = "de";
SOLUTION:
I think I have already done everything right, so the problem must to be in the iOs simulator. If anyone can take advantage of that, my solution has been edit the scheme clicking in the image of the project in the superior task bar, and in the tab "Options" (on the Run part) set "Spanish" as my language by default.
Thanks everybody anyway.
The syntax of NSLocalizedString goes like the below.
NSString * NSLocalizedString(
NSString *key,
NSString *comment
)
The key should be used in your .strings file. The value of the key will be different for different languages .
So when you run the key will be replaced by the value provided in the language .strings file you set.
Look at this tutorial for more explanation.
syntax is NSLocalizedString(key, comment)
And this one on the "Localizable.strings (English)":
"language" = "en";
"connector to link words" = "of";
so "language" is the key and "en" is the value
so
NSString *language = NSLocalizedString(#"language", #"");
NSString *connector = NSLocalizedString(#"connector to link words",#"");

if statements and stringWithFormat

I need to know if there is a way to use if statements to display certain nsstrings, depending on whether or not that NSString contains any data.
I have an nsstringcalled visitorInfo.
The string uses data from other strings (i.e. which operating system the user is running) and displays that info. Here is an example of what I'm talking about:
NSString *visitorInfo = [NSString stringWithFormat:#"INFO\n\nVisitor Location\n%#\n\nVisitor Blood Type\n\%#", _visitor.location, _visitor.bloodType];
And it would display like this:
INFO
Location
Miami, FL
Blood Type
O positive
However, I have several pieces of data that only load if the user chooses to do so. i.e their email address.
This section of code below would do what I want, but my visitorInfo string contains tons of different strings, and if I use this code below, then it won't load any of them if the user chooses not to submit his blood type.
if ([self.visitor.bloodType length] > 0) {
NSString *visitorInfo = [NSString stringWithFormat:#"INFO\n\nVisitor Location\n%#\n\nVisitor Blood Type\n\%#", _visitor.location, _visitor.bloodType];
}
So basically if their is data stored in bloodType then i went that code to run, but if there isn't any data I only want it to skip over bloodType, and finish displaying the rest of the data.
Let me know if you have any more questions
Additional details. I'm using an NSString for a specific reason, which is why I'm not using a dictionary.
Just build up the string as needed using NSMutableString:
NSMutableString *visitorInfo = [NSMutableString stringWithFormat:#"INFO\n\nVisitor Location\n%#, _visitor.location];
if ([self.visitor.bloodType length] > 0) {
[visitorInfo appendFormat:#"\n\nVisitor Blood Type\n\%#", _visitor.bloodType];
}
You can check if a string has any data in it by using the following
if([_visitor.location length]<1){
//This means there's no data and is a better way of checking, rather than isEqualToString:#"".
}else{
//there is some date here
}
** EDIT - (just re-reading your question, sorry this answer is dependant on _visitor.location being a string in the first place)*
I hope this helps
Try this -
NSString *str = #"INFO";
if (_visitor.location) {
str = [NSString stringWithFormat:#"\n\nVisitor Location\n%#",_visitor.location];
}
if (_visitor.bloodType) {
str = [NSString stringWithFormat:#"\n\nVisitor Blood Type\n\%#",_visitor.bloodType];
}

Check if Text Field NEARLY Matches Set Text? iOS

Does anyone now how I can check if a text field NEARLY matches a set text?
I know how to check if it exactly matches, but i want it to know if its even close to the set text
So if they type HELLO WORD it indicates its close but not exact match?
if (([textfield.text isEqual:#"HELLO WORLD"]))
{
NSLog(#"Correct");
} else {
NSLog(#"Incorrect");
}
This library may be of use to you. And since it's open source, you can check the source to see how it's done. :)
Use this
For Case Insensitive :
if( [textfield.text caseInsensitiveCompare:#"My Case sensitiVE"] == NSOrderedSame ) {
// strings are equal except for possibly case
}
For Case Sensitive :
if([textfield.text isEqualToString:#"My Case sensitiVE"]) {
// Case sensitive Compare
}
You can compare each index of two string and see how many difference is there. And you should define your "nearly match", it may be difference in single character or in multiple character. And decide if you should accept it or reject it.
If you like algorithm Longest Common Subsequence is a key to your goal.. :)
use
NSString caseInsensitiveCompare:
or
- (NSComparisonResult)compare:(NSString *)aString
options:(NSStringCompareOptions)mask`
NSString *string = #"HELLO WORLD I AM JACK";
if ([string rangeOfString:#"HELLO WORLD"].location == NSNotFound) {
NSLog(#"string does not contain HELLO WORLD");
} else {
NSLog(#"string contains HELLO WORLD!");
}

Fallback language iOS (with incomplete Localizable.strings file)

I have an iOS project that is localized into 16 languages. Only some words are not localized (Mainly those that go into an update and the localization office did not deliver in time).
For my keys I do not use the english wording, as this can also change if a translator wishes.
So now if I just don't have a translation for a language, if falls back to the key that I used. But as this key is not 'human readable' or at least not 'human enjoyable to read' this is a problem.
I did some research but couldn't find a solution to my exact problem.
I have fe.:
Localizable.strings in en.lproj
#"Key1" = #"Value 1"
#"Key2" = #"Value 2"
Localizable.strings in de.lproj
#"Key1" = #"Wert 1"
// Note that #"Key2" is missing here in my de.lproj
I would expect that if I make NSLocalizedString(#"Key2", ...)
and am running on a german phone, it falls back to the english
translation for this key as it exists...
So for now i just copied the english translation into the missing Localizable.strings files. But this is a big hack!
But also using the english words as keys seems to be a hack to me!
Is there any way to tell my app, that it should use f.e. english as the fallback if there is no value for a given key? I tried adding a base localization but this doesn't help...
Thanks a lot
As far as I know, there's no "official" way to do it, but I have implemented functions such as this before:
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;
}
borrowed from: https://stackoverflow.com/a/8784451/1403046
Basically, instead of NSLocalizedString(), which will return the input string, this version will fallback to English if necessary.
Inspired by this and this, my Swift code version:
public func LS(_ key: String) -> String {
let value = NSLocalizedString(key, comment: "")
if value != key || NSLocale.preferredLanguages.first == "en" {
return value
}
// Fall back to en
guard
let path = Bundle.main.path(forResource: "en", ofType: "lproj"),
let bundle = Bundle(path: path)
else { return value }
return NSLocalizedString(key, bundle: bundle, comment: "")
}
Many developers expect an incomplete translation to fallback on the development language.. but that's not the way Apple choose to behave. I have a pseudocode to help better understand how Apple choose to fallback.
For Swift project SwiftGen tool can be used. It generates string constants that will contain fallback strings from base localisation language. If a string key is not found in the localization file for currently selected language then the fallback string will be used.
Example of a generated constant for CommonTextClose localization key from Localizable.strings file:
internal static let commonTextClose = L10n.tr("Localizable", "CommonTextClose", fallback: "Close")
You can use a Base localization and all unlocalized strings will be taken from this.

Resources