Localizable.strings key-value pair - ios

I want to localize "1 of 9", and 1 and 9 are int parameters, my code is as below
context = [NSString stringWithFormat:NSLocalizedString(#"%d of %d",
"This text will be used to show page number on the screen"),
currentPageIndex + 1, pageCount];
And the generated Localizable.strings show like that
/* This text will be used to show page number on the screen */
"%d of %d" = "%1$d of %2$d";
I think the thing on the left of "=" is key and the the thing on the right of "=" is value, but I want the key looks like "show_page_number" not included the format "%d", how can I do? I try to replace "%d of %d" with "show_page_number", but it does not work. Any advice?

NSLocalizedString() replaced key with value at runtime .So you can use anystring as key & it will be replaced as "%1$d of %2$d" at runtime.
Add string in Localizable file :
"show_page_number" = "%1$d of %2$d";
& in code use that key
context = [NSString stringWithFormat:NSLocalizedString(#"show_page_number", "This text will be used to show page number on the screen"), currentPageIndex + 1, pageCount];
Add localizable.string file in xcode project.

If you want full control over the key and its initial value you need to use NSLocalizedStringWithDefaultValue instead of NSLocalizedString (which uses the key as the initial value).
Change your code to:
NSString *format = NSLocalizedStringWithDefaultValue(#"show_page_number", #"Localizable", NSBundle.mainBundle, #"%1$d of %2$d", #"This text will be used to show page number on the screen")
context = [NSString stringWithFormat:format, currentPageIndex + 1, pageCount];
When you run genstrings, you will get:
/* This text will be used to show page number on the screen */
"show_page_number" = "%1$d of %2$d";

Related

How to format localised strings in Swift?

I am learning to localise my app to Simplified Chinese. I am following this tutorial on how to do this.
Because the tutorial is based on Obj-C, formatted strings can be written like this:
"Yesterday you sold %# apps" = "Ayer le vendió %# aplicaciones";
"You like?" = "~Es bueno?~";
But I am using Swift. And in Swift I don't think you can use %# to indicate that there is something to be placed there. We have string interpolation right?
My app is kind of related to maths. And I want to display which input(s) is used to compute the result in a detailed label of a table view cell. For example
--------------
1234.5678
From x, y <---- Here is the detailed label
--------------
Here, From x, y means "The result is computed from x and y". I want to translate this to Chinese:
从 x, y 得出
Before, I can just use this:
"From \(someVariable)"
with the strings file:
"From" = "从 得出";
And this is how I would use it in code
"\(NSLocalizedString("From", comment: "")) \(someVariable)"
But if this were used in the Chinese version, the final string will be like this:
"从 得出 x, y"
I mean I can put the 从 and 得出 in two different entries in the strings file. But is there a better way to do it?
You can use %# in Swift's String(format:...), it can be substituted
by a Swift String or any instance of a NSObject subclass.
For example, if the Localizable.strings file contains the definition
"From %#, %#" = "从 %#, %# 得出";
then
let x = 1.2
let y = 2.4
let text = String(format: NSLocalizedString("From %#, %#", comment: ""), "\(x)", "\(y)")
// Or alternatively:
let text = String(format: NSLocalizedString("From %#, %#", comment: ""), NSNumber(double: x), NSNumber(double: y))
produces "从 1.2, 2.4 得出". Another option would be to use the
%f format for double floating point numbers:
"From %f, %f" = "从 %f, %f 得出";
with
let text = String(format: NSLocalizedString("From %f, %f", comment: ""), x, y)
See Niklas' answer
for an even better solution which localizes the number representation
as well.
From WWDC 2017:
let format = NSLocalizedString("%d popular languages", comment:"Number of popular languages")
label.text = String.localizedStringWithFormat(format, popularLanguages.count)
Swift localize a string
One more simple example
let changeable = "something"
let result = String(format: NSLocalizedString("stringId", comment: ""), arguments: [changeable]) // Hello World and something
localizable.strings with
"stringId" = "Hello World and %#";
comment parameter doesn't have effect on result and is used for translators and by genstrings code-gen as comment
New in iOS 15 and macOS Monterey you can use the new refined method for String.
String(localized: "From \(x), \(y)", comment: "The result is computed from x and y")
They did a lot of updates in 2021 for localization with Xcode. Check this video from WWDC21 for more info.
https://developer.apple.com/videos/play/wwdc2021/10221/
In objective C, if we want to get strings added at runtime as below
John Appleseed is the name
YourLocalizable.strings
"theStringToDisplay" = "%# is the name";
ViewController.m
NSString *username = #"John Appleseed";
NSString *messageBeforeFormat = NSLocalizedStringFromTable(#"theStringToDisplay", #"YourLocalizable", nil);
NSString *messageAfterFormat = [NSString stringWithFormat:messageBeforeFormat, username ];
self.yourLabel.text = messageAfterFormat;
Further explanation in this nice post
https://www.oneskyapp.com/academy/learn-ios-localization/2-format-strings-plurals/

How to replace one NSString with specific NSString

In my app, users have the ability to search for other users by entering an # and then some letters, at which point a popup will show with the potential usernames. I am stuck at the point where the user will select a username from the popup, which should replace the partially entered text with the selected username. For example, if I type:
hi #jo
and then select john from the table, then it should look like below
hi #john
But this is not happening. I have find one method called
stringByPaddingToLength, but it work for only one character of the replaced text. If I search with two characters, it gives the wrong output. My code is following:
-(void)storeData:(NSString *)strName
{
NSString *strText = textView.text;//the String which is enter in textview
NSRange startRange = [strText rangeOfString:#"#" options:NSBackwardsSearch];//find the range of '#' from currently pointed at backward
strText = [strText stringByPaddingToLength:(strName.length + strText.length - 1) withString:strName startingAtIndex:(startRange.location+startRange.length)];//the string after append the string
}
If I enter #ch and then select "Chandru" it gives the following output:
2015-05-05 19:55:02.789 [3733:131086] StrName::#chhandru
If I just enter #c and then select "Chandru" it gives the following (correct) output.
2015-05-05 19:55:58.371 [3733:131086] StrName::#chandru
How can I make it display the correct username, no matter how many characters were already entered?
You can use replaceOccurrencesOfString:withString:options:range: method on NSMutableString for this.
[strText replaceOccurrencesOfString:#"#jo" withString:#"#john" options: CaseInsensitiveSearch range:NSMakeRange(0, strText.length)] ;

Formatted NSLocalizedString with variable value

I'm new to Objective-C. Here is my question:
In my two string files are the following two entries:
(German string file)
/* Class = "IBUILabel"; text = "Import to DoS"; ObjectID = "GfF-rD-aDa"; */
"GfF-rD-aDa.text" = "Zu DT %lu importieren";
(English string file)
/* Class = "IBUILabel"; text = "Import to DoS"; ObjectID = "GfF-rD-aDa"; */
"GfF-rD-aDa.text" = "Import to DoS %lu";
My code looks like:
self.importLabel.text = [NSString localizedStringWithFormat:NSLocalizedString(#"GfF-rD-aDa.text", nil), projectday];
According to Apples Documentation NSLocalizedString needs a key and a comment. That's why I putted #"GfF-rD-aDa.text" into the first parameter because it's the same key like in my strings file.
So I want it to generate strings like:
"Zu DT 2 importieren"
and
"Import to DoS 2"
but it doesn't work. The output text is:
"GfF-rD-aDa.text"
I'm not allowed to change the key in the strings table because we use a script to generate all these entries based on the object id.
Regards
Try using this specify your strings file in NSLocalizedStringFromTable macro.
self.importLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(#"GfF-rD-aDa.text", #"yourStringsFile", #"comment"), projectday];
Try this:
self.importLabel.text = [NSString stringWithFormat:NSLocalizedString(#"GfF-rD-aDa.text", nil), projectday];

Is it has '\0' at the end after convert the NSString to char in Objective-C?

I am trying to get the text from TextField and convert to the char like the following:
const char *TEXT;
TEXT = [[_data text] UTF8String];
NSLog(#"TEXT = %s" , TEXT);
NSLog(#"strlen(TEXT) = %lu" , strlen(TEXT));
When I input the abcde in textfield , and the log show
TEXT = abcde
strlen(TEXT) = 5
If I want to send TEXT by TCP , should I add the '\0' by myself ? of it already has '\0' at the end ?
It contains, you don't need to add a null terminator (\0).
As it says in the documenation:
UTF8String
A null-terminated UTF8 representation of the string. (read-only)
So it's already null terminated.
the strlen function counts the length of the contents, not including the null at the end. The actual length of the data in your TEXT variable is one byte longer (for the null)
BTW, you should follow Cocoa naming conventions. Variables (and method names) should be lower case, with words after the first word capitalized ("camel case", as it's sometimes called, e.g. "capitalizedLikeThis")
Class names should start with an upper case character and then follow the same camel case rules. (e.g. "ThisIsAClass")

Objective-C - Remove last character from string

In Objective-C for iOS, how would I remove the last character of a string using a button action?
In your controller class, create an action method you will hook the button up to in Interface Builder. Inside that method you can trim your string like this:
if ([string length] > 0) {
string = [string substringToIndex:[string length] - 1];
} else {
//no characters to delete... attempting to do so will result in a crash
}
If you want a fancy way of doing this in just one line of code you could write it as:
string = [string substringToIndex:string.length-(string.length>0)];
*Explanation of fancy one-line code snippet:
If there is a character to delete (i.e. the length of the string is greater than 0)
     (string.length>0) returns 1 thus making the code return:
          string = [string substringToIndex:string.length-1];
If there is NOT a character to delete (i.e. the length of the string is NOT greater than 0)
     (string.length>0) returns 0 thus making the code return:
          string = [string substringToIndex:string.length-0];
     Which prevents crashes.
If it's an NSMutableString (which I would recommend since you're changing it dynamically), you can use:
[myString deleteCharactersInRange:NSMakeRange([myRequestString length]-1, 1)];
The solutions given here actually do not take into account multi-byte Unicode characters ("composed characters"), and could result in invalid Unicode strings.
In fact, the iOS header file which contains the declaration of substringToIndex contains the following comment:
Hint: Use with rangeOfComposedCharacterSequencesForRange: to avoid breaking up composed characters
See how to use rangeOfComposedCharacterSequenceAtIndex: to delete the last character correctly.
The documentation is your friend, NSString supports a call substringWithRange that can shorten the string that you have an return the shortened String. You cannot modify an instance of NSString it is immutable. If you have an NSMutableString is has a method called deleteCharactersInRange that can modify the string in place
...
NSRange r;
r.location = 0;
r.size = [mutable length]-1;
NSString* shorted = [stringValue substringWithRange:r];
...

Resources