Hacker News new | ask | show | jobs
by stasm 2616 days ago
This is an excellent question and a very good use-case. I'm a Polish speaker myself, so I can definitely relate. It's also a good excuse for me to talk a little bit more about the advanced features of Fluent.

The Fluent Syntax is a simple declarative DSL. By design, it doesn't allow translators to build complex conditionals or use arithmetic. There is, however, an escape hatch. The problem you described can be solved in Fluent with a little bit of one-time help from the developer of the source code, through a feature of Fluent called custom functions.

Translations in Fluent can use functions to format values or decide between variants. There exist built-in functions like NUMBER and DATETIME. They are rarely used because the Fluent runtime calls them on numeric and temporal values implicitly, but they can be helpful when localizers wish to use custom formatting options.

    weekday-today = Today is {DATETIME($today, weekday: "long")}.
See https://projectfluent.org/play/?id=a3540d4f02c104a634adbfc0e... for a live example of DATETIME.

There can also be custom functions, defined during the initialization of the runtime. In Firefox, we use one such function called PLATFORM: https://searchfox.org/mozilla-central/rev/d33d470140ce3f9426.... It can be used as follows:

    open-preferences = {PLATFORM() ->  
        [windows] Open Options
       *[other] Open Preferences
    }
The logic of custom functions is entirely up to developers and the localization needs of the UI. In https://github.com/projectfluent/fluent/issues/228#issuecomm..., for instance, I suggested using a custom function to handle negative and positive floor numbers.

A custom function can also cater to the use-case you described. A simple and possibly naive implementation in JavaScript could look like the following one:

    function NUMBER_HEAD(num) {
        while (num > 999) {
            num /= 1e3;
        }
        let first = num.toString()[0];
        return num < 10 ? first
            : num < 100 ? first + "x"
            : first + "xx";
    }
I wrote this with Polish in mind, but it could be useful to other languages in which numerals are named after the first thousand-triple, in a left to right order. Depending on the exact product requirements, the function could be called NUMBER_HEAD_POLISH, or perhaps NUMBER_HEAD_TRIPLE_FIRST_DIGIT :)

Once defined, the function can be used as follows:

    # The Polish copy can take advantage of the custom function.
    page-of = {NUMBER_HEAD($pageTotal) ->
        [1xx] Strona {$pageCurrent} ze {$pageTotal}
       *[other] Strona {$pageCurrent} z {$pageTotal}
    }
This method still requires some work from developers, but it only needs to happen once and in a single palce in code: where the Fluent runtime is initialized. Because they are code, custom functions can be reviewed and tested just as any other code in the code base, to help ensure that they do what they claim to :)

Importantly, the use of the custom function is completely opt-in.

    # The English copy doesn't need any special handling.
    page-of = Page {$pageCurrent} of {$pageTotal}
All localization callsites remain unchanged, and all existing translations remain functional.
1 comments

Thanks for the detailed answer.

Right now I'm using qt translation system, it handles nicely various plural forms, just like Fluent.

But it requires special code in each message that has "X of Y" to handle the "ze 100" correctly in Polish. It might be done for Polish, because we have Polish developers, but many languages have similar quirks and it's not done for them. And it would result in combinatorial explosion of translation message versions if source code had to add special case for each quirk in each language.

This seems to be a much better solution.

Thanks!

> And it would result in combinatorial explosion of translation message versions if source code had to add special case for each quirk in each language.

This is the exact problem we designed Fluent to solve. If you get a chance to try it out, feel free to reach out to me if you questions. I'll be more than happy to help and to hear feedback.