public ReadOnlyDictionary <PluralCategories, ReadOnlyDictionary <int, NumberFormatPattern> > GetCompactNotationFormats(NumberCompactDisplayFormat style) { XElement decimalFormats = elements.FirstOrDefault(v => v.Name.LocalName == "decimalFormats"); if (decimalFormats == null) { return(this.Parent.GetCompactNotationFormats(style)); } if (CldrUtility.IsAlias(decimalFormats, out string numberSystem)) { return(GetFormat(locale, numberSystem).GetCompactNotationFormats(style)); } Dictionary <PluralCategories, Dictionary <int, NumberFormatPattern> > dict = new Dictionary <PluralCategories, Dictionary <int, NumberFormatPattern> >(); foreach (PluralCategories kind in pluralRules.EnumerateCategories()) { dict[kind] = new Dictionary <int, NumberFormatPattern>(); } XElement decimalFormat = decimalFormats.XPathSelectElement(String.Format("decimalFormatLength[@type = '{0}']/decimalFormat", IntlProviderOptions.ToStringValue(style))); foreach (XElement pattern in decimalFormat.XPathSelectElements("pattern")) { PluralCategories count = IntlProviderOptions.ParseEnum <PluralCategories>(pattern.Attribute("count").Value); dict[count][pattern.Attribute("type").Value.Length - 1] = ParseNumberFormatPattern(pattern.Value); } if (decimalFormat.Attribute("inherits") != null) { ReadOnlyDictionary <PluralCategories, ReadOnlyDictionary <int, NumberFormatPattern> > parent = this.Parent.GetCompactNotationFormats(style); foreach (KeyValuePair <PluralCategories, ReadOnlyDictionary <int, NumberFormatPattern> > e in parent) { CldrUtility.CopyPatternFromParent(dict[e.Key], e.Value); } } return(new ReadOnlyDictionary <PluralCategories, ReadOnlyDictionary <int, NumberFormatPattern> >(dict.ToDictionary(v => v.Key, v => new ReadOnlyDictionary <int, NumberFormatPattern>(v.Value)))); }
private CldrPluralRules(XElement rules) { this.PluralCategories = PluralCategories.Other; foreach (XElement node in rules.Elements("pluralRule")) { PluralCategories category = IntlProviderOptions.ParseEnum <PluralCategories>(node.Attribute("count").Value); if (category != PluralCategories.Other) { string textContent = node.Value; ruleset[category] = ParseExpression(textContent); this.PluralCategories |= category; } } }
public FormattedString Format(double value, NumberFormat formatter, RelativeTimeNumericFormat numeric, out string[] units) { FormattedString pattern; if (numeric == RelativeTimeNumericFormat.Auto) { double intValue = Math.Floor(value); if (intValue == value && intValue >= Int32.MinValue && intValue <= Int32.MaxValue) { if (relative.TryGetValue((int)intValue, out pattern)) { units = new string[1]; return(pattern); } } } CldrPluralRules pluralRules = CldrPluralRules.Resolve(PluralRuleType.Cardinal, locale); PluralCategories key = pluralRules.Match(value); if ((value < 0 ? past : future).TryGetValue(key, out pattern)) { FormattedString numParts = formatter.Format(Math.Abs(value)); FormattedPart[] parts = pattern.GetParts(); int index = Array.FindIndex(parts, v => v.Type == FormattedPartType.Placeholder); string unitStr = IntlProviderOptions.ToStringValue(unit); if (numParts.PartCount > 1) { List <FormattedPart> parts1 = new List <FormattedPart>(parts); parts1.RemoveAt(index); parts1.InsertRange(index, numParts); units = new string[parts1.Count]; for (int j = 0, len2 = numParts.PartCount; j < len2; j++) { units[index + j] = unitStr; } return(new FormattedString(parts1)); } else { units = new string[parts.Length]; units[index] = unitStr; parts[index] = numParts[0]; return(new FormattedString(parts)); } } units = new string[0]; return(FormattedString.Empty); }
public static CldrRelativeTimeFormat Resolve(string locale, string type) { string key = locale + "/" + type; if (resolvedPatterns.TryGetValue(key, out CldrRelativeTimeFormat cached)) { return(cached); } CldrRelativeTimeFormat formatter = new CldrRelativeTimeFormat(locale, type); XElement field = xDocument.XPathSelectElement(String.Format("/root/fields[@locale = '{0}']/field[@type = '{1}']", locale, type)); if (field == null) { throw new InvalidOperationException("Unknown locale or type"); } if (CldrUtility.IsAlias(field, out string use)) { return(resolvedPatterns.GetOrAdd(key, Resolve(locale, use))); } bool hasInheritedValues = field.Attribute("inherits") != null; foreach (XElement relative in field.Elements("relative")) { int amount = Int32.Parse(relative.Attribute("type").Value); formatter.relative[amount] = FormattedString.Parse(relative.Value); } foreach (XElement relativeTime in field.Elements("relativeTime")) { Dictionary <PluralCategories, FormattedString> dict = relativeTime.Attribute("type").Value == "future" ? formatter.future : formatter.past; foreach (XElement child in relativeTime.Elements()) { PluralCategories category = IntlProviderOptions.ParseEnum <PluralCategories>(child.Attribute("count").Value); dict[category] = FormattedString.Parse(child.Value); } hasInheritedValues |= relativeTime.Attribute("inherits") != null; } if (hasInheritedValues) { CldrRelativeTimeFormat parent = CldrUtility.GetParentPatterns(locale, type, Resolve); CldrUtility.CopyPatternFromParent(formatter.relative, parent.relative); CldrUtility.CopyPatternFromParent(formatter.future, parent.future); CldrUtility.CopyPatternFromParent(formatter.past, parent.past); } return(resolvedPatterns.GetOrAdd(key, formatter)); }
private NumberFormatPattern GetCompactNotationPattern(double doubleValue, PluralCategories pluralCount, out double roundedValue) { ReadOnlyDictionary <int, NumberFormatPattern> dict = this.compactNotations[pluralCount]; int exponent = (int)Math.Floor(Math.Log10(Math.Abs(doubleValue))); NumberFormatPattern pattern; if (dict.TryGetValue(exponent, out NumberFormatPattern notationFormats)) { pattern = notationFormats; } else { pattern = exponent < dict.Keys.First() ? dict.Values.First() : dict.Values.Last(); } int roundExp = exponent - pattern.PositivePattern.ToString().Count(v => v == '0') + 1; roundedValue = doubleValue / Math.Pow(10, roundExp); return(pattern.ToDisplayFormat(this)); }
public FormattedString Format(EcmaValue value) { EnsureInitialized(); NumberFormatInfo formatter = formatProvider.FormatProvider; value = value.ToNumber(); if (value.IsNaN || !value.IsFinite) { string str = value.ToDouble().ToString(formatter); return(new FormattedString(new[] { new FormattedPart(value.IsNaN ? FormattedPartType.NaN : FormattedPartType.Infinity, str) })); } double doubleValue = value.ToDouble(); if (this.SignDisplay == SignDisplayFormat.Never) { doubleValue = Math.Abs(doubleValue); } if (this.Style == NumberStyle.Percent) { doubleValue *= 100; } PluralCategories pluralCount = pluralRules.Match(doubleValue); NumberFormatPattern notationFormats = this.Notation == NumberNotation.Compact ? GetCompactNotationPattern(doubleValue, pluralCount, out doubleValue) : this.notationFormats; NumberFormatPattern styleFormats = this.styleFormats.Count == 1 ? this.styleFormats[PluralCategories.Other] : this.styleFormats[pluralCount]; FormattedString notationFormat = null; FormattedString styleFormat = null; switch (doubleValue.CompareTo(0)) { case -1: notationFormat = notationFormats.NegativePattern; styleFormat = styleFormats.NegativePattern; break; case 0: notationFormat = notationFormats.ZeroPattern; styleFormat = styleFormats.ZeroPattern; break; case 1: notationFormat = notationFormats.PositivePattern; styleFormat = styleFormats.PositivePattern; break; } if (this.Digits.RoundingType == RoundingType.SignificantDigits) { doubleValue = RoundToSignificantDigits(doubleValue, this.Digits.MaximumSignificantDigits); } // format double value with corresponding notation (scienific, compact, ...) List <FormattedPart> numParts = new List <FormattedPart>(notationFormat); List <FormattedPart> subParts = new List <FormattedPart>(); int index = numParts.FindIndex(v => v.Type == FormattedPartType.Placeholder); string formatted = doubleValue.ToString(numParts[index].Value, formatter); FormattedPartType integerType = FormattedPartType.Integer; RoundingType roundingType = this.Digits.RoundingType; int maxDigits = roundingType == RoundingType.SignificantDigits ? this.Digits.MaximumSignificantDigits : -1; int numOfDigits = 0; foreach (Match m in Regex.Matches(formatted, "([0-9]+)|.")) { FormattedPartType type = FormattedPartType.Literal; string str = m.Value; if (m.Groups[1].Success) { type = integerType; if (roundingType == RoundingType.SignificantDigits) { if (type != FormattedPartType.ExponentInteger) { numOfDigits += numOfDigits == 0 ? str.TrimStart('0').Length : str.Length; } if (type == FormattedPartType.Fraction && numOfDigits > maxDigits) { str = str.Substring(0, str.Length - numOfDigits + maxDigits); } } } else if (symbolType.TryGetValue(str, out type)) { if (type == FormattedPartType.Decimal) { integerType = FormattedPartType.Fraction; } else if (type == FormattedPartType.ExponentSeparator) { integerType = FormattedPartType.ExponentInteger; } } subParts.Add(new FormattedPart(type, str)); } numParts.RemoveAt(index); numParts.InsertRange(index, subParts); // format as curreny or unit with the formatted number List <FormattedPart> finalParts = new List <FormattedPart>(styleFormat); index = finalParts.FindIndex(v => v.Type == FormattedPartType.Placeholder); finalParts.RemoveAt(index); finalParts.InsertRange(index, numParts); return(new FormattedString(finalParts)); }