64

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?

Sweeper
  • 213,210
  • 22
  • 193
  • 313

5 Answers5

83

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.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    Is there a way to specify the order of the parameters or insert a single parameter multiple times? In some languages the insertion order might be reversed. Android allows this by using `%1` and `%2` before the format specifier. – Suragch Nov 30 '17 at 09:01
  • 4
    Is using `%@` better than `%s` (for strings)? – Suragch Nov 30 '17 at 09:03
  • @Suragch: There are encoding problems with `%s`, see https://stackoverflow.com/a/23672885 for an example. – I *think* that positional parameters like `%1$s` work here as well. – Martin R Nov 30 '17 at 09:11
  • 2
    This code won’t localize the numbers themselves — for example in German they use periods for commas and vice-versa, and in Arabic their digits are different codepoints. Use String.localizedStringWithFormat() or String(format: "%f", locale: Locale.current, number) instead. – Wil Shipley Jan 20 '18 at 00:04
  • 1
    @WilShipley: You are completely right. Perhaps that method did not exist then or I did not think about it. I still think that I answered the question *"I don't think you can use %@ to indicate that there is something to be placed there"*, but I have added a link to the better solution. – Martin R Jan 20 '18 at 08:45
  • Thanks Martin! I didn’t know about the other two methods but someone from that AppKit team pointed them out to me. So hopefully we can spread the word. – Wil Shipley Jan 21 '18 at 10:12
  • I am literally suprised "You have successfully checked-in to %@ %@" = "%@ %@ のチェックインが完了しました"; let translatedText = NSLocalizedString("You have successfully checked-in to %@ %@", comment: "") let checkInMessage = String.localizedStringWithFormat(translatedText, spaceTypeName.localizedText(), spaceName) The above is not working…can someone help – Sujit Baranwal Jul 20 '21 at 06:10
62

From WWDC 2017:

let format = NSLocalizedString("%d popular languages", comment:"Number of popular languages")
label.text = String.localizedStringWithFormat(format, popularLanguages.count)
Michal
  • 15,429
  • 10
  • 73
  • 104
Niklas
  • 1,322
  • 14
  • 11
  • 5
    I believe this is the best answer because String.localizedStringWithFormat(_, ...) will localize the actual digits of the numbers (and swap commas and periods for German, for example), and String(format:...) will not. You can also use `String(format: "%f", locale: Locale.current, number)`. – Wil Shipley Jan 20 '18 at 00:01
  • 1
    what if the variables to be substituted are in CVarArg? – shakram02 Dec 17 '18 at 18:56
3

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
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
2

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/

Magnus
  • 391
  • 1
  • 7
  • 35
TALE
  • 960
  • 13
  • 22
-5

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/

Naishta
  • 11,885
  • 4
  • 72
  • 54