use bevy::prelude::*;
use crate::I18n;
#[derive(Component, Clone, Debug)]
#[require(Text)]
pub struct I18nText {
pub file: String,
pub key: String,
pub mode: I18nMode,
}
impl I18nText {
pub fn new(file: impl Into<String>, key: impl Into<String>) -> Self {
Self {
file: file.into(),
key: key.into(),
mode: I18nMode::Plain,
}
}
}
#[derive(Clone, Debug)]
pub enum I18nMode {
Plain,
Args(Vec<(String, String)>),
Plural(usize),
Gender(String),
GenderArgs(String, Vec<(String, String)>),
GenderPlural(String, usize),
}
#[derive(Message, Debug, Clone)]
pub struct LanguageChanged {
pub from: String,
pub to: String,
}
pub fn update_i18n_text(
i18n: Res<I18n>,
mut sets: ParamSet<(
Query<(&I18nText, &mut Text), Or<(Changed<I18nText>, Added<I18nText>)>>,
Query<(&I18nText, &mut Text)>,
)>,
mut last_lang: Local<Option<String>>,
mut events: MessageWriter<LanguageChanged>,
) {
let current = i18n.get_lang().to_string();
let lang_changed = last_lang.as_deref() != Some(current.as_str());
if lang_changed {
let prev = last_lang.replace(current.clone());
if let Some(prev) = prev {
events.write(LanguageChanged { from: prev, to: current.clone() });
}
let mut q = sets.p1();
for (it, mut text) in &mut q {
text.0 = render(&i18n, it);
}
} else {
let mut q = sets.p0();
for (it, mut text) in &mut q {
text.0 = render(&i18n, it);
}
}
}
fn render(i18n: &I18n, it: &I18nText) -> String {
let t = i18n.translation(&it.file);
match &it.mode {
I18nMode::Plain => t.t(&it.key),
I18nMode::Plural(c) => t.t_with_plural(&it.key, *c),
I18nMode::Gender(g) => t.t_with_gender(&it.key, g),
I18nMode::Args(args) => {
let view: Vec<(&str, &dyn ToString)> = args
.iter()
.map(|(k, v)| (k.as_str(), v as &dyn ToString))
.collect();
t.t_with_args(&it.key, &view)
}
I18nMode::GenderArgs(g, args) => {
let view: Vec<(&str, &dyn ToString)> = args
.iter()
.map(|(k, v)| (k.as_str(), v as &dyn ToString))
.collect();
t.t_with_gender_and_args(&it.key, g, &view)
}
I18nMode::GenderPlural(g, c) => t.t_with_gender_and_plural(&it.key, g, *c),
}
}