How do I do proper regional formatting in iOS? (Xamarin.Forms)

I have read about a million posts on the topic and all the approaches I have seen thus far appear to be incomplete.

Configuration 1
Language = Español (España), Region = España.
Using this configuration I create a new CultureInfo("es-ES") and assign it to DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture, everything works as expected. My numbers are formatted correctly I.e. 234,55, the numeric keyboard pops up using the "," as decimal separator. Life is good.

Configuration 2
Language = Español (España), Region = Canada.
Using this configuration I create a new CultureInfo("es-CA") which of course fails. I then fallback to new CultureInfo("es") and assign it to DefaultThreadCurrentCulture and DefaultThreadCurrentUICulture. Under this configuration my numbers are formatted using "," which I expect but the numeric keyboard utilizes "." as the decimal separator.

Is it possible to have the keyboard respect the threads culture settings? How does iOS decide that the decimal separator should be "." when Canada supports point and comma?

Best Answer

  • edited February 18 Accepted Answer

    I just wanted to follow up on this thread. I ended up taking a different approach as I could find no way to influence the decimal place character within the iOS keyboard. I ended up opting to create a neutral culture from the device language code and then configure the number and date formats as required by my application. The resulting CultureInfo object is then assigned to both CultureInfo.DefaultThreadCurrentCultureInfo and CultureInfo.DefaultThreadCurrentUICulture. This was the best compromise I could think of. By all means if you see a potential issue with this approach feel free to comment. And yes I know that a few locales will need to be mapped to .net locales since they do not map directly. I will add them in later.

        public CultureInfo GetCurrentCultureInfo()
        {
            try
            {
                return new CultureInfo(NSLocale.CurrentLocale.LocaleIdentifier.Replace("_", "-"));
            }
            catch (CultureNotFoundException cultureNotFoundException1)
            {
                _loggingService.Error(cultureNotFoundException1);
    
                try
                {
                    return GetNeutralLanguage(NSLocale.CurrentLocale);
                }
                catch (CultureNotFoundException cultureNotFoundException2)
                {
                    _loggingService.Error(cultureNotFoundException2);
    
                    return GetNeutralLanguage(NSLocale.CurrentLocale, "en");
                }
            }
        }
    
        private static CultureInfo GetNeutralLanguage(NSLocale locale, string languageCode = null)
        {
            using (var dateFormatter = new NSDateFormatter {DateStyle = NSDateFormatterStyle.Short, TimeStyle = NSDateFormatterStyle.None, Locale = locale})
            {
                return new CultureInfo(languageCode ?? locale.LanguageCode)
                {
                    NumberFormat =
                    {
                        NumberDecimalSeparator = locale.DecimalSeparator,
                        CurrencyDecimalSeparator = locale.DecimalSeparator,
                        CurrencyGroupSeparator = locale.GroupingSeparator,
                        NumberGroupSeparator = locale.GroupingSeparator,
                        CurrencySymbol = locale.CurrencySymbol
                    },
                    DateTimeFormat =
                    {
                        ShortDatePattern = dateFormatter.DateFormat
                    }
                };
            }
        }
    

Answers

  • JuniorJiangJuniorJiang Member, Xamarin Team Xamurai

    Hi @pasteusernamehere ,

    Is it possible to have the keyboard respect the threads culture settings? How does iOS decide that the decimal separator should be "." when Canada supports point and comma?

    Onein IOS is possible.Set your desired language code ("en-US", "de-CH", etc.) to the variable languageCode.

    var key = new NSString("AppleLanguages"); 
    string[] languageValues = { languageCode };
    NSUserDefaults.StandardUserDefaults.SetValueForKey(NSArray.FromObjects(languageValues), key);
    NSUserDefaults.StandardUserDefaults.Synchronize();
    

    Two, iOS decide that the decimal separator should be "." mostly by language.

  • @JuniorJiang said:
    Hi @pasteusernamehere ,

    Is it possible to have the keyboard respect the threads culture settings? How does iOS decide that the decimal separator should be "." when Canada supports point and comma?

    Onein IOS is possible.Set your desired language code ("en-US", "de-CH", etc.) to the variable languageCode.

    var key = new NSString("AppleLanguages"); 
    string[] languageValues = { languageCode };
    NSUserDefaults.StandardUserDefaults.SetValueForKey(NSArray.FromObjects(languageValues), key);
    NSUserDefaults.StandardUserDefaults.Synchronize();
    

    Doing this appears to have zero impact on the numeric keyboard presented. If I set the language code to "en-US" and the system is locale is "en-ES" the keyboard still presents "," as the decimal separator.

  • pasteusernameherepasteusernamehere Member ✭✭
    edited February 18 Accepted Answer

    I just wanted to follow up on this thread. I ended up taking a different approach as I could find no way to influence the decimal place character within the iOS keyboard. I ended up opting to create a neutral culture from the device language code and then configure the number and date formats as required by my application. The resulting CultureInfo object is then assigned to both CultureInfo.DefaultThreadCurrentCultureInfo and CultureInfo.DefaultThreadCurrentUICulture. This was the best compromise I could think of. By all means if you see a potential issue with this approach feel free to comment. And yes I know that a few locales will need to be mapped to .net locales since they do not map directly. I will add them in later.

        public CultureInfo GetCurrentCultureInfo()
        {
            try
            {
                return new CultureInfo(NSLocale.CurrentLocale.LocaleIdentifier.Replace("_", "-"));
            }
            catch (CultureNotFoundException cultureNotFoundException1)
            {
                _loggingService.Error(cultureNotFoundException1);
    
                try
                {
                    return GetNeutralLanguage(NSLocale.CurrentLocale);
                }
                catch (CultureNotFoundException cultureNotFoundException2)
                {
                    _loggingService.Error(cultureNotFoundException2);
    
                    return GetNeutralLanguage(NSLocale.CurrentLocale, "en");
                }
            }
        }
    
        private static CultureInfo GetNeutralLanguage(NSLocale locale, string languageCode = null)
        {
            using (var dateFormatter = new NSDateFormatter {DateStyle = NSDateFormatterStyle.Short, TimeStyle = NSDateFormatterStyle.None, Locale = locale})
            {
                return new CultureInfo(languageCode ?? locale.LanguageCode)
                {
                    NumberFormat =
                    {
                        NumberDecimalSeparator = locale.DecimalSeparator,
                        CurrencyDecimalSeparator = locale.DecimalSeparator,
                        CurrencyGroupSeparator = locale.GroupingSeparator,
                        NumberGroupSeparator = locale.GroupingSeparator,
                        CurrencySymbol = locale.CurrencySymbol
                    },
                    DateTimeFormat =
                    {
                        ShortDatePattern = dateFormatter.DateFormat
                    }
                };
            }
        }
    
Sign In or Register to comment.