1use std::borrow::Cow;
5
6use bevy_asset::prelude::*;
7use bevy_ecs::prelude::*;
8use bevy_utils::all_tuples;
9use smallvec::{SmallVec, smallvec};
10
11use crate::{
12 arg::LocaleArg,
13 def::{LocaleArgs, LocaleCache, LocaleCollection, LocaleKey, LocaleSrc},
14};
15
16pub trait LocBundle {
18 #[doc(hidden)]
19 fn spawn(this: Self, commands: Commands) -> SmallVec<[Entity; 4]>;
20}
21
22macro_rules! impl_loc_bundle {
23 ((T0, t0)) => {
24 #[cfg_attr(docsrs, doc(fake_variadic))]
25 impl<T0: LocBundle> LocBundle for (T0,) {
26 #[allow(unused)]
27 fn spawn((t0,): Self, mut commands: Commands) -> SmallVec<[Entity; 4]> {
28 T0::spawn(t0, commands.reborrow())
29 }
30 }
31 };
32 ($(($T:ident, $t:ident)),*) => {
33 #[doc(hidden)]
34 impl<$($T: LocBundle),*> LocBundle for ($($T,)*) {
35 #[allow(unused)]
36 fn spawn(($($t,)*): Self, mut commands: Commands) -> SmallVec<[Entity; 4]> {
37 let mut out = SmallVec::new();
38 $(out.append(&mut $T::spawn($t, commands.reborrow()));)*
39 out
40 }
41 }
42 };
43}
44
45all_tuples!(impl_loc_bundle, 0, 15, T, t);
46
47impl<T: LocaleArg> LocBundle for T {
48 #[inline]
49 fn spawn(this: Self, mut commands: Commands) -> SmallVec<[Entity; 4]> {
50 smallvec![
51 commands
52 .spawn((LocaleSrc(this), LocaleCache {
53 result: None,
54 locale: AssetId::default(),
55 changed: false,
56 }))
57 .id()
58 ]
59 }
60}
61
62pub trait LocCommandsExt {
65 fn spawn_localized<L: LocBundle>(
67 &mut self,
68 bundle: impl Bundle,
69 key: impl Into<Cow<'static, str>>,
70 handle: Handle<LocaleCollection>,
71 loc: L,
72 ) -> EntityCommands;
73
74 fn spawn_localized_empty<L: LocBundle>(
76 &mut self,
77 key: impl Into<Cow<'static, str>>,
78 handle: Handle<LocaleCollection>,
79 loc: L,
80 ) -> EntityCommands;
81}
82
83impl LocCommandsExt for Commands<'_, '_> {
84 #[inline]
85 fn spawn_localized<L: LocBundle>(
86 &mut self,
87 bundle: impl Bundle,
88 key: impl Into<Cow<'static, str>>,
89 handle: Handle<LocaleCollection>,
90 loc: L,
91 ) -> EntityCommands {
92 let args = L::spawn(loc, self.reborrow());
93 self.spawn((
94 bundle,
95 LocaleKey {
96 key: key.into(),
97 collection: handle,
98 },
99 LocaleArgs(args),
100 ))
101 }
102
103 #[inline]
104 fn spawn_localized_empty<L: LocBundle>(
105 &mut self,
106 key: impl Into<Cow<'static, str>>,
107 handle: Handle<LocaleCollection>,
108 loc: L,
109 ) -> EntityCommands {
110 let args = L::spawn(loc, self.reborrow());
111 self.spawn((
112 LocaleKey {
113 key: key.into(),
114 collection: handle,
115 },
116 LocaleArgs(args),
117 ))
118 }
119}
120
121pub trait LocEntityExt {
124 fn localize<L: LocBundle>(
126 &mut self,
127 key: impl Into<Cow<'static, str>>,
128 handle: Handle<LocaleCollection>,
129 loc: L,
130 ) -> &mut Self;
131}
132
133impl LocEntityExt for EntityCommands<'_> {
134 #[inline]
135 fn localize<L: LocBundle>(
136 &mut self,
137 key: impl Into<Cow<'static, str>>,
138 handle: Handle<LocaleCollection>,
139 loc: L,
140 ) -> &mut Self {
141 let args = L::spawn(loc, self.commands());
142 self.insert((
143 LocaleKey {
144 key: key.into(),
145 collection: handle,
146 },
147 LocaleArgs(args),
148 ))
149 }
150}
151
152impl LocEntityExt for EntityWorldMut<'_> {
153 #[inline]
154 fn localize<L: LocBundle>(
155 &mut self,
156 key: impl Into<Cow<'static, str>>,
157 handle: Handle<LocaleCollection>,
158 loc: L,
159 ) -> &mut Self {
160 let bundle = self.world_scope(|world| {
161 let cmd = world.commands();
162 let args = L::spawn(loc, cmd);
163
164 (
165 LocaleKey {
166 key: key.into(),
167 collection: handle,
168 },
169 LocaleArgs(args),
170 )
171 });
172
173 self.insert(bundle);
174 self.world_scope(World::flush);
175 self
176 }
177}