An opinionated but dead simple internationalization library for the Bevy game engine.
This project wraps rust-i18n library and is therefore not very "Bevy" like. The rust-i18n
library embeds all of your locales via macros at compile time, while this is incredibly convenient, it isn't always desirable for game development. I have attempted to wrap the library in the most Bevy way I could but the long term goal is to create a more Bevy-like internationalization library, so this is mostly a proof of concept and you should expect breaking changes.
cargo add bevy_simple_i18n
Add the following to your Cargo.toml
:
bevy_simple_i18n = { version = "*" }
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(I18nPlugin)
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d::default());
commands.spawn((I18nText::new("hello"), I18nFont::new("NotoSans")));
commands.spawn((I18nNumber::new(2503.10), I18nFont::new("NotoSans")));
}
In order to use this plugin, the following folder structure is recommended:
.
├── assets
│ ├── locales
│ │ ├── {locale_file}.yml
│ │ ├── {locale_file}.json
│ │ └── {locale_file}.toml
│ └── fonts
│ └── {font_name}
│ ├── fallback.ttf
│ ├── {locale}.ttf
│ └── {locale}.otf
└── Cargo.toml
Locale files can technically be put anywhere in your assets
folder and this crate should find them. Since we're just using the rust-i18n
library, the format is the same. You can find more information on the supported formats here.
To translate text, you can use the I18nText
component. This component takes a string as an argument and will automatically translate it based on the current locale.
Translation File:
_version: 2
hello:
en: Hello world
zh-TW: 你好世界
ja: こんにちは世界
Bevy code:
commands.spawn(I18nText::new("hello"));
To localize numbers, you can use the I18nNumber
component. This component will automatically localize the number based on the current locale.
Bevy code:
commands.spawn(I18nNumber::new(2350.54));
Interpolation is supported using the I18nText
component. You can interpolate variables by adding tuple (key, value) arguments to the I18nText
component.
Translation File:
_version: 2
messages.hello:
en: Hello, %{name}
zh-TW: 你好,%{name}
ja: こんにちは、%{name}
messages.cats:
en: You have %{count} cats
zh-TW: 你有%{count}隻貓
ja: あなたは%{count}匹の猫を持っています
Bevy code:
commands.spawn(I18nText::new("messages.hello").with_arg("name", "world"));
commands.spawn(I18nText::new("messages.cats").with_num_arg("count", 20));
Dynamic fonts enable this plugin to automatically switch between different fonts based on the current locale. For example, since Japanese and English languages have different character sets, you may want to use different fonts for each language. In order to make use of dynamic font, you must follow the file structure mentioned above.
Folder setup:
.
├── assets
│ └── fonts
│ └── NotoSans
│ ├── fallback.ttf
│ ├── ja.ttf
│ └── zh.ttf
└── Cargo.toml
We would then spawn the dynamic font using:
commands.spawn((I18nText::new("hello"), I18nFont::new("NotoSans")))
When the locale is set to ja
, the font will be set to ja.ttf
. If the locale is set to zh-TW
, the font automatically load zh.ttf
, since zh-TW
does not have a font file. If the locale is set to any other locale, Bevy will load fallback.ttf
.
When the locale is changed, the plugin will automatically update all I18nText
components to reflect the new locale. No boilerplate code is required, other than changing the locale using the I18n
resource.
fn change_locale(mut i18n: ResMut<I18n>) {
i18n.set_locale("zh-TW");
}
Implementing this trait for your component makes it eligible to register it and enable automatic re-translations. See Example Implementation for an example.
This trait enables the register_i18n_component
method on your Bevy App. Registering your components with this method will allow the plugin to automatically update the components when the locale is changed, requires your component to implement the I18nComponent
trait. Unfortunately, this does not work with the Dynamic Font feature yet.
app.register_i18n_component::<I18nText>();
bevy | bevy_simple_i18n |
---|---|
0.15 | 0.1 |