hephae_locale/
arg.rs

1//! Defines [`LocaleTarget`] and [`LocaleArg`], both configurable by
2//! [`LocaleTargetPlugin`](crate::LocaleTargetPlugin) and
3//! [`LocaleArgPlugin`](crate::LocaleArgPlugin), respectively.
4//!
5//! See each type-level documentations for more information.
6
7use std::{
8    borrow::Cow,
9    fmt::{Error as FmtError, Write},
10};
11
12use bevy_derive::{Deref, DerefMut};
13use bevy_ecs::prelude::*;
14use bevy_reflect::{Reflectable, prelude::*};
15
16use crate::def::{Locale, LocaleFmt, LocaleResult};
17
18/// Components that are localizable. For example, this may be a text widget component. You may
19/// configure Hephae to register this type for updating using
20/// [`LocaleTargetPlugin`](crate::LocaleTargetPlugin).
21pub trait LocaleTarget: Component {
22    /// Receiver for localized strings result. Calling [`str::clone_into`] is recommended.
23    fn update(&mut self, src: &str);
24}
25
26pub(crate) fn localize_target<T: LocaleTarget>(mut query: Query<(&mut T, &LocaleResult), Changed<LocaleResult>>) {
27    for (mut target, src) in &mut query {
28        target.update(src);
29    }
30}
31
32/// Locale arguments that may be used in positional format locale templates. You may configure
33/// Hephae to register this argument using [`LocaleArgPlugin`](crate::LocaleArgPlugin).
34pub trait LocaleArg: 'static + FromReflect + Reflectable + Send + Sync {
35    /// Extracts this argument into a writable string.
36    fn localize_into(&self, locale: &Locale, out: &mut impl Write) -> Result<(), FmtError>;
37
38    /// Convenient shortcut for [`localize_into`](LocaleArg::localize_into) that allocates a new
39    /// [`String`].
40    #[inline]
41    fn localize(&self, locale: &Locale) -> Result<String, FmtError> {
42        let mut out = String::new();
43        self.localize_into(locale, &mut out)?;
44
45        Ok(out)
46    }
47}
48
49impl LocaleArg for &'static str {
50    #[inline]
51    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
52        out.write_str(self)
53    }
54}
55
56impl LocaleArg for String {
57    #[inline]
58    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
59        out.write_str(self)
60    }
61}
62
63impl LocaleArg for Cow<'static, str> {
64    #[inline]
65    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
66        out.write_str(self)
67    }
68}
69
70impl LocaleArg for u8 {
71    #[inline]
72    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
73        write!(out, "{self}")
74    }
75}
76
77impl LocaleArg for u16 {
78    #[inline]
79    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
80        write!(out, "{self}")
81    }
82}
83
84impl LocaleArg for u32 {
85    #[inline]
86    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
87        write!(out, "{self}")
88    }
89}
90
91impl LocaleArg for u64 {
92    #[inline]
93    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
94        write!(out, "{self}")
95    }
96}
97
98impl LocaleArg for u128 {
99    #[inline]
100    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
101        write!(out, "{self}")
102    }
103}
104
105impl LocaleArg for i8 {
106    #[inline]
107    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
108        write!(out, "{self}")
109    }
110}
111
112impl LocaleArg for i16 {
113    #[inline]
114    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
115        write!(out, "{self}")
116    }
117}
118
119impl LocaleArg for i32 {
120    #[inline]
121    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
122        write!(out, "{self}")
123    }
124}
125
126impl LocaleArg for i64 {
127    #[inline]
128    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
129        write!(out, "{self}")
130    }
131}
132
133impl LocaleArg for i128 {
134    #[inline]
135    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
136        write!(out, "{self}")
137    }
138}
139
140impl LocaleArg for f32 {
141    #[inline]
142    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
143        write!(out, "{self:.2}")
144    }
145}
146
147impl LocaleArg for f64 {
148    #[inline]
149    fn localize_into(&self, _: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
150        write!(out, "{self:.2}")
151    }
152}
153
154/// A [`LocaleArg`] that fetches a key from a [`Locale`].
155///
156/// # Caveat
157///
158/// This only supports [unformatted](LocaleFmt::Unformatted) strings at the moment.
159#[derive(Component, Reflect, Clone, Deref, DerefMut, Debug)]
160#[reflect(Component, Debug)]
161pub struct LocalizeBy(pub Cow<'static, str>);
162
163impl LocaleArg for LocalizeBy {
164    #[inline]
165    fn localize_into(&self, locale: &Locale, out: &mut impl Write) -> Result<(), FmtError> {
166        let Some(LocaleFmt::Unformatted(res)) = locale.get(&***self) else {
167            return Err(FmtError);
168        };
169
170        write!(out, "{res}")
171    }
172}