19

In Objective C, is there any way to format an integer to ordinals 1 => "1st", 2 => "2nd" etc... that works for any language? So if the user is French he will see "1er", "2ieme" etc..

Thanks a lot!

Edit: This is for an iOs app

Johann
  • 12,158
  • 11
  • 62
  • 89

5 Answers5

14

Have you taken a look at TTTOrdinalNumberFormatter which is in FormatterKit? It works great, and I'm pretty sure it's exactly what you're looking for.


Here's an example taken from the kit:

TTTOrdinalNumberFormatter *ordinalNumberFormatter = [[TTTOrdinalNumberFormatter alloc] init];
[ordinalNumberFormatter setLocale:[NSLocale currentLocale]];
[ordinalNumberFormatter setGrammaticalGender:TTTOrdinalNumberFormatterMaleGender];
NSNumber *number = [NSNumber numberWithInteger:2];
NSLog(@"%@", [NSString stringWithFormat:NSLocalizedString(@"You came in %@ place!", nil), [ordinalNumberFormatter stringFromNumber:number]]);

Assuming you've provided localized strings for "You came in %@ place!", the output would be:

* English: "You came in 2nd place!"
* French: "Vous êtes venu à la 2eme place!"
* Spanish: "Usted llegó en 2.o lugar!"
sudo rm -rf
  • 29,408
  • 19
  • 102
  • 161
  • Don't forget you also need to localize the grammatical gender since the same noun can have different genders in different languages. – Mihai Damian Jun 05 '15 at 11:05
8

The solution is immediately available from NSNumberFormatter:

- (NSString *)getOrdinalStringFromInteger:(NSInteger)integer
{
    NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
    [formatter setLocale:[NSLocale currentLocale]];
    [formatter setNumberStyle:NSNumberFormatterOrdinalStyle];
    return [formatter stringFromNumber:[NSNumber numberWithInteger:integer]];
}
Henry95
  • 623
  • 6
  • 16
3

You could use ICU, which includes a way of doing what you describe:

http://icu-project.org/apiref/icu4c/classRuleBasedNumberFormat.html

You don't say what context you're using Objective-C in, but if you're writing for Cocoa, ICU is actually present. However, reaching down to talk to it directly can be a bit tricky.

[edited to link to someone who actually seems to have figured out how to build ICU and link it]

How to build ICU so I can use it in an iPhone app?

Community
  • 1
  • 1
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Would this work for ios? Is there any code sample I could look at? – Johann Dec 06 '11 at 17:34
  • icu is present on ios (ios uses it for regex, date/locale formatting, etc.) but the headers exposed are very limited. I suppose you could try including it as a library wholesale, but it's kind of large and its' tricky to build: see http://stackoverflow.com/questions/8126233/how-to-build-icu-so-i-can-use-it-in-an-iphone-app – matt Dec 06 '11 at 17:40
  • i just published a pod that uses the ICU4C underneath from the system libraries. Before using, please check how the example project works: https://github.com/dimat/DMNumberSpellOutFormatter – Dmitry Jan 29 '17 at 23:25
2

You need a rule set for each language you want to support. Any language is asking too much: they are all wildly different. First, create a rule set class which holds the regular and the exception cases for a given language. That class needs a single method that takes a number and returns a string suffix (or the number plus the suffix.) Create rule set instances (statically) for each language you care about.

Then create a category on NSNumber that returns a suffix pulled from the appropriate rule set for whatever language the user needs (system locale, or some choice they make, or case by case.)

Each language has different rules, of course. For example, English is relatively complicated: 1st, 2nd, 3rd, 4th, 5th, ... 20th and then it starts again at st, nd, rd, th... Unit 1s, 2s, 3s and 4s are always special cases. Zero is 'th' (zeroth, hundredth, millionth etc.)

French is different. 1er, then it's x ième all the way up. (These are usually abbreviated to just 're' and 'e', making French quite easy.)

Japanese gets very odd. Cardinal 1, 2, 3, 4: (ichi, ni, san, yon) becomes tsuichi, futsuka, mikka and yokka. Those aren't suffixes though: the numbers are named differently when they're used as ordinals. Luckily, because that's incredibly confusing, you can just stick a kanji 'kai' character (which looks like a box in box) after the number and everyone knows what you mean.

Tim
  • 5,024
  • 2
  • 30
  • 58
  • 1
    I like this theoretical overview, but i miss the solution. It only points how it may be hard to do. – Frizi Dec 06 '11 at 18:00
  • 1
    That is a fair point Frizi. It *is* hard though. The main point of my answer is the category, which is the "Objective C" way to solve problems like this. – Tim Dec 06 '11 at 18:15
1

Swift:

func getOrdinalDegreeValue() -> String? {
    let formatter = NumberFormatter()
    formatter.locale = Locale.current
    formatter.numberStyle = .ordinal
    return formatter.string(from: NSNumber(value: 1)) // Number
}

1st

Hemang
  • 26,840
  • 19
  • 119
  • 186