/// <summary> /// Creates or reuses a numbering system for the specified <see cref="Locale"/>. /// </summary> /// <param name="locale"> /// The locale. /// </param> /// <returns> /// A numbering system that is the best for the <paramref name="locale"/>. /// </returns> /// <remarks> /// The locale identifier can use the "u-nu-XXX" extension to specify a numbering system. /// If the extension's numbering system doesn't exist or is not specified, /// then the default numbering system for the locale is used. /// <para> /// The <see href="http://unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems">other numbering systems</see> /// ("u-nu-native", "u-nu-finance" and "u-nu-traditio") are also allowed. /// </para> /// </remarks> public static NumberingSystem Create(Locale locale) { string name; if (locale.Id.UnicodeExtension.Keywords.TryGetValue("nu", out name)) { try { if (Others.Contains(name)) { // Consistency is the hobgoblin of small minds. var other = name == "traditio" ? "traditional" : name; name = locale.Find($"ldml/numbers/otherNumberingSystems/{other}").Value; } return(NumberingSystem.Create(name)); } catch (KeyNotFoundException) { // eat it, will fallback to default numbering system. } } // Find the default numbering system for the locale. var ns = locale.Find("ldml/numbers/defaultNumberingSystem/text()").Value; return(NumberingSystem.Create(ns)); }
string Transform(string s, string currencyCode, string pattern, NumberFormatInfo nfi) { var sb = new StringBuilder(s); // Replace digits with number system digits. for (int i = 0; i < 10; ++i) { sb.Replace(digits[i], NumberingSystem.Digits[i]); } // Replace currency symbol if (s.Contains("¤")) { if (currencyCode == null) { currencyCode = Locale.CurrencyCode; } if (s.Contains("¤¤¤¤¤")) { throw new NotImplementedException(); } else if (s.Contains("¤¤¤¤")) { throw new NotImplementedException(); } else if (s.Contains("¤¤¤")) { // Currency display name throw new NotImplementedException(); } else if (s.Contains("¤¤")) { // ISO currency symbol sb.Replace("¤¤", currencyCode); } else if (s.Contains("¤")) { // Standard currency symbol var symbol = $"ldml/numbers/currencies/currency[@type='{currencyCode}']/symbol"; sb.Replace("¤", Locale.Find(symbol).Value); } } return(sb.ToString()); }
/// <summary> /// Creates the symbols for the specified <see cref="Locale"/>. /// </summary> /// <param name="locale"> /// The locale. /// </param> /// <returns> /// The symbols that are the best for the <paramref name="locale"/>. /// </returns> public static NumberSymbols Create(Locale locale) { var ns = NumberingSystem.Create(locale).Id; var path = $"ldml/numbers/symbols[@numberSystem='{ns}']/"; var symbols = new NumberSymbols { Decimal = locale.Find(path + "decimal").Value, Exponential = locale.Find(path + "exponential").Value, Group = locale.Find(path + "group").Value, Infinity = locale.Find(path + "infinity").Value, List = locale.Find(path + "list").Value, MinusSign = locale.Find(path + "minusSign").Value, NotANumber = locale.Find(path + "nan").Value, PercentSign = locale.Find(path + "percentSign").Value, PerMille = locale.Find(path + "perMille").Value, PlusSign = locale.Find(path + "plusSign").Value, SuperscriptingExponent = locale.Find(path + "superscriptingExponent").Value }; var found = locale.FindOrDefault(path + "currencyDecimal"); if (found != null) { symbols.CurrencyDecimal = found.Value; } found = locale.FindOrDefault(path + "currencyGroup"); if (found != null) { symbols.CurrencyGroup = found.Value; } return(symbols); }
void NumberInfo(string currencyCode, int nDigits, out string pattern, out NumberFormatInfo nfi) { nfi = new NumberFormatInfo { NaNSymbol = Symbols.NotANumber, NegativeSign = Symbols.MinusSign, NegativeInfinitySymbol = Symbols.MinusSign + Symbols.Infinity, NumberDecimalSeparator = Symbols.Decimal, NumberGroupSeparator = Symbols.Group, // NativeDigits is NOT used the formatter!! //NativeDigits = NumberingSystem.Digits, PercentDecimalSeparator = Symbols.Decimal, PercentSymbol = Symbols.PercentSign, PerMilleSymbol = Symbols.PerMille, PositiveInfinitySymbol = Symbols.Infinity, PositiveSign = Symbols.PlusSign }; pattern = null; if (Options.Style == NumberStyle.Decimal) { var path = $"ldml/numbers/decimalFormats[@numberSystem='{NumberingSystem.Id}']/decimalFormatLength[not(@type)]/decimalFormat/pattern"; pattern = Locale.Find(path).Value; } else if (Options.Style == NumberStyle.Percent) { var path = $"ldml/numbers/percentFormats[@numberSystem='{NumberingSystem.Id}']/percentFormatLength[not(@type)]/percentFormat/pattern"; pattern = Locale.Find(path).Value; } else if (Options.Style == NumberStyle.Scientific) { var path = $"ldml/numbers/scientificFormats[@numberSystem='{NumberingSystem.Id}']/scientificFormatLength[not(@type)]/scientificFormat/pattern"; pattern = Locale.Find(path).Value; pattern = pattern == "#E0" ? "0.0######E0" : pattern; } else if (Options.Style == NumberStyle.CurrencyStandard || Options.Style == NumberStyle.CurrencyAccounting) { nfi.NumberDecimalSeparator = Symbols.CurrencyDecimal; nfi.NumberGroupSeparator = Symbols.CurrencyGroup; string path = null; if (Options.Style == NumberStyle.CurrencyStandard) { path = $"ldml/numbers/currencyFormats[@numberSystem='{NumberingSystem.Id}']/currencyFormatLength/currencyFormat[@type='standard']/pattern"; } else if (Options.Style == NumberStyle.CurrencyAccounting) { path = $"ldml/numbers/currencyFormats[@numberSystem='{NumberingSystem.Id}']/currencyFormatLength/currencyFormat[@type='accounting']/pattern"; } pattern = Locale.Find(path).Value; // Apply currency decimal places if (currencyCode == null) { currencyCode = Locale.CurrencyCode; } var digits = Cldr.Instance .GetDocuments("common/supplemental/supplementalData.xml") .FirstElementOrDefault($"supplementalData/currencyData/fractions/info[@iso4217='{currencyCode}']/@digits"); if (digits != null) { int significantDigits = Int32.Parse(digits.Value); pattern = significantDigitsPattern.Replace(pattern, "." + new String('0', significantDigits)); } } else { throw new NotImplementedException(); } // Grouping of digits. var useGrouping = Options.UseGrouping; if (useGrouping) { // Grouping digits, "#,##,##0" => [3, 2, 1] var parts = pattern.Split(';'); nfi.NumberGroupSizes = groupingPattern .Matches(parts[0]) .Cast <Match>() .Skip(1) .Reverse() .Select(m => m.Length - 1) .DefaultIfEmpty(3) .ToArray(); // Don't group if min grouping digits is not met. var minElement = Locale.FindOrDefault("ldml/numbers/minimumGroupingDigits"); if (minElement != null) { var minDigits = Int32.Parse(minElement.Value) + nfi.NumberGroupSizes[0]; useGrouping = nDigits > minDigits; } } if (!useGrouping) { nfi.NumberGroupSeparator = ""; } nfi.PercentGroupSizes = nfi.NumberGroupSizes; nfi.PercentGroupSeparator = nfi.NumberGroupSeparator; }