Format integers in Localizable.stringsdict

I'm writing an app in swift that is being localized and I have a question around formatting integers.


Here is a simplified version of my Localizable.stringsdict file:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>RecordsFound</key>
  <dict>
    <key>NSStringLocalizedFormatKey</key>
    <string>%#@value@</string>
    <key>value</key>
    <dict>
      <key>NSStringFormatSpecTypeKey</key>
      <string>NSStringPluralRuleType</string>
      <key>NSStringFormatValueTypeKey</key>
      <string>d</string>
      <key>one</key>
      <string>$d record found</string>
      <key>other</key>
      <string>$d records found</string>
    </dict>
  </dict>
</plist>


Making this call:


String(format: NSLocalizedString("RecordsFound", comment: ""), 1)


returns "1 record found" (singular) and making this call:


String(format: NSLocalizedString("RecordsFound", comment: ""), 2)


returns "2 records found" (plural).


All good so far. However making this call:


String(format: NSLocalizedString("RecordsFound", comment: ""), 15387)


returns "15387 records found". I'd like it to return "15,387 records found" (with the thousand separator). My Language & Region settings are set to use thousand separators but it doesn't seem to pick this up.


I could use NumberFormatter but of course that returns a string which breaks the pluralization rules. I could also pass 2 parameters (the integer itself and a string representation of the integer) but that gets messy especially when there are already multiple integers being passed (some of my strings contain multiple integers and therefore multiple pluralization rules - one for each integer).


Is it possible to add formatting rules to integers in Localizable.stringsdict? If not what's the recommended method of doing this?

In this case I would write a wrapper func:

func numberOfRecordsToString(nbRecords nb: Int {
// that builds the number with numberFormatter
// builds the name with the right plural rule
// assemble the 2 and return
}

then call

print(numberOfRecordsToString(nbRecords: 15387))

The way I read the documentation, the formatting of the %d number itself, within each plural case, follows the standard iEEE rules:


pubs.opengroup.org/onlinepubs/009695399/functions/printf.html


That would suggest the correct way to get the separator is to use the flag character, as in: %'d. (A single ASCII quote after the percent sign.) I would also assume that would give you the correct localized separator.


(Did you mean %d in lines 16-18?)

Thanks for replying Qincey,


I tried that but then it just puts 'd in the string (so it comes out as " 'd records found").


Yes I did mean %d. I edited the file in my post to simplify it as the original file has multiple pluralization rules and I didn't want that to overcomplicate the question. The real file has %1$d because there may be more than one parameter passed and it may be in a different order for some localizations.

Thanks Claude.


That may be the only solution. It's a shame if that's the only way though as is seems a little messy escpecially if you have a string with multiple integers. I'm surprised there isn't a built-in method to achieve this as I'd imagine it's quite common. It seems you can do something similar with floats where you can specify the number of decimal places but not thousand separators.

I wanted to solve the same problem, ie. being able to combine a custom NumberFormatter with the pluralization rules. Here's what seems to be working for me:


<key>FormattedHours</key>
    <dict>
        <key>NSStringLocalizedFormatKey</key>
        <string>%1$@ %2$#@hours@</string>
        <key>hours</key>
        <dict>
            <key>NSStringFormatSpecTypeKey</key>
            <string>NSStringPluralRuleType</string>
            <key>NSStringFormatValueTypeKey</key>
            <string>f</string>
            <key>one</key>
            <string>hour</string>
            <key>other</key>
            <string>hours</string>
        </dict>
    </dict>


Then to use:


let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = 2

let hours = 1.0
let formattedHours = formatter.string(from: NSNumber(floatLiteral: hours)) ?? ""
let hoursString = String(format: NSLocalizedString("FormattedHours", comment: ""), arguments: formattedHours, hours)


So now my output looks like this:


let hours = 1.0 // prints "1 hour"
let hours = 10.5 // prints "10.5 hours"

The localized format string methods will format numbers for you.

String.localizedStringWithFormat(NSLocalizedString("RecordsFound", comment: ""), 15387)

Will return "15,387 records found"

Alternatively, especially if you need to specify a different Locale

String(format: NSLocalizedString("RecordsFound", comment: ""), locale: Locale.current, arguments: [15387])

Will also return "15,387 records found"

This doesn't have the full freedom of allowing you to pass any string in, but it does keep the stringsdict file the same and doesn't restrict translations.

Format integers in Localizable.stringsdict
 
 
Q