fluent
                                
                                 fluent copied to clipboard
                                
                                    fluent copied to clipboard
                            
                            
                            
                        Negative numbers and positive/negative selectors?
The docs at https://projectfluent.org/fluent/guide/selectors.html really miss how you can handle negative numbers…
Also, how would I split *[other] into negative (<0) and positive (>0) integer ranges?
Also can I "ceil" numbers or so…?
Did you even ever consider negative numbers or do you live in a world of positive numbers only? :stuck_out_tongue_winking_eye: (just kidding, I am really having a hard time in fluent to do it)
Same use-case as in https://github.com/projectfluent/fluent/issues/227#issuecomment-455810107
Thanks for filing this, @rugk. You're right—the guide doesn't mention negative numbers at all. I'll fix this.
To type negative numbers in Fluent, prefix them with a - (minus). (Just as you did in the gist.)
Well... this only answer one of the questions though. My second coment lists two more.
I wrote a lengthier comment in https://github.com/projectfluent/fluent/issues/227#issuecomment-456083729 which also touches on these two additional questions. In it, I suggested using custom functions for both named ranges as well as any arithmetic operations.
I'll leave this issue open to fix the documentation issue related to the lack of examples of how to use negative numbers in the Fluent syntax.
Okay, so while this issue is about problematic docs ("negative numbers"), it's also about a feature that i totally miss: "negative selectors". As said:
Also, how would I split *[other] into negative (<0) and positive (>0) integer ranges?
So e.g. I need to do this:
floor_ENGLI_in_EN = { $level ->
    [negative] on basement floor B{ $level - 2*$level }
    [-1] on basement floor B
    [0] on ground floor
    [one] on floor 2
   *[other] on floor { $level + 1 }
}
Or:
floor_ENGLI_in_EN = { $level ->
    [negative] on basement floor B{ $level - 2*$level }
    [-1] on basement floor B
    [0] on ground floor
    [one] on floor 2
   *[other] on floor { $level + 1 }
}
Or, syntax-wise:
floor_ENGLI_in_EN = { $level ->
    [-other] on basement floor B{ $level - 2*$level }
    [-1] on basement floor B
    [0] on ground floor
    [one] on floor 2
   *[other] on floor { $level + 1 }
}
Or:
floor_ENGLI_in_EN = { $level ->
    [-] on basement floor B{ $level - 2*$level }
    [-1] on basement floor B
    [0] on ground floor
    [one] on floor 2
   *[+] on floor { $level + 1 }
}
Whatever you do, without such a selector, one cannot completly fullfill that use-case.
In your particular use-case, is the distinction between underground and overground common enough to warrant two separate strings, each getting a positive number of floor levels?
There's a level of over-use of Fluent in some numbering cases. Like using "Please select photos to upload" for 0 in a "Upload { $photocount} Photos" string. I personally think the developer should use a distinct string for "Please select". That's also better for things like translation memory and possibly MT tooling.
Ah, so you mean something like:
floor_ENGLI_in_EN_UNDER = { $level ->
    *[other] on basement floor B{ $level - 2*$level }
    [-1] on basement floor B
}
floor_ENGLI_in_EN_OVER = { $level ->
    [0] on ground floor
    [one] on floor 2
   *[other] on floor { $level + 1 }
}
So I get the problem why it would not make sense in your photo example (especially as the strings are totally different), but IMHO, in this example such a distinction would be a rather ugly workaround, because:
- It requires me to decide to which group 0(ground floor) belongs to, i.e to "over" or "under"? While I would have an opinion on that, translators may not like it/be confused…
- As explained my data source is exactly this one integer. So if I split it in two groups, I would have to evaluate it in my code/logic, which is not really needed, if you just want to display a string. (Especially if both strings are supposed to get a positive number.)
- In contrast to the photos example, the strings here follow the same logic, only the "position (i.e. floor)" varies, e.g. it could be expanded to "XY is located in floor Z" -> "XY is located in basement floor 1" or "XY is located in floor 2". IMHO that perfectly fits into the use case of fluent's selectors.
So IMHO it would be unintuitive to split it into two strings and I see no advantage of doing so, I only see the listed disadvantages…
Other things I can think of:
- While here it may not be the case, maybe in some use cases the localized values would not fit into the groups the programmer (arbitrarily) defined. E.g. if there would be a language, where floors <= 0 would be called "basement floor" and the ground floor starts with 1… Or something similar which shifts the groups…
Regarding the negative and positive ranges, you can use a custom function to select the desired range.
floor_ENGLI_in_EN = { LOCATION($level) ->
    [under] on basement floor B{ FLOOR($level, ground: 1, sign: "positive" ) }
    [ground] on ground floor
   *[over] on floor { FLOOR($level, ground: 1) }
}
Or, using arithmetic functions:
# The made-up SIGN function returns -1, 0, or 1 here. It could be made
# to return a string-typed description (negative, zero, positive) instead.
floor_ENGLI_in_EN = { SIGN($level) ->
    [-1] on basement floor B{ ABS($level) }
    [0] on ground floor
   *[1] on floor { INCR($level) }
}
If you'd wish to define floors -1 and 1 as special cases, you'd need to use nested selectors. It's not possible right now to define exact matches when using custom functions. Exact matches only work for the built-in plural category matching.
# This currently doesn't work in Fluent.
# Custom functions can't uses exact matching.
floor_ENGLI_in_EN = { LOCATION($level) ->
    [under] on basement floor B{ FLOOR($level, ground: 1, sign: "positive") }
    [-1] on basement floor B
    [ground] on ground floor
    [1] on first floor
   *[over] on floor { FLOOR($level, ground: 1) }
}
The work-around is to use nested select expressions which single out the special cases:
# This will work.
floor_ENGLI_in_EN = { LOCATION($level) ->
    [under]
        { $level ->
            [-1] on basement floor B
           *[other] on basement floor B{ FLOOR($level, ground: 1, sign: "positive") }
        }
    [ground] on ground floor
   *[over]
        { $level ->
            [1] on first floor
           *[other] on floor { FLOOR($level, ground: 1) }
        }
}
Or, again using custom arithmetic functions:
# This will work as well.
floor_ENGLI_in_EN = { SIGN($level) ->
    [-1]
        { $level ->
            [-1] on basement floor B
           *[other] on basement floor B{ ABS($level) }
        }
    [0] on ground floor
   *[1]
        { $level ->
            [1] on first floor
           *[other] on floor { INCR($level) }
        }
}
Ah, great solutions, thanks. :smiley: I also did not know that you can actually nest selectors.
That said, I think if you only had this one selector for negative numbers, the whole syntax/defintion here would be a lot simpler.
I also did not know that you can actually nest selectors.
Variant values (which follow variant keys, e.g. [other]) are just like values of messages and attributes. They can contain text as well as interpolate variables and other expressions inside of { }, including select expressions.