Get currency code / symbol from language code in iOS [duplicate] - ios

This question already has answers here:
Get local currency in swift
(2 answers)
iPhone: How to get local currency symbol (i.e. "$" instead of "AU$")
(7 answers)
Closed 5 years ago.
In my swift project, I have to show the list of available Locale Identifiers. If user selects a locale like "ar" i.e. lanugage code alone. How I can get the currency symbols or number formats for this.
func listCountriesAndCurrencies() {
let localeIds = Locale.availableIdentifiers
var countryCurrency = [String: String]()
for localeId in localeIds {
let locale = Locale(identifier: localeId)
if let country = locale.regionCode, country.count == 2 { // how to get currency for locale without region code ?
if let currency = locale.currencySymbol {
countryCurrency[localeId] = currency
}
}
}
let sorted = countryCurrency.keys.sorted()
for country in sorted {
let currency = countryCurrency[country]!
print("country: \(country), currency: \(currency)")
}
}
My question is explained in the code comment

Related

Can't get correct number formatting as a string [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 2 years ago.
I've developed a custom control for money input, which contains UITextField and UILabel. When the user taps on it, it becomes active and switches to the UITextField for data input and accepts only numbers and dot symbol, when the user finishes editing it becomes passive and switches to UILabel just to show formatted money value. But there is one little issue which I'm unable to fix a lot of days already.
Let's say the user writes down 88.99 and presses done, this becomes "$ 88.99" in a UILabel, next when the user again taps on it to edit the initial value I get the following value "88.98999999999999". To not present the entire code I selected the core part in a playground format which gives the same result as in my complete project:
extension NumberFormatter {
static public func defaultCurrencyFormatter() -> NumberFormatter {
let formatter = NumberFormatter()
formatter.usesGroupingSeparator = true
formatter.numberStyle = .currency
formatter.currencySymbol = ""
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
return formatter
}
}
let stringValue = NumberFormatter.defaultCurrencyFormatter().number(from: "88.99")?.stringValue
print(stringValue) // result is Optional("88.98999999999999")
I have no idea why using this NumberFormatter I get such a result. I was thinking that explicitly setting minimumFractionDigits and maximumFractionDigits will solve my issue but it does not affect my result
NumberFormatter is legacy from objc and it operates with NSNumber/CGFloat etc. and usually it is helpful for localized text formatting. Much powerful and convenient parser for numbers is Scanner but if you don't have complex data structure to parse and don't want to deal with Floating-point error mitigation just use swift's Float:
// Float from string
if let float = Float("88.99") {
print(float)
// String from float
let text = String(float)
print(text)
}
Prints:
88.99
88.99
Try this:
extension String {
var currencyStyle: String? {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 1
formatter.maximumFractionDigits = 2
formatter.usesGroupingSeparator = true
formatter.groupingSize = 3
formatter.currencyGroupingSeparator = ","
formatter.currencyDecimalSeparator = "."
if let double = Double(self) {
let number = NSNumber(value: double)
return formatter.string(from: number)
}
return nil
}
}
to use it:
let str = "12388.98999999999999".currencyStyle
print(str) // Optional("12,388.99")

How to give users in iOS the choice to choose their own currency

I have an iOS app that keeps getting feedback from the users that they would like the ability to set their own currency type. Right now I'm using the currencyFormatter.locale to get the user local currency and use that for the app. My thought is that I might be able to create a tableView in the settings section of the app and let the users pick the currency they want to use.
I would save there desired currency and then use that instead of the locale one being displayed now.
To make this work what data would I need to pull? Would this data be supplied by Apple? I think I would need currency codes but would this be the correct data to display for the user to choose from?
I found this repo and it seems like this is something that would be useful, but it doesn't seem to be supported/updated anymore.
I just need some help being pointed in the correct direction for this, as my research isn't making any progress for me.
Money
EDIT
I found an app that I think is doing something similar to what I would like to implement.
You're right, you should make a list screen and let the users choose their desired currency from that. Save that currency and use it instead of the locale. You can use this code to get a list of currency names and currency symbols.
NSLocale *locale = [NSLocale currentLocale];
NSArray *currencyCodesArray = [NSLocale ISOCurrencyCodes];
NSMutableDictionary *currenciesDict = [NSMutableDictionary new];
for (NSString *currencyCode in currencyCodesArray) {
NSString *currencyName = [locale displayNameForKey:NSLocaleCurrencyCode value:currencyCode];
NSString *currencySymbol = [locale displayNameForKey:NSLocaleCurrencySymbol value:currencyCode];
if (currencyName != nil && currencySymbol != nil) {
[currenciesDict setValue:currencySymbol forKey:currencyName];
}
}
return currenciesDict;
Edit
Here's the same code in swift.
let locale = NSLocale.current as NSLocale
let currencyCodesArray = NSLocale.isoCurrencyCodes
var currenciesDict = [String: String]()
for currencyCode in currencyCodesArray {
let currencyName = locale.displayName(forKey: NSLocale.Key.currencyCode, value : currencyCode)
let currencySymbol = locale.displayName(forKey: NSLocale.Key.currencySymbol, value : currencyCode)
if let currencySymbol = currencySymbol, let currencyName = currencyName {
currenciesDict[currencySymbol] = currencyName
}
}
print(currenciesDict)
Edit 2
Same code with custom model.
This is how your custom model will look like.
class CurrencyModel {
var currencyName = ""
var currencyCode = ""
}
And this is how the code will look like.
let locale = NSLocale.current as NSLocale
let currencyCodesArray = NSLocale.isoCurrencyCodes
var currencies = [CurrencyModel]()
for currencyCode in currencyCodesArray {
let currencyName = locale.displayName(forKey:
NSLocale.Key.currencyCode, value : currencyCode)
let currencySymbol = locale.displayName(forKey:NSLocale.Key.currencySymbol, value : currencyCode)
if let currencySymbol = currencySymbol, let currencyName = currencyName {
let currencyModel = CurrencyModel()
currencyModel.currencyName = currencyName
currencyModel.currencyCode = currencyCode
currencies.append(currencyModel)
}
}
print(currencies)
You should set the currencySymbol of the formatter instead:
let currencyFormatter = NumberFormatter()
currencyFormatter.numberStyle = .currency
currencyFormatter.currencySymbol = "¥"
currencyFormatter.string(from: 123) // "¥123.00"
You can provide the user with a UITextField to let them enter any arbitrary string as the currency symbol.
If you want the user to choose a locale from a list and use that locale's currency symbol, the currencySymbol property of a Locale instance can also be used.
Clarification on locales and currencies:
Currencies and locales don't have a one-to-one correspondence. One currency can be used in multiple locales, but one locale usually has one corresponding currency, as there is a currencySymbol in Locale. And locale is used to decide where the currency symbol is. In France, for example, the currency symbol would be placed at the end. This means that if you just have a currency symbol, there is no "right" place for it in a string, because you have not specified a locale. So if you want the currency symbol to be at the user's expected place, ask the user for the locale they desire, and not the currency symbol. If you don't care whether the currency symbol is displayed at the user's expected place, then display it with the user's current locale.

