Variables - complex types

Hi.

At this moment, if I am not mistaken, Fluent can implicitly work only with what I would call “primitive” types - strings and numbers. I wanted to ask, whether there was a discussion if the support more “complex” types, like objects (key-value pairs) and lists?

To illustrate such feature on an example, having that supported by Fluent, the string and variables from playground may work like this.

For object in variables

{
    "user": {
        "name": "Anne",
        "gender": "female"
    },
    "photoCount": 3
}

using syntax $object[field] would render

shared-photos =
    {$user[name]} {$photoCount ->
        [one] added a new photo
       *[other] added {$photoCount} new photos
    } to {$user[gender] ->
        [male] his stream
        [female] her stream
       *[other] their stream
    }.

as “Anne added 3 new photos to her stream.”.

List in variables

{
    "userName": "Anne",
    "userGender": "female",
    "photos": [
        "my dog",
        "my cat"
    ]
}

using syntax $list[item_order] and function LENGTH($list) would render

shared-photos =
    {$userName} {length($photos) ->
        [one] added a new photo called "$photos[1]"
        [two] added new photos called "$photos[1]" and "$photos[2]"
       *[other] added {LENGTH($photos)} new photos
    } to {$userGender ->
        [male] his stream
        [female] her stream
       *[other] their stream
    }.

as “Anne added a new photos called “my dog” and “my cat” to her stream.”.

The main question is, whether you think this may be sane to include into the Fluent syntax. It’s more of a feature for the developers, rather than for localizers.

1 Like

IIRC, some version of L20n/Fluent had arbitrarily deep hashes. I recall that we ripped that out explicitly. Not sure if that was when we introduced traits, or when we dropped traits, or unrelated.

Anywho, I’m personally quite happy that we did.

As for lists, that’s a slightly different question. If we had them as atomic containers, you could use them with ListFormat-like functionality. But those are also non-trivial in how they operate with native types. I.e., the JS one only takes string arguments, and what should happen if you pass in numbers or datetimes?

As for access to individual elements … that’s even more complex, and requires quite a bit of specification work to drill down if that’s a good idea. And what to do in error scenarios.

And implementing all of this consistently with all the different type systems we have by now is also not something I’d appreciate.

And tooling support. Ugh, tooling support.

1 Like

I think it was around that time, yes. I found the old commit which removed the support for nested property access on variables, but unfortunately it lacks any more context. IIRC, the rationale was that it was a feature that added a lot of complexity for not a lot of benefit. After all, it’s possible to represent any nested hierarchy as a flat object by using more explicit key names, provided there aren’t any cyclic references.

A flat object meant that the resolver didn’t have to worry about cycles or about how to format $user when it’s passed as a user: {name, gender} nested data type. Also, it allowed us to simplify the AST: rather than store a PropertyExpr(PropertyExpr(VariableRef))) to represent arbitrarily nested property access ($user.name.first), we could always just store a single flat VariableReference; that was a big win for tooling. Later on, we did the same with the AST for attribute access on Messages and Terms in Fluent 0.9.

Fluent used to support lists as variable types, but I removed them in Fluent 0.3. The changelog offered a rather enigmatic mention of the fact, unfortunately. For some context, here are two related issues from the Fluent spec repo: #46, #79.

One challenge with lists is that whatever is inside the list needs to be formatted, and the list itself needs to be formatted too. On the implementation side, it adds complexity because instead of a binary raw vs. formatted state, we’d have: (1) completely raw, (2) raw list with (some?) elements formatted, (3) formatted list with raw elements, and (4) a completely formatted list including elements. This is doable, of course, but I wanted to keep the implementation as simple as possible for as long as possible.

On the syntax side, if we wanted to allow specifying formatting options for list elements, I guess we’d have to consider higher order functions like map. Given photoCounts: [1, 2, 3], that would mean something like MAP($photoCounts, NUMBER(_, style: "decimal")), and I’m afraid to think where that would take us :slight_smile:

Totally get it, thank you for the feedback and context.

1 Like