Question

I am using StoreKit to implement an in app purchase store in my application.

I have a custom design and it means that the value of the price should be white and large, and the currency symbol smaller, darker and aligned to the top of the price value.

I can get the currency symbol without any problems by using the NSLocale in SKproduct's priceLocale property, and the value of the price in the price property.

My problem is knowing when I should put the currency symbol before the price and when to put it after the price.

Examples:

  • $5,99
  • 0,79€

I could easily use the NSNumberFormatter to get this worked out "out of the box", but since my layout defines a different style for the value and currency symbol, I've found myself in a position where a more manual workaround is required.

Any thoughts ?

Était-ce utile?

La solution

The locale object doesn't seem to provide this information directly, but of course the number formatter must know it. You're not supposed to ask (new-style) number formatters for their format directly, although that'll probably work, and you can then look for the currency symbol, ¤, in the format string.

Possibly better would be to create a CFNumberFormatter, which does explicitly allow you to view its format, and then inspect that string:

// NSLocale and CFLocale are toll-free bridged, so if you have an existing
// NSNumberFormatter, you can get its locale and use that instead.
CFLocaleRef usLocale = CFLocaleCreate(NULL, CFSTR("en_US"));
CFNumberFormatterRef usFormatter = CFNumberFormatterCreate(NULL, usLocale, kCFNumberFormatterCurrencyStyle);
CFLocaleRef frLocale = CFLocaleCreate(NULL, CFSTR("fr_FR"));
CFNumberFormatterRef frFormatter = CFNumberFormatterCreate(NULL, frLocale, kCFNumberFormatterCurrencyStyle);

NSString * usString = (__bridge NSString *)CFNumberFormatterGetFormat(usFormatter);
NSString * frString = (__bridge NSString *)CFNumberFormatterGetFormat(frFormatter);

NSUInteger loc = ([usString rangeOfString:@"¤"]).location;
NSLog(@"Currency marker at beginning for US? %@", (loc == 0) ? @"YES" : @"NO");
loc = ([frString rangeOfString:@"¤"]).location;
NSLog(@"Currency marker at end for FR? %@", (loc == [frString length] - 1) ? @"YES" : @"NO");

Autres conseils

You have everything you need in your SKProduct instance. Just use NSNumberFormatter in conjunction and that's it.

NSNumberFormatter *priceFormatter = [[NSNumberFormatter alloc] init];
[priceFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];        

for (SKProduct *product in response.products) {
    [priceFormatter setLocale:product.priceLocale];
    NSLog(@"Price for %@ is: %@",product.localizedTitle,[priceFormatter stringFromNumber:product.price]);
}

Swift 3+

let priceFormatter = NumberFormatter()
priceFormatter.numberStyle = .currency

for product in response.products {
    priceFormatter.locale = product.priceLocale
    let localizedPrice = priceFormatter.string(from: product.price)
    print("Price for \(product.localizedTitle) is: \(localizedPrice)")
}

I use this solution (Swift):

let currencyFormat = CFNumberFormatterGetFormat(CFNumberFormatterCreate(nil, locale, .CurrencyStyle)) as NSString
let positiveNumberFormat = currencyFormat.componentsSeparatedByString(";")[0] as NSString
let currencySymbolLocation = positiveNumberFormat.rangeOfString("¤").location
return (currencySymbolLocation == 0) ? .Before : .After

The accepted answer should be fixed since the CFNumberFormatterGetFormat sometimes (for some locales) returns double value: ¤##,#00.0;-¤##,#00.0 which includes a negative number format. Make sure to parse that string.

My solution for this was to set the decimal style and set the minimum number of significant digits.

static NSNumberFormatter *NumberFormatter;

if (!NumberFormatter) {
    NumberFormatter = [[NSNumberFormatter alloc] init];
    [NumberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
    [NumberFormatter setUsesSignificantDigits:YES];
    [NumberFormatter setMinimumSignificantDigits:2];
}

NSString *formattedNumberString = [NumberFormatter stringFromNumber:@(valueInEuro)];

NSString *stringInEuro = [NSString stringWithFormat:@"€ %@", formattedNumberString];

I have created an extension of SKProduct, putting things where they belong imho.

extension SKProduct
{
    var localizedPrice: String {
        let numberFormatter = NSNumberFormatter()
        numberFormatter.numberStyle = .CurrencyStyle
        numberFormatter.locale = self.priceLocale
        numberFormatter.formatterBehavior = .Behavior10_4
        return numberFormatter.stringFromNumber(self.price)!
    }
}

That way of formatting is, by the way, also exactly what Apple suggests in the In-App Purchase Programming Guide, section Retrieving Product Information.

Swift 3

An extension function on Locale:

extension Locale {
    func IsCurrenySymbolAtStart() -> Bool {
        let currencyFormatter = NumberFormatter()
        currencyFormatter.numberStyle = .currency
        currencyFormatter.locale = self

        let positiveFormat = currencyFormatter.positiveFormat as NSString
        let currencySymbolLocation = positiveFormat.range(of: "¤").location

        return (currencySymbolLocation == 0)
    }
}

Usage:

let displayCurrencySymbolAtStart = NSLocale.current.IsCurrenySymbolAtStart()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top