This Week In Veloren 186

7 minute read22 August 2022

Authored by Christof

This week, we hear about work done with the translation system by @juliancoffee.

- AngelOnFira, TWiV Editor

Contributor Work

Thanks to this week's contributors, @imbris, @juliancoffee, @matheusclmb, @xMAC94x, @parzivale, @xMAC94x, @zesterer, @XVar, @Matheus, @DaforLynx, @SaverioMiroddi, @Socksonme, @Tormod, and @tygyh

Translation updates by @juliancoffee

Henlo frens, if you remember last blog, I mentioned that we're moving to a new translation system. And now, I want to say that we officially did it! As you will see in this RFC, our old system was plain hash map in .ron format. .ron is Rust's analogue for .json format from the web world, and it's good for generic structured data but quite verbose for specific cases like translation. Let's look at a "hello world" example.

/// Localization for "global" English (.ron)
    string_map: {
        /// Start Main screen section
        "main.intro": "Hello, World!",

    vector_map: {

And with our new format,

#### Localization for "global" English (.ftl)
main-intro = Hello, World!

Of course, we didn't move to a new translation system just because it was verbose, but during my research I was like, wow, it's so pleasant to write in. So, to give more background, we knew that .ron system is temporary. Localisation isn't something you want to build yourself because you need to support large variety of languages, standards, and tooling, if you want to create a good thing. And for more than a year (29 November 2020), we had an issue that pointed to limitations of the system, like web UI and plural forms.

Assuming you know English, we all know that in plural form, words get a -s ending, for example, coin => coins. And, of course, it's not that easy. Even in English, there are deviations from this rule, words that end with s/sh already, like ash => ashes. And there is more, think about counting: first, second, third, fourth, twenty-first. Four forms overall. Thankfully, there is a standard for that, and of course, our .ron format didn't cover that.

This and web UI sounded so incredibly complex that I was afraid to even think about that, but when I tried to fix one of the issues with translations, @Sharp pointed to me that it makes more sense to create a more flexible localisation system than trying to extend our .ron system. That's when the journey began. I looked at our issue and proposed solutions there, found Fluent's main page, found Weblate docs and started research. And to be honest, I was sold on Fluent right there because of an example of Polish as Polish being one of the Slavic languages has quite complex grammar and Fluent can handle it, yay. Fluent has basic things you expect from a localisation format:

  1. Plain messages.
  2. Variables. We supported them in .ron format, but it worked as a convention, variables weren't part of the syntax and weren't checked.
  3. Attributes, as a way to group messages.
  4. Selectors on numbers.
  5. Selectors on arbitrary strings (gender, grammar case, letter case).

There are many formats other than Fluent - one of them is gettext with .po files. Legends say Ancient Maya used it to communicate with Spanish conquistadors. It's very primitive by itself but has a lot of extensions and tools to work with it. Despite that, in our opinion, Fluent has a brighter future so we decided to use it.

At last, here are some examples.

## trivial message
common-singleplayer = Singleplayer

## variables
hud-sct-experience = { $amount } Exp

## attributes
common-abilities-debug-possess = Possessing Arrow
    .desc = Shoots a poisonous arrow. Lets you control your target.
common-abilities-sword-spin = Whirlwind
    .desc = Move forward while spinning with your sword.
common-abilities-axe-leap = Axe Jump
    .desc = A jump with the slashing leap to position of cursor.

## number selectors
hud-trade-buy = Buy Price: { $coin_num ->
    [one] one coin
    *[other] { $coin_formatted } coins
hud-trade-sell = Sell Price: { $coin_num ->
    [one] one coin.
    *[other] { $coin_formatted } coins

Also thanks to @Sharp for pushing for new translation system and @EvanMeek for pushing translation work. Of course, we still have a lot of things to do for internalisation of Veloren, so if you want to get involved, check this tracking issue. And if you want to get involved in translating the game to your favourite language, check out this guide.

Translation is cool, but it's some nerdy thing for devs. Veloren now has another killer feature, /body command, which is obviously admin-only*, and it allows you to change your body to arbitrary species. It allows you to fly like an eagle, swim like a fish and beave like a beaver. Here are some pictures of me having fun:

And to add on beavers and eagles, there is war. I wrote my first impression on 24 February here Read it if you haven't. In two days from the time I'm writing this post, it will be Ukraine Independence Day, and ironically, it will be six months since Russia's full-scale invasion, so I wanted to express my feelings again.

The first thing I wanted to mention is that I call 24 February a full-scale invasion because the war started eight years ago, with the occupation of Crimea and the War in Donbas started by Russian agents like Girkin. The second thing that I think is important to understand is that every war has the front line and rear. And for eight years, the front line was mostly stable, and while more two million people left their homes, it was so easy to forget about the war. What I can say about today, Russian reminds about war every day. I can only imagine what happens on occupied territories, knowing what happened in Bucha. And I can only imagine what happens at towns near frontline. But what I don't need to imagine is air alarm each day and night, two three times per day or sometimes even frequent. And usually these air alarm end with strikes of Russian rockets somewhere in Ukraine. And if at first, core emotion was chaos, now the core emotion is non-stop stress. Stress and hope.

Gliding towards the moon's reflection. See you next time!