How would I use NSLocalizedString for this string:
[NSString stringWithFormat:#"Is “%#“ still correct for “%#“ tap “OK“ otherwise tap “Change“ to choose new contact details", individual.contactInfo, individual.name];
When using stringWithFormat before I've used it in the following manner:
[NSString stringWithFormat:#"%d %#", itemCount, NSLocalizedString(#"number of items", nil)];
[NSString stringWithFormat:NSLocalizedString(#"Is “%#“ still correct for “%#“ tap “OK“ otherwise tap “Change“ to choose new contact details", #"Query if parm 1 is still correct for parm 2"), individual.contactInfo, individual.name];
Given sentences can be constructed with the variable parts in a different order in some languages then I think you should use positional arguments with [NSString stringWithFormat:]:
NSString *format = NSLocalizedString(#"number_of_items", #"Number of items");
Which would load the following string for English:
#"Is \"%1$#\" still correct for \"%2$#\" tap \"OK\" otherwise tap \"Change\" to choose new contact details"
And perhaps something else for French (I don't know French so I won't attempt a translation, but it could well have the first and second argument in a different order):
"French \"%2$#\" french \"%1$#\" french"
And you can safely format the string as normal:
NSString *translated = [NSString stringWithFormat:format individual.contactInfo, individual.name];
I just want to add one very helpful definition which I use in many of my projects.
I've added this function to my header prefix file:
#define NSLocalizedFormatString(fmt, ...) [NSString stringWithFormat:NSLocalizedString(fmt, nil), __VA_ARGS__]
This allows you to define a localized string like the following:
"ExampleScreenAuthorizationDescriptionLbl"= "I authorize the payment of %# to %#.";
and it can be used via:
self.labelAuthorizationText.text = NSLocalizedFormatString(#"ExampleScreenAuthorizationDescriptionLbl", self.formattedAmount, self.companyQualifier);
Swift
//Localizable.strings
"my-localized-string" = "foo %# baz";
Example:
myLabel.text = String(format: NSLocalizedString("my-localized-string",
comment: "foo %# baz"), "bar") //foo bar baz
Related
I would like to know how can I use my Localizable.strings file to translate my widget ?
I try this but it doesn't working:
_result.text = [NSString stringWithFormat:NSLocalizedString(#"Votre avion a besoin de: %#USG", nil), #((int)number)];
You need to take the localizable string name in my case is str-name-demo
And you can use like a NSString
// 200 is the parameter
NSString *textStr = [NSString stringWithFormat: NSLocalizedString(#"str-name-demo", nil), 200];
NOTE: I assume you have the more settings ready to user NSLocalizedString method but you can see this tutorial to more understand it.
https://www.raywenderlich.com/64401/internationalization-tutorial-for-ios-2014
:)
I have a predicate editor, which the template was generate via the following:
NSArray * test = [NSArray arrayWithObjects:
[NSExpression expressionForKeyPath: #"Abc"],
[NSExpression expressionForKeyPath: #"Def"],
nil];
NSPredicateEditorRowTemplate * template = [[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: test
rightExpressionAttributeType: NSStringAttributeType
modifier: NSDirectPredicateModifier
operators: [NSArray arrayWithObject:
[NSNumber numberWithUnsignedInteger:NSContainsPredicateOperatorType]]
options:(NSCaseInsensitivePredicateOption|NSDiacriticInsensitivePredicateOption)];
So if I fill in a predicate editor like this:
When I log out the generated predicate I get:
Abc CONTAINS[cd] "abc" OR Def CONTAINS[cd] "def"
What I'm wondering is if I can somehow have the predicate editors template display be different than the value that gets set in the generated predicate.
EX: I want the output predicate to have:
Field1 CONTAINS[cd] "abc" OR Field2 CONTAINS[cd] "def"
Even though the editor still displays abc and def as the fields. Is this possible?
Yes, you can do this.
You want the array of left expressions to be the actual keyPaths in the final predicate. In your case, "Field1" and "Field2".
As for making a different value appear in the popup, here's where a mind-bending concept comes in:
You're going to localize your predicate editor into English.
There are two ways you could do this.
With a .strings file
With an NSDictionary
With a .strings file
In your source, you would include the following in a comment:
// NSLocalizedStringFromTable(#"%[Field1,Field2]# %[contains]# %#", #"PredicateEditor", #"")
When you run genstrings on your source code, this will generate a PredicateEditor.strings file with the following entries:
"%[Field1]# %[contains]# %#" = "%[Field1]# %[contains]# %#";
"%[Field2]# %[contains]# %#" = "%[Field2]# %[contains]# %#";
You would change the values to be:
"%[Field1]# %[contains]# %#" = "%[Abc]# %[contains]# %#";
"%[Field2]# %[contains]# %#" = "%[Def]# %[contains]# %#";
Then, when you create your NSPredicateEditor, you would set the formattingStringsFileName property to "PredicateEditor", and the editor will take care of the rest.
With an NSDictionary
This would follow the same fundamental concepts as the .strings option, except that you would essentially do:
NSDictionary *formatting = #{
#"%[Field1]# %[contains]# %#" : #"%[Abc]# %[contains]# %#",
#"%[Field2]# %[contains]# %#" : #"%[Def]# %[contains]# %#"
}
[myPredicateEditor setFormattingDictionary:formatting];
That's all you have to do.
I blogged about this a long time ago, and that has more information that you might find useful.
Basically you want to modify the title of the menu items in your popup button. That's all you need to do. It shouldn't effect the underlying predicate that you get returned. If you created it in interface builder it's easy to get at the menu items of a template and set their title. But since you did this in code you'll have to fix it in code.
Here's how you might do that. In my row template class I wanted to change the width of my NSTextFields. So in my row template class I look for them and modify them like this...
- (void)awakeFromNib {
NSArray* views = [self templateViews];
for (id view in views) {
if ([[view class] isEqual:[NSTextField class]]) {
NSRect tfFrame = [view frame];
tfFrame.size.width = 600;
[view setFrame:tfFrame];
}
}
}
You can see that I get the templateViews and look for the NSTextFields... and then modify them. You could do something similar looking for NSPopupButtons. Once you found one check their menu item titles and look for the ones titled "abc" and "def" and change their title to "Field1" and "Field2" respectively.
Rather than using NSLocalizedString with the option literals in the specific format and genstrings to generate the localization strings, it seems easier/cleaner to generate the final localization .strings file strings yourself.
From this blog post, we can use the Private API _generateFormattingDictionaryStringsFile to get the formatting strings from the NSPredicateEditor itself:
extension NSPredicateEditor {
func formattingDictionaryStrings() -> String? {
var strings: String? = nil
if let formattingDictionaryData = self.perform(Selector("_generateFormattingDictionaryStringsFile"))?.takeRetainedValue() as? Data {
strings = String(data: formattingDictionaryData, encoding: .utf16)
}
return strings
}
}
This generates all of the permutations, skipping the need for genstrings. You then replace the tokens to the right of the = with your user-displayed strings.
"%[ABC]# %[is]# %[123]#" = "%1$[ABC]# %2$[is]# %3$[123]#";
"%[ABC]# %[is]# %[456]#" = "%1$[ABC]# %2$[is]# %3$[456]#";
"%[ABC]# %[is]# %[789]#" = "%1$[ABC]# %2$[is]# %3$[789]#";
"%[ABC]# %[contains]# %[123]#" = "%1$[ABC]# %2$[contains]# %3$[123]#";
"%[ABC]# %[contains]# %[456]#" = "%1$[ABC]# %2$[contains]# %3$[456]#";
"%[ABC]# %[contains]# %[789]#" = "%1$[ABC]# %2$[contains]# %3$[789]#";
Even better, you can construct the code that builds each NSPredicateEditorRowTemplate to take as input both the keypath used internally in the predicate and the localized string for that option.
Your method can then generate the strings above, but with the correct localization already inserted.
NOTE: calling this _generateFormattingDictionaryStringsFile private API method seems to cause random crashes within the NSPredicateEditor:
this class is not key value coding-compliant for the key rowType.
So be sure to run it once when needed, but don't leave it active when you're normally running or testing your app.
Yes, it is all a matter of localization, thanks to the fact that the objects are menu items. And they can be treated as such easily.
All you need to do is ...
localize your application.
Then enter the .strings file and change the value to what you want to be displayed
or...
use tools for managing/translating localized apps.
Here is an example of changing things directly in a .strings file:
Change is to ist and booktitle to Buchtitel
/* Class = "NSMenuItem"; title = "is"; ObjectID = "G1c-st-GEK"; */
"G1c-st-GEK.title" = "ist";
/* Class = "NSMenuItem"; title = "booktitle"; ObjectID = "nQh-54-5Nx"; */
"nQh-54-5Nx.title" = "Buchtitel";
Remark: The best way to find the line to change is by looking for the ObjectID. This can be found for each MenuItem by the UIB identity inspector:
I am trying to read the name of a product which is entered by the user in a text field, and add it to a string later. This works fine whenever the user inputs only one word, but when the product is more than one word, the program crashes. When I run the debugger, the value of the NSString product is listed as "variable is not nsstring". This method is triggered when the user hits return after entering the product's name:
-(IBAction)textFieldReturn3:(id)sender
{
[sender resignFirstResponder];
product = inputtext.text;
}
and this is part of the method that is triggered when the user hits a twitter button two scenes later (my goal is to have a certain message displayed already when the user is deciding what to tweet) [and yes, choice is set to either 0 or 3]
- (IBAction)twitter:(id)sender
{
TWTweetComposeViewController *twitter = [[TWTweetComposeViewController alloc] init];
[fmt5 setNumberStyle:NSNumberFormatterDecimalStyle];
[fmt5 setMaximumFractionDigits:2];
[fmt5 setMinimumFractionDigits:2];
if (choice == #"0" || choice == #"3")
{
str = #"I just bought a new ";
str = [str stringByAppendingString:product]; // line where it crashes
str = [str stringByAppendingString:#" for $"];
str = [str stringByAppendingString:[fmt5 stringFromNumber:[NSNumber numberWithDouble:myDouble]]];
[twitter setInitialText:str];
}
How do I fix this problem? Thanks.
Plenty of problems. Let's start with the actual reason.
product = inputtext.text;
is not good. If you use it later, when your view has already been deallocated, its text property is no longer valid. You have to retain it to have a reference to it. So change the above line to something like this:
[product release];
product = [inputtext.text retain];
Also don't forget to initialize product to nil to avoid crashes related to the first release call.
Secondly, your comparison isn't good.
choice == #"0" || choice == #"3"
doesn't do what you think it does. Use
if ([choice isEqualToString:#"0"] || [choice isEqualToString:#"3"]) {
etc.
Edit: also a minor design point. Don't reinvent the wheel by appending portions of the text sequentially - that's extremely unreadable. Browsing through NSString's class reference, you would have quickly found the following method:
str = [NSString stringWithFormat:#"I just bought a new %# for $%.2lf", product, myDouble];
I have tried using a variable as an input parameter to NSLocalizedString, but all I am getting back is the input parameter. What am I doing wrong? Is it possible to use a variable string value as an index for NSLocalized string?
For example, I have some strings that I want localized versions to be displayed. However, I would like to use a variable as a parameter to NSLocalizedString, instead of a constant string. Likewise, I would like to include formatting elements in the parameter for NSLocalizedString, so I would be able to retrieved a localized version of the string with the same formatting parameters. Can I do the following:
Case 1: Variable NSLocalizedstring:
NSString *varStr = #"Index1";
NSString *string1 = NSLocalizedString(varStr,#"");
Case 2: Formatted NSLocalizedString:
NSString *string1 = [NSString stringWithFormat:NSLocalizedString(#"This is an %#",#""),#"Apple"];
(Please note that the variable can contain anything, not just a fixed set of strings.)
Thanks!
If what you want is to return the localized version of "This is an Apple/Orange/whatever", you'd want:
NSString *localizedVersion = NSLocalizedString(([NSString stringWithFormat:#"This is an %#", #"Apple"]), nil);
(I.e., the nesting of NSLocalizedString() and [NSString stringWithFormat:] are reversed.)
If what you want is the format to be localized, but not the substituted-in value, do this:
NSString *finalString = [NSString stringWithFormat:NSLocalizedString(#"SomeFormat", nil), #"Apple"];
And in your Localizable.strings:
SomeFormat = "This is an %#";
I just want to add one very helpful definition which I use in many of my projects.
Inspired by androids possibility, I've added this function to my header prefix file:
#define NSLocalizedFormatString(fmt, ...) [NSString stringWithFormat:NSLocalizedString(fmt, nil), __VA_ARGS__]
This allows you to define a localized string like the following:
"ExampleScreenAuthorizationDescriptionLbl"= "I authorize the payment of %# to %#.";
and it can be used via:
self.labelAuthorizationText.text = NSLocalizedFormatString(#"ExampleScreenAuthorizationDescriptionLbl", self.formattedAmount, self.companyQualifier);
For swift :
let myString = String(format: NSLocalizedString("I authorize the payment of %d ", comment: ""), amount)
extension String {
public var localizedString: String {
return NSLocalizedString(self, comment: "")
}
public func localizedString(with arguments: [CVarArg]) -> String {
return String(format: localizedString, arguments: arguments)
}
}
Localizable.string:
"Alarm:Popup:DismissOperation:DeviceMessage" = "\"%#\" will send position updates on a regular basis again.";
"Global:Text:Ok" = "OK";
Usage:
let message = "Alarm:Popup:DismissOperation:DeviceMessage".localizedString(with: [name])
and
let title = "Global:Text:Ok".localizedString
It turns out that a missing target entry is to blame. Just checking that my current build target includes the Localizable.string file solved the problem!
If you have more than one variable in your localized string can you use this solution:
In Localizable.strings
"winpopup" = "#name# wins a #type# and get #points# points(s)";
And use stringByReplacingOccurrencesOfString to insert the values
NSString *string = NSLocalizedString(#"winpopup", nil); //"#name# wins a #type# and get #points# points(s)"
NSString *foo = [string stringByReplacingOccurrencesOfString:#"#name#" withString:gameLayer.turn];
NSString *fooo = [foo stringByReplacingOccurrencesOfString:#"#type#" withString:winMode];
NSString *msg = [fooo stringByReplacingOccurrencesOfString:#"#points#" withString:[NSString stringWithFormat:#"%i", pkt]];
NSLog(#"%#", msg);
Your ideas should work. But if you are getting back the input parameter, that means that the input parameter was not found as a key in your Localizable.strings file. Check the syntax and location of that file.
This works for me:
NSMutableString *testMessage = [NSMutableString stringWithString:NSLocalizedString(#"Some localized text", #"")];
testMessage = [NSMutableString stringWithString:[testMessage stringByAppendingString:someStringVariable]];
I'm in my second day of learning Objective-C, Cocoa and IB. This is probably something really simple but I cannot work it out.
Basically, I have a form with a NSTextField, when the user types in this field and clicks an OK button the application will display an alert saying Hello followed by the value of text field.
It's all working apart from the string concatenation. I'm using the following code to concatenate the string "Hello" and the NSTextField value:
NSString *nameText = [NSString stringWithFormat:#"Hello %s", [nameTextField stringValue]];
When the user clicks the OK button an alert displays "Hello ‡√Ÿpˇ"!
Camsoft,
The NSString of Obj-C is an object, correct the format call with:
NSString *nameText = [NSString stringWithFormat:#"Hello %#",[nameTextField stringValue]];
Note the %# instead of %s .
Frank
stringValue returns NSString object and %s expects c-string parameter. Try to use %# instead:
NSString *nameText = [NSString stringWithFormat:#"Hello %#", [nameTextField stringValue]];