use super::I18nError;
use super::catalog;
pub trait LocalizedMsg {
fn message_key(&self) -> &'static str;
fn message_args(&self) -> Vec<(&'static str, String)> {
Vec::new()
}
}
pub trait I18nExt: LocalizedMsg + std::error::Error {
fn to_localized_string(&self) -> String {
catalog::translate(self.message_key(), &self.message_args())
}
fn message_en(&self) -> String {
catalog::translate_en(self.message_key(), &self.message_args())
}
}
impl<E: LocalizedMsg + std::error::Error> I18nExt for E {}
impl LocalizedMsg for I18nError {
fn message_key(&self) -> &'static str {
match self {
I18nError::InvalidLocale { .. } => "i18n-error-invalid-locale",
I18nError::InvalidNumber { .. } => "i18n-error-invalid-number",
I18nError::DateError(_) => "i18n-error-date",
I18nError::FormatError(_) => "i18n-error-format",
}
}
fn message_args(&self) -> Vec<(&'static str, String)> {
match self {
I18nError::InvalidLocale { input, reason }
| I18nError::InvalidNumber { input, reason } => {
vec![("input", input.clone()), ("reason", reason.clone())]
}
I18nError::DateError(message) | I18nError::FormatError(message) => {
vec![("message", message.clone())]
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_i18n_error_dual_track() {
let err = I18nError::InvalidLocale {
input: "zh-CN".to_string(),
reason: "nope".to_string(),
};
assert_eq!(err.to_string(), "invalid locale 'zh-CN': nope");
assert_eq!(err.message_en(), "invalid locale 'zh-CN': nope");
}
#[test]
fn test_message_args_default_empty() {
#[derive(Debug)]
struct E;
impl std::fmt::Display for E {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "e")
}
}
impl std::error::Error for E {}
impl LocalizedMsg for E {
fn message_key(&self) -> &'static str {
"rate-limit-exceeded"
}
}
let err = E;
assert!(err.message_args().is_empty());
assert!(!err.to_localized_string().is_empty());
assert_eq!(err.message_en(), "Rate limit exceeded");
}
}