private static void TestData(string cultureStr, RuleType type, bool isDecimal, string lower, string?upper, PluralCategory expected) { if (!TryGetCultureInfo(cultureStr, type, out var info)) { return; } // If upper limit exist, we probe the range a bit if (upper != null) { var start = FluentNumber.FromString(lower); var end = FluentNumber.FromString(upper); var midDouble = (end.Value - start.Value) / 2 + start; FluentNumber mid = isDecimal ? midDouble : Convert.ToInt32(Math.Floor(midDouble), CultureInfo.InvariantCulture); var actualStart = GetPluralCategory(info, type, start); Assert.AreEqual(expected, actualStart, $"Failed on start of range: {start}"); var actualEnd = GetPluralCategory(info, type, end); Assert.AreEqual(expected, actualEnd, $"Failed on end of range: {end}"); var actualMid = GetPluralCategory(info, type, mid); Assert.AreEqual(expected, actualMid, $"Failed on middle of range: {mid}"); } else { var value = FluentNumber.FromString(lower); var actual = GetPluralCategory(info, type, value); Assert.AreEqual(expected, actual); } }
internal static ILocValue ToLocValue(this IFluentType arg) { return(arg switch { FluentNone => new LocValueNone(""), FluentNumber number => new LocValueNumber(number), FluentString str => new LocValueString(str), FluentLocWrapperType value => value.WrappedValue, _ => throw new ArgumentOutOfRangeException(nameof(arg)), });
public void TestFluentSymbolUsesLocaleRules() { var lt = new MessageContext("lt"); var us = new MessageContext(new string[] { "en-US", "en" }); var one = new FluentSymbol("one"); var few = new FluentSymbol("few"); var many = new FluentSymbol("many"); var other = new FluentSymbol("other"); var num1 = new FluentNumber("1"); var num11 = new FluentNumber("11"); var num2 = new FluentNumber("2"); var num0_6 = new FluentNumber("0.6"); one.Match(lt, num1).Should().BeTrue(); one.Match(lt, num11).Should().BeFalse(); one.Match(lt, num2).Should().BeFalse(); one.Match(lt, num0_6).Should().BeFalse(); one.Match(us, num1).Should().BeTrue(); one.Match(us, num11).Should().BeFalse(); one.Match(us, num2).Should().BeFalse(); one.Match(us, num0_6).Should().BeFalse(); few.Match(lt, num1).Should().BeFalse(); few.Match(lt, num11).Should().BeFalse(); few.Match(lt, num2).Should().BeTrue(); few.Match(lt, num0_6).Should().BeFalse(); few.Match(us, num1).Should().BeFalse(); few.Match(us, num11).Should().BeFalse(); few.Match(us, num2).Should().BeFalse(); few.Match(us, num0_6).Should().BeFalse(); many.Match(lt, num1).Should().BeFalse(); many.Match(lt, num11).Should().BeFalse(); many.Match(lt, num2).Should().BeFalse(); many.Match(lt, num0_6).Should().BeTrue(); many.Match(us, num1).Should().BeFalse(); many.Match(us, num11).Should().BeFalse(); many.Match(us, num2).Should().BeFalse(); many.Match(us, num0_6).Should().BeFalse(); other.Match(lt, num1).Should().BeFalse(); other.Match(lt, num11).Should().BeTrue(); other.Match(lt, num2).Should().BeFalse(); other.Match(lt, num0_6).Should().BeFalse(); other.Match(lt, num1).Should().BeFalse(); other.Match(us, num11).Should().BeTrue(); other.Match(us, num2).Should().BeTrue(); other.Match(us, num0_6).Should().BeTrue(); }
public static bool TryWrite(this IExpression expression, TextWriter writer, Scope scope) { var errors = new List <FluentError>(); if (expression is IInlineExpression inlineExpression) { inlineExpression.Write(writer, scope); } else if (expression is SelectExpression selectExpression) { var selector = selectExpression.Selector.Resolve(scope); if (selector is FluentString or FluentNumber) { foreach (var variant in selectExpression.Variants) { IFluentType key; switch (variant.Type) { case VariantType.NumberLiteral: key = FluentNumber.TryNumber(variant.Key.Span); break; default: key = new FluentString(variant.Key.Span); break; } if (key.Matches(selector, scope)) { variant.Value.Write(writer, scope); return(scope.Errors.Count == 0); } } } for (var i = 0; i < selectExpression.Variants.Count; i++) { var variant = selectExpression.Variants[i]; if (variant.IsDefault) { variant.Value.Write(writer, scope); return(errors.Count == 0); } } errors.Add(ResolverFluentError.MissingDefault()); } return(scope.Errors.Count == 0); }
public void TestFluentNumber() { var num = new FluentNumber("105.6"); var ctx = new MessageContext("en-US"); num.Value.Should().Be("105.6"); num.Match(ctx, new FluentNumber("105.6")).Should().BeTrue(); num.Match(ctx, new FluentNumber("105.5")).Should().BeFalse(); num.Match(ctx, 105.6F).Should().BeTrue(); num.Match(ctx, 105.6).Should().BeTrue(); num.Match(ctx, 105.6M).Should().BeTrue(); num.Match(ctx, (sbyte)105).Should().BeFalse(); num.Match(ctx, (short)105).Should().BeFalse(); num.Match(ctx, (int)105).Should().BeFalse(); num.Match(ctx, (long)105).Should().BeFalse(); num.Match(ctx, (byte)105).Should().BeFalse(); num.Match(ctx, (ushort)105).Should().BeFalse(); num.Match(ctx, (uint)105).Should().BeFalse(); num.Match(ctx, (ulong)105).Should().BeFalse(); num.Match(ctx, "whatever").Should().BeFalse(); num.Format(ctx).Should().Be("105.6"); }
public static IFluentType Resolve(this IInlineExpression self, Scope scope) { if (self is TextLiteral textLiteral) { StringWriter stringWriter = new(); UnicodeUtil.WriteUnescapedUnicode(textLiteral.Value, stringWriter); return((FluentString)stringWriter.ToString()); } if (self is NumberLiteral numberLiteral) { return(FluentNumber.TryNumber(numberLiteral.Value.Span)); } if (self is VariableReference varRef) { var args = scope.LocalArgs ?? scope.Args; if (args != null && args.TryGetValue(varRef.Id.ToString(), out var arg)) { return(arg.Copy()); } if (scope.LocalArgs == null) { scope.AddError(ResolverFluentError.UnknownVariable(varRef)); } return(new FluentErrType()); } var writer = new StringWriter(); self.TryWrite(writer, scope); return((FluentString)writer.ToString()); }
/// <summary> /// Method that compares a Fluent string to a Fluent number /// </summary> /// <param name="scope">Scope of Fluent Bundle</param> /// <param name="fs1"></param> /// <param name="fn2"></param> /// <returns></returns> public static bool MatchByPluralCategory(this IScope scope, FluentString fs1, FluentNumber fn2) { if (!fs1.TryGetPluralCategory(out var strCategory)) { return(false); } var numCategory = scope.GetPluralRules(RuleType.Cardinal, fn2); return(numCategory == strCategory); }
public PluralCategory GetPluralRules(RuleType type, FluentNumber number) { return(ResolverHelpers.PluralRules.GetPluralCategory(Bundle.Culture, type, number)); }
public static PluralCategory GetPluralCategory(CultureInfo info, RuleType ruleType, FluentNumber number) { var specialCase = IsSpecialCase(info.Name, ruleType); var langStr = GetPluralRuleLang(info, specialCase); var func = RuleTable.GetPluralFunc(langStr, ruleType); if (number.TryPluralOperands(out var op)) { return(func(op)); } return(PluralCategory.Other); }
private static void Write(this IInlineExpression self, TextWriter writer, Scope scope) { if (self is TextLiteral textLiteral) { UnicodeUtil.WriteUnescapedUnicode(textLiteral.Value, writer); return; } if (self is NumberLiteral numberLiteral) { var value = FluentNumber.TryNumber(numberLiteral.Value.Span); value.Write(writer, scope); return; } if (self is MessageReference msgRef) { ProcessMsgRef(self, writer, scope, msgRef); return; } if (self is TermReference termRef) { var res = scope.GetArguments(termRef.Arguments); scope.SetLocalArgs(res.Named); if (scope.Bundle.TryGetAstTerm(termRef.Id.ToString(), out var term)) { var attrName = termRef.Attribute; var attr = term .Attributes .Find(a => a.Id.Equals(attrName)); scope.Track(writer, attr != null ? attr.Value : term.Value, self); } else { scope.WriteRefError(writer, self); } scope.SetLocalArgs(null); return; } if (self is FunctionReference funcRef) { var(resolvedPosArgs, resolvedNamedArgs) = scope.GetArguments(funcRef.Arguments); if (scope.Bundle.TryGetFunction(funcRef.Id, out var func)) { var result = func.Function(resolvedPosArgs, resolvedNamedArgs); if (result.IsError()) { self.WriteError(writer); } else { writer.Write(result.AsString()); } } else { scope.WriteRefError(writer, self); } } if (self is VariableReference varRef) { var id = varRef.Id; var args = scope.LocalArgs ?? scope.Args; if (args != null && args.TryGetValue(id.ToString(), out var arg)) { arg.Write(writer, scope); } else { if (scope.LocalArgs == null) { scope.AddError(ResolverFluentError.Reference(self)); } writer.Write('{'); self.WriteError(writer); writer.Write('}'); } } if (self is Placeable placeable) { placeable.Expression.TryWrite(writer, scope); } }