Swift - Format textfield for a credit card [duplicate]

This question already has answers here:
Formatting a UITextField for credit card input like (xxxx xxxx xxxx xxxx)
(30 answers)
Closed 6 years ago.
I've been stuck on this for awhile now and I was wondering what is the best way to format a textfield for a credit card type format?
You can use Caishen framework.
It updates the contents of the textfield after every edit using this function :
public func formattedCardNumber(cardNumberString: String) -> String {
let regex: NSRegularExpression
let cardType = cardTypeRegister.cardTypeForNumber(Number(rawValue: cardNumberString))
do {
let groups = cardType.numberGrouping
var pattern = ""
var first = true
for group in groups {
pattern += "(\\d{1,\(group)})"
if !first {
pattern += "?"
}
first = false
}
regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions())
} catch {
fatalError("Error when creating regular expression: \(error)")
}
return NSArray(array: self.splitString(cardNumberString, withRegex: regex)).componentsJoinedByString(self.separator)
}

Convert high numbers to lower format [duplicate]

This question already has answers here:
NSNumberFormatter : Show 'k' instead of ',000' in large numbers?
(3 answers)
How to get file size properly and convert it to MB, GB in Cocoa? [duplicate]
(3 answers)
Closed 6 years ago.
How can I change high numbers to something like:
1,000 = 1K
1,250 = 1,2K
10,200 = 10,2K
102,000 = 102K
1,200,000 = 1,2M
Or something like that?
This is how I set the number:
textCell?.ll1.text = "\(String(thumb[indexPath.row].count))"
textCell?.ll2.text = "\(String(love[indexPath.row].count))"
let formatter = NSByteCountFormatter()
That's it ;)
Examples:
let oneFormattedNumber = formatter.stringFromByteCount(1025000000000)
let formattedList = [1_000, 1_250, 10_200, 102_000, 1_200_000].map(formatter.stringFromByteCount)
You can add this functionality as an extension to Int:
extension Int {
func shortLiteralDescription() -> String {
var factor = 0
let tokens = ["","K", "M", "G","T","P"] //If you think you will need to express more, add them here
var value = Double(self);
while (value > 1000) {
value /= 1000
factor++
}
return "\(value)\(tokens[factor])"
}
}
And then:
400200.shortLiteralDescription() //400.2K
4000.shortLiteralDescription() //4.0K

NSLocale to Country name [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have seen this answered in objective-C, but I don't know how to convert to swift.
My app receives the public information of a user from Facebook, and I need to convert the locale into the country name.
FBRequestConnection.startForMeWithCompletionHandler({
connection, result, error in
user["locale"] = result["locale"]
user["email"] = result["email"]
user.save()
println(result.locale)
})
For example, for a French user, the code sends "Optional(fr_FR)" to the log. However I need it to just send the country name. According to localeplanet.com, the display name of "fr_FR" is "French (France)". So in the log all I want is "France".
Working off of this SO question, I've whipped up a Swift translation. Try this:
let locale: NSLocale = NSLocale(localeIdentifier: result.locale!)
let countryCode = locale.objectForKey(NSLocaleCountryCode) as String
var country: String? = locale.displayNameForKey(NSLocaleCountryCode, value: countryCode)
// According to the docs, "Not all locale property keys
// have values with display name values" (thus why the
// "country" variable's an optional). But if this one
// does have a display name value, you can print it like so.
if let foundCounty = country {
print(foundCounty)
}
Updated for Swift 4:
FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"locale"]).start { (connection, result, error) in
guard let resultDictionary = result as? [String:Any],
let localeIdentifier = resultDictionary["locale"] as? String else {
return
}
let locale: NSLocale = NSLocale(localeIdentifier: localeIdentifier)
if let countryCode = locale.object(forKey: NSLocale.Key.countryCode) as? String,
let country = locale.displayName(forKey: NSLocale.Key.countryCode, value: countryCode) {
print(country)
}
}

Resources