Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a pluralized string and a number formatter at the same time

I want to show a localized string in iOS that supports the following outputs:

1 mile

1.5 miles

2 miles

1,5 miles

I can use a .stringsdict file to make the pluralization work in a way that is localizable. However, I want the number passed in to have a decimal part and I only want to show 0 or 1 decimal places. Furthermore, the number should be formatted based on locale (i.e. show the correct decimal separator).

It occurs to me the solution may take one of two forms, but I can't get either working:

  1. pass in a number representation to stringsdict alongside a string representation
  2. format the number inside the stringsdict using the IEEE printf specification
like image 263
ganzogo Avatar asked Aug 31 '25 22:08

ganzogo


2 Answers

Okay, I actually got (1) working in the end, but it feels kind of hacky, so if anyone knows a better answer, I would still like to hear it.

let miles: Double = 1.5

let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 1
let milesString = formatter.string(from: NSNumber(value: miles))!

let formatString = NSLocalizedString("key", comment: "")
let string = String(format: formatString, arguments: [miles, milesString])

And the stringsdict looks like:

<dict>
        <key>key</key>
        <dict>
                <key>NSStringLocalizedFormatKey</key>
                <string>%1$#@miles@</string>
                <key>miles</key>
                <dict>
                        <key>NSStringFormatSpecTypeKey</key>
                        <string>NSStringPluralRuleType</string>
                        <key>NSStringFormatValueTypeKey</key>
                        <string>f</string>
                        <key>one</key>
                        <string>1 mile</string>
                        <key>other</key>
                        <string>%2$@ miles</string>
                </dict>
        </dict>
</dict>
like image 124
ganzogo Avatar answered Sep 03 '25 14:09

ganzogo


MeasurementFormatter is exactly made for this kind of thing. You can use:

let formatter = MeasurementFormatter()
formatter.unitStyle = .long
formatter.unitOptions = .providedUnit
let string = formatter.string(from: Measurement(value: 1.5, unit: UnitLength.miles))

MeasurementFormatter will handle all the plural and localisation for you.

If you only want to localise the number, but not the unit, you can set the formatter.locale to an English locale, and set formatter.numberFormatter.locale to the local locale:

formatter.locale = Locale(identifier: "en")
formatter.numberFormatter.locale = Locale.current
like image 31
Sweeper Avatar answered Sep 03 '25 13:09

Sweeper