Skip to main content

Lang

Struct Lang 

Source
pub struct Lang { /* private fields */ }
Expand description

The translation tables and the current language. Reach it through ctx.lang.

Implementations§

Source§

impl Lang

Source

pub fn new() -> Self

Empty tables, English as current and fallback language.

Source

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.

Source

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.

Source

pub fn insert( &mut self, code: &str, key: impl Into<String>, text: impl Into<String>, )

Adds or replaces one text.

Source

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.

Source

pub fn current(&self) -> &str

The current language code, e.g. "de".

Source

pub fn fallback(&self) -> &str

The language used for keys missing in the current one (default "en").

Source

pub fn set_fallback(&mut self, code: &str)

Changes the fallback language.

Source

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.

Source

pub fn name(&self, code: &str) -> String

The name of a language as written in its file (key language), else the code.

Source

pub fn has(&self, key: &str) -> bool

Whether key has a text in the current or the fallback language.

Source

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.

Source

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)]);
Source

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.

Source

pub fn plural_with( &self, key: &str, n: i64, args: &[(&str, &dyn Display)], ) -> String

Like Lang::plural with more placeholders.

Source

pub fn system() -> Option<String>

The player’s system language (e.g. "de"), if the system tells.

Source

pub fn direction_name(&self, degrees: f32) -> String

Like math::direction_name in the current language.

Source

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?
examples/online.rs (line 258)
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    }
Source

pub fn describe_speed(&self, vehicle: &Vehicle) -> String

Like Vehicle::describe_speed in the current language.

Source

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?
examples/online.rs (line 91)
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§

Source§

impl Clone for Lang

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Lang

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Lang

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more