use crate::prelude::*;
use bevy_platform::collections::HashMap;
use core::any::Any;
use core::fmt::Debug;
use log::error;
pub trait TextProvider: Debug + Send + Sync {
fn clone_shallow(&self) -> Box<dyn TextProvider>;
fn accept_line_hints(&mut self, line_ids: &[LineId]);
fn get_text(&self, id: &LineId) -> Option<String>;
fn set_language(&mut self, language: Option<Language>);
fn get_language(&self) -> Option<Language>;
fn are_lines_available(&self) -> bool;
fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
impl Clone for Box<dyn TextProvider> {
fn clone(&self) -> Self {
self.clone_shallow()
}
}
#[allow(missing_docs)]
pub type StringTable = HashMap<LineId, String>;
#[derive(Debug, Clone, Default)]
pub struct StringTableTextProvider {
base_language_table: StringTable,
translation_table: Option<(Language, StringTable)>,
translation_language: Option<Language>,
}
impl StringTableTextProvider {
pub fn new() -> Self {
Self::default()
}
pub fn extend_base_language<T>(&mut self, string_table: impl IntoIterator<Item = T>)
where
StringTable: Extend<T>,
{
self.base_language_table.extend(string_table);
}
pub fn extend_translation<T>(
&mut self,
language: impl Into<Language>,
string_table: impl IntoIterator<Item = T>,
) where
StringTable: Extend<T>,
{
let language = language.into();
if let Some((current_language, translation_table)) = self.translation_table.as_mut()
&& language == *current_language
{
translation_table.extend(string_table);
return;
}
let (language, mut table) = self
.translation_table
.take()
.unwrap_or_else(|| (language, StringTable::new()));
table.clear();
table.extend(string_table);
self.translation_table = Some((language, table));
}
}
impl TextProvider for StringTableTextProvider {
fn clone_shallow(&self) -> Box<dyn TextProvider> {
Box::new(self.clone())
}
fn accept_line_hints(&mut self, _line_ids: &[LineId]) {
}
fn get_text(&self, id: &LineId) -> Option<String> {
if let Some(language) = self.translation_language.as_ref()
&& let Some((registered_language, translation_table)) = self.translation_table.as_ref()
{
if registered_language != language {
error!(
"Didn't find language {language} in translations, falling back to base language."
);
} else if let Some(line) = translation_table.get(id) {
return Some(line.clone());
} else {
error!(
"No translation found for line {id} in language {language}, falling back to base language."
);
}
}
self.base_language_table.get(id).cloned()
}
fn set_language(&mut self, language_code: Option<Language>) {
self.translation_language = language_code;
}
fn get_language(&self) -> Option<Language> {
self.translation_language.clone()
}
fn are_lines_available(&self) -> bool {
let Some(language) = self.translation_language.as_ref() else {
return !self.base_language_table.is_empty();
};
let translation_language = self
.translation_table
.as_ref()
.map(|(language, _)| language);
translation_language == Some(language)
}
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
}