slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.54k stars 600 forks source link

Add support for translations without gettext #3715

Open ogoffart opened 1 year ago

ogoffart commented 1 year ago

We need to support user changing translations through the interface, as well as translation on platform that do not have gettext (MCU)

The idea would be somehow to have API to provide a translator.

Perhaps we can re-use an interface similar to https://docs.rs/tr/latest/tr/trait.Translator.html and have a global setter to set it. That setter would mark all translated string as dirty.

( This should also help for https://github.com/slint-ui/slint/issues/3307 )

qarmin commented 1 year ago

I know that this has been discussed before and that the idea was already discarded, but isn't it worthwhile, however, to give users the option of using fluent-rs instead of gettext, since it works very well under any system, including windows.

This way, the external dependence on the code in C can be removed and it will make cross-compilation easier.

ogoffart commented 1 year ago

Regarding fluent, this can be done by using a global. The old documentation should five hint https://slint.dev/releases/1.0.2/docs/slint/src/recipes/recipes#translations So you would have in your code something like text: Fluent.translate("my-text", ["FooBar"]) Other possibilities are also possible: https://github.com/slint-ui/slint/issues/33#issuecomment-1275856180

CarbonPool commented 11 months ago

Any progress on changing the language dynamically?

tronical commented 5 months ago

Changing translations dynamically (when using gettext) is implemented in the master branch. This ticket was split and slightly confusing, so I've refocused it on the gettext removal.

ogoffart commented 1 month ago

I'm proposing to have the following:

The the compiler would look at the content of and look for file with a given pattern. Either:

We can use crates like gettext (to open .mo) or polib (to open .po) Then at compile time, we translate @tr("Hello {}", name) to something like (pseudo-code)

   private_api::format_string(match private_api::language() {
       1 => "Bonjour {}",
       2 => "Hallo {}",
       _ => "Hello {}",
   },&[name]);

Or maybe

   private_api::translation(&["Hello {}", "Bonjour {}", "Hallo {}"], &[name])

We can even have warning if a string or translated string don't have the right format, (or doesn't exist ?)

Now we still need a way to set or change the language. I'm thinking there could be slint::set_language(???) but how does it map the language string to a number? Or we could generate a slint_set_language(&str) function in the generated code. Or, we could have a slint function set-language("fr") in .slint

This solution also doesn't help to translate strings in the native C++/Rust code.

This is mostly useful for MCU or platform without file system. I still think we should have a slint::set_translator(Box<dyn Translator>) function for desktop.

tronical commented 1 month ago

I agree that this is the way to go, roughly.

In terms of language selection: I think the build system API should explicitly say which languages/translations to pick. This permits creating multi-language builds as well as region-specific builds. Later the list of support translations could also go into the project file, to enable access in the live-preview.

Generally, I think it makes sense to see translations like resources/assets and bundle them, also on targets with operating systems, as opt-in.