Add i18n keys to abilities

* New hud/ability.ron file for ability localizations
* i18n keys are created by adding .name and .desc to ability id. Because
  of how i18n worked (returning key if string wasn't found), it was
  impossible to do because it leads to UB in case string is missed.
  To solve this we've added get_opt method that returns None
* New Localization::get_or method for convinient fallback key usage
This commit is contained in:
juliancoffee 2022-06-25 14:23:06 +03:00
parent f4d9cca89b
commit 8c837da561
5 changed files with 73 additions and 58 deletions

View File

@ -0,0 +1,35 @@
/// WARNING: Localization files shall be saved in UTF-8 format without BOM
/// Localization for "global" English
(
string_map: {
// Debug stick
"common.abilities.debug.possess.name": "Possessing Arrow",
"common.abilities.debug.possess.desc": "Shoots a poisonous arrow. Lets you control your target.",
// Sword
"common.abilities.sword.spin.name": "Whirlwind",
"common.abilities.sword.spin.desc": "Move forward while spinning with your sword.",
// Axe
"common.abilities.axe.leap.name": "Axe Jump",
"common.abilities.axe.leap.desc": "A jump with the slashing leap to position of cursor.",
// Hammer
"common.abilities.hammer.leap.name": "Smash of Doom",
"common.abilities.hammer.leap.desc": "An AOE attack with knockback. Leaps to position of cursor.",
// Bow
"common.abilities.bow.shotgun.name": "Burst",
"common.abilities.bow.shotgun.desc": "Launches a burst of arrows",
// Staff
"common.abilities.staff.fireshockwave.name": "Ring of Fire",
"common.abilities.staff.fireshockwave.desc": "Ignites the ground with fiery shockwave.",
// Sceptre
"common.abilities.sceptre.wardingaura.name": "Warding Aura",
"common.abilities.sceptre.wardingaura.desc": "Wards your allies against enemy attacks.",
// Unknown
"common.abilities.unknown.name": "Ability has no title",
"common.abilities.unknown.desc": "Ability has no description",
},
vector_map: {
}
)

View File

@ -80,17 +80,14 @@ struct Language {
impl Language {
/// Get a localized text from the given key
pub fn get<'a>(&'a self, key: &'a str) -> Option<&str> {
pub fn get<'a>(&'a self, key: &str) -> Option<&str> {
self.string_map.get(key).map(String::as_str)
}
/// Get a variation of localized text from the given key
///
/// `index` should be a random number from `0` to `u16::max()`
///
/// If the key is not present in the localization object
/// then the key is returned.
pub fn get_variation<'a>(&'a self, key: &'a str, index: u16) -> Option<&str> {
pub fn get_variation<'a>(&'a self, key: &str, index: u16) -> Option<&str> {
self.vector_map.get(key).and_then(|v| {
if v.is_empty() {
None
@ -163,19 +160,30 @@ pub struct LocalizationGuard {
pub type Localization = LocalizationGuard;
impl LocalizationGuard {
/// Get a localized text from the given key
///
/// First lookup is done in the active language, second in
/// the fallback (if present).
pub fn get_opt<'a>(&'a self, key: &str) -> Option<&'a str> {
self.active
.get(key)
.or_else(|| self.fallback.as_ref().and_then(|f| f.get(key)))
}
/// Get a localized text from the given key
///
/// First lookup is done in the active language, second in
/// the fallback (if present).
/// If the key is not present in the localization object
/// then the key is returned.
pub fn get<'a>(&'a self, key: &'a str) -> &str {
self.active.get(key).unwrap_or_else(|| {
self.fallback
.as_ref()
.and_then(|f| f.get(key))
.unwrap_or(key)
})
pub fn get<'a>(&'a self, key: &'a str) -> &str { self.get_opt(key).unwrap_or(key) }
/// Get a localized text from the given key
///
/// First lookup is done in the active language, second in
/// the fallback (if present).
pub fn get_or<'a>(&'a self, key: &str, fallback_key: &str) -> Option<&'a str> {
self.get_opt(key).or_else(|| self.get_opt(fallback_key))
}
/// Get a variation of localized text from the given key

View File

@ -835,7 +835,7 @@ impl<'a> Widget for Diary<'a> {
)
.ability_id(Some(self.inventory));
let (ability_title, ability_desc) = if let Some(ability_id) = ability_id {
util::ability_description(ability_id)
util::ability_description(ability_id, self.localized_strings)
} else {
(Cow::Borrowed("Drag an ability here to use it."), "")
};
@ -1033,7 +1033,7 @@ impl<'a> Widget for Diary<'a> {
.enumerate()
{
let (ability_title, ability_desc) =
util::ability_description(ability_id.unwrap_or(""));
util::ability_description(ability_id.unwrap_or(""), self.localized_strings);
let (align_state, image_offsets) = if id_index < 6 {
(state.ids.sb_page_left_align, 120.0 * id_index as f64)

View File

@ -612,7 +612,7 @@ impl<'a> Skillbar<'a> {
.get(i)
.and_then(|a| Ability::from(*a).ability_id(Some(inventory)))
})
.map(util::ability_description),
.map(|id| util::ability_description(id, self.localized_strings)),
})
};

View File

@ -356,48 +356,20 @@ pub fn ability_image(imgs: &img_ids::Imgs, ability_id: &str) -> image::Id {
}
}
#[rustfmt::skip]
pub fn ability_description(ability_id: &str) -> (Cow<str>, &str) {
let (name, desc) = match ability_id {
// Debug stick
"common.abilities.debug.possess" => (
"Possessing Arrow",
"Shoots a poisonous arrow. Lets you control your target.",
pub fn ability_description<'a>(
ability_id: &'a str,
loc: &'a i18n::Localization,
) -> (Cow<'a, str>, &'a str) {
let (name, desc) = (
format!("{}.name", ability_id),
format!("{}.desc", ability_id),
);
(
Cow::Borrowed(
loc.get_or(&name, "common.abilities.unknown.name")
.unwrap_or(ability_id),
),
// Sword
"common.abilities.sword.spin" => (
"Whirlwind",
"Move forward while spinning with your sword.",
),
// Axe
"common.abilities.axe.leap" => (
"Axe Jump",
"A jump with the slashing leap to position of cursor.",
),
// Hammer
"common.abilities.hammer.leap" => (
"Smash of Doom",
"An AOE attack with knockback. Leaps to position of cursor.",
),
// Bow
"common.abilities.bow.shotgun" => (
"Burst",
"Launches a burst of arrows",
),
// Staff
"common.abilities.staff.fireshockwave" => (
"Ring of Fire",
"Ignites the ground with fiery shockwave.",
),
// Sceptre
"common.abilities.sceptre.wardingaura" => (
"Thorn Bulwark",
"Protects you and your group with thorns for a short amount of time.",
),
_ => (
"Ability has no title",
"Ability has no description."
),
};
(Cow::Borrowed(name), desc)
loc.get_or(&desc, "common.abilities.unknown.desc")
.unwrap_or(ability_id),
)
}