pub struct Lang { /* private fields */ }Expand description
The translation tables and the current language. Reach it through ctx.lang.
Implementations§
Source§impl Lang
impl Lang
Sourcepub fn load_dir(&mut self, dir: impl AsRef<Path>) -> usize
pub fn load_dir(&mut self, dir: impl AsRef<Path>) -> usize
Loads every <code>.txt in dir. Returns how many languages were loaded. A missing
folder is fine and loads nothing.
Sourcepub fn add_text(&mut self, code: &str, text: &str)
pub fn add_text(&mut self, code: &str, text: &str)
Adds the lines of a translation file (key = text) to a language. Later keys
replace earlier ones. Handy with include_str! to ship texts inside the executable.
Sourcepub fn insert(
&mut self,
code: &str,
key: impl Into<String>,
text: impl Into<String>,
)
pub fn insert( &mut self, code: &str, key: impl Into<String>, text: impl Into<String>, )
Adds or replaces one text.
Sourcepub fn set(&mut self, code: &str) -> bool
pub fn set(&mut self, code: &str) -> bool
Switches the language. "de-AT" falls back to "de". Returns false (and keeps the
current language) if no texts exist for it. English and German always exist, because
the engine’s own texts are built in. To remember the choice, use
Context::set_language(crate::Context::set_language) instead.
Sourcepub fn fallback(&self) -> &str
pub fn fallback(&self) -> &str
The language used for keys missing in the current one (default "en").
Sourcepub fn set_fallback(&mut self, code: &str)
pub fn set_fallback(&mut self, code: &str)
Changes the fallback language.
Sourcepub fn languages(&self) -> Vec<String>
pub fn languages(&self) -> Vec<String>
The languages with loaded texts, sorted by code. Built in engine texts do not count, so this lists exactly the languages your game was translated to.
Sourcepub fn name(&self, code: &str) -> String
pub fn name(&self, code: &str) -> String
The name of a language as written in its file (key language), else the code.
Sourcepub fn has(&self, key: &str) -> bool
pub fn has(&self, key: &str) -> bool
Whether key has a text in the current or the fallback language.
Sourcepub fn get(&self, key: &str) -> String
pub fn get(&self, key: &str) -> String
The text for key in the current language. See the module docs for what
happens when it is missing.
Sourcepub fn format(&self, key: &str, args: &[(&str, &dyn Display)]) -> String
pub fn format(&self, key: &str, args: &[(&str, &dyn Display)]) -> String
The text for key with {name} placeholders filled in.
// score = {player} has {points} points
let text = ctx.lang.format("score", &[("player", &"Anna"), ("points", &12)]);Sourcepub fn plural(&self, key: &str, n: i64) -> String
pub fn plural(&self, key: &str, n: i64) -> String
Picks key.one when n is 1 (or -1) and key.other otherwise, and fills in {n}.
Without those keys, key itself is used.
Sourcepub fn plural_with(
&self,
key: &str,
n: i64,
args: &[(&str, &dyn Display)],
) -> String
pub fn plural_with( &self, key: &str, n: i64, args: &[(&str, &dyn Display)], ) -> String
Like Lang::plural with more placeholders.
Sourcepub fn system() -> Option<String>
pub fn system() -> Option<String>
The player’s system language (e.g. "de"), if the system tells.
Sourcepub fn direction_name(&self, degrees: f32) -> String
pub fn direction_name(&self, degrees: f32) -> String
Like math::direction_name in the current language.
Sourcepub fn describe_position(&self, from: Vec3, yaw: f32, target: Vec3) -> String
pub fn describe_position(&self, from: Vec3, yaw: f32, target: Vec3) -> String
Like math::describe_position in the current
language, e.g. "3 Uhr, 12 Meter".
Examples found in repository?
231 fn update(&mut self, ctx: &mut Context) {
232 let step = vec3(
233 ctx.input.repeating(Key::Right, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Left, 0.25, 0.25) as i32 as f32,
234 ctx.input.repeating(Key::Up, 0.25, 0.25) as i32 as f32 - ctx.input.repeating(Key::Down, 0.25, 0.25) as i32 as f32,
235 0.0,
236 );
237 if step != Vec3::ZERO {
238 self.position = (self.position + step).clamp(Vec3::splat(-20.0), Vec3::splat(20.0));
239 ctx.play("step");
240 if ctx.net.is_host() {
241 ctx.net.send_all(Packet::new("pos").with(PeerId::SERVER).with(self.position));
242 } else {
243 ctx.net.send_all(Packet::new("move").with(self.position));
244 }
245 }
246 ctx.audio.set_listener(self.position, 0.0);
247
248 if ctx.pressed(Key::Enter) {
249 ctx.ui.input("chat", "Message");
250 }
251 if ctx.pressed(Key::Space) {
252 let text = if self.others.is_empty() {
253 "Nobody else is here".to_string()
254 } else {
255 let places: Vec<String> = self
256 .others
257 .values()
258 .map(|o| format!("{}: {}", o.name, ctx.lang.describe_position(self.position, 0.0, o.position)))
259 .collect();
260 places.join(". ")
261 };
262 ctx.speak(text);
263 }
264 if ctx.pressed(Key::P) {
265 if ctx.net.is_host() {
266 ctx.speak(format!("You are the host, {} players connected", ctx.net.player_count()));
267 } else {
268 let ms = (ctx.net.ping(PeerId::SERVER) * 1000.0).round();
269 ctx.speak(format!("Ping {ms} milliseconds"));
270 }
271 }
272 if ctx.pressed(Key::Escape) {
273 ctx.net.close();
274 ctx.audio.stop_all();
275 ctx.speak("You left");
276 let scene = Lobby::new(ctx);
277 ctx.switch_scene(scene);
278 }
279 }Sourcepub fn describe_speed(&self, vehicle: &Vehicle) -> String
pub fn describe_speed(&self, vehicle: &Vehicle) -> String
Like Vehicle::describe_speed in the current language.
Sourcepub fn describe_reason(&self, reason: &Reason) -> String
pub fn describe_reason(&self, reason: &Reason) -> String
Why a network connection ended, as a sentence in the current language, e.g.
"The server is full".
for (_, reason) in ctx.net.left() {
ctx.speak(ctx.lang.describe_reason(&reason));
}Examples found in repository?
88 fn on_net(&mut self, event: &NetEvent, ctx: &mut Context) {
89 match event {
90 NetEvent::Connected(_) => Self::start_game(ctx),
91 NetEvent::Disconnected(_, reason) => ctx.ui.message("error", ctx.lang.describe_reason(reason)),
92 NetEvent::Message(..) => {}
93 }
94 }
95
96 fn update(&mut self, _ctx: &mut Context) {}
97}
98
99/// Another player: where they are and the sound that marks them.
100struct Other {
101 name: String,
102 position: Vec3,
103 sound: Sound,
104}
105
106struct Field {
107 position: Vec3,
108 others: BTreeMap<PeerId, Other>,
109}
110
111impl Field {
112 fn new(ctx: &mut Context) -> Self {
113 ctx.audio.register("other", Synth::triangle(660.0).length(0.06).decay(40.0).then(Synth::silence(0.5)));
114 ctx.audio.register("step", Synth::noise().length(0.05).decay(80.0).volume(0.5));
115 ctx.audio.register("chat", Synth::sine(1200.0).length(0.05).volume(0.3));
116 Self { position: Vec3::ZERO, others: BTreeMap::new() }
117 }
118
119 fn add(&mut self, ctx: &mut Context, id: PeerId, name: &str, position: Vec3) {
120 let sound = ctx.audio.play_looped_at("other", position);
121 sound.set_pitch(1.0 + id.number() as f32 * 0.15);
122 self.others.insert(id, Other { name: name.to_string(), position, sound });
123 }
124
125 fn remove(&mut self, ctx: &mut Context, id: PeerId) {
126 if let Some(other) = self.others.remove(&id) {
127 other.sound.stop();
128 ctx.speak(format!("{} left", other.name));
129 }
130 }
131
132 fn moved(&mut self, id: PeerId, position: Vec3) {
133 if let Some(other) = self.others.get_mut(&id) {
134 other.position = position;
135 other.sound.set_position(position);
136 }
137 }
138
139 fn name(&self, ctx: &Context, id: PeerId) -> String {
140 if id == ctx.net.id() {
141 return ctx.net.name(id).to_string();
142 }
143 self.others.get(&id).map_or("Someone".to_string(), |o| o.name.clone())
144 }
145
146 /// The host's side of the protocol.
147 fn host_events(&mut self, event: &NetEvent, ctx: &mut Context) {
148 match event {
149 NetEvent::Connected(id) => {
150 let name = ctx.net.name(*id).to_string();
151 ctx.speak(format!("{name} joined"));
152 // Tell the newcomer about everybody, and everybody about the newcomer.
153 ctx.net.send(*id, Packet::new("player").with(PeerId::SERVER).with(ctx.net.name(PeerId::SERVER)).with(self.position));
154 for (other, o) in &self.others {
155 ctx.net.send(*id, Packet::new("player").with(*other).with(&o.name).with(o.position));
156 }
157 ctx.net.send_all_except(*id, Packet::new("player").with(*id).with(&name).with(Vec3::ZERO));
158 self.add(ctx, *id, &name, Vec3::ZERO);
159 }
160 NetEvent::Message(from, packet) => match packet.kind() {
161 "move" => {
162 self.moved(*from, packet.vec3(0));
163 ctx.net.send_all_except(*from, Packet::new("pos").with(*from).with(packet.vec3(0)));
164 }
165 "chat" => {
166 let text = packet.text(0);
167 ctx.play("chat");
168 ctx.speak(format!("{}: {text}", self.name(ctx, *from)));
169 ctx.net.send_all_except(*from, Packet::new("chat").with(*from).with(text));
170 }
171 _ => {}
172 },
173 NetEvent::Disconnected(id, _) => {
174 self.remove(ctx, *id);
175 ctx.net.send_all(Packet::new("gone").with(*id));
176 }
177 }
178 }
179
180 /// The client's side of the protocol.
181 fn client_events(&mut self, event: &NetEvent, ctx: &mut Context) {
182 match event {
183 NetEvent::Message(_, packet) => match packet.kind() {
184 "player" => self.add(ctx, packet.peer(0), packet.text(1), packet.vec3(2)),
185 "pos" => self.moved(packet.peer(0), packet.vec3(1)),
186 "gone" => self.remove(ctx, packet.peer(0)),
187 "chat" => {
188 ctx.play("chat");
189 ctx.speak(format!("{}: {}", self.name(ctx, packet.peer(0)), packet.text(1)));
190 }
191 _ => {}
192 },
193 NetEvent::Disconnected(_, reason) => {
194 ctx.speak(ctx.lang.describe_reason(reason));
195 ctx.audio.stop_all();
196 let scene = Lobby::new(ctx);
197 ctx.switch_scene(scene);
198 }
199 NetEvent::Connected(_) => {}
200 }
201 }Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Lang
impl !RefUnwindSafe for Lang
impl !Sync for Lang
impl Send for Lang
impl Unpin for Lang
impl UnsafeUnpin for Lang
impl UnwindSafe for Lang
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.