Ejemplo n.º 1
0
        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)),
     });
Ejemplo n.º 3
0
        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();
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
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");
        }
Ejemplo n.º 6
0
        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());
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
 public PluralCategory GetPluralRules(RuleType type, FluentNumber number)
 {
     return(ResolverHelpers.PluralRules.GetPluralCategory(Bundle.Culture, type, number));
 }
Ejemplo n.º 9
0
            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);
            }
Ejemplo n.º 10
0
        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);
            }
        }