2022-09-29 09:59:17 +00:00
|
|
|
#![feature(let_chains)]
|
2023-08-27 17:04:20 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
2024-02-02 18:25:46 +00:00
|
|
|
use common::{
|
|
|
|
comp::{
|
2024-02-03 00:05:38 +00:00
|
|
|
body::Gender,
|
2024-02-02 18:25:46 +00:00
|
|
|
chat::{KillSource, KillType},
|
|
|
|
BuffKind, ChatMsg, ChatType, Content,
|
|
|
|
},
|
|
|
|
uid::Uid,
|
2022-09-09 15:27:21 +00:00
|
|
|
};
|
|
|
|
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
|
|
|
use i18n::Localization;
|
|
|
|
|
2022-09-29 09:59:17 +00:00
|
|
|
pub fn localize_chat_message(
|
2023-04-11 14:46:36 +00:00
|
|
|
msg: ChatMsg,
|
2022-09-29 09:59:17 +00:00
|
|
|
lookup_fn: impl Fn(&ChatMsg) -> ChatTypeContext,
|
2023-04-11 22:51:07 +00:00
|
|
|
localization: &Localization,
|
2022-09-09 15:27:21 +00:00
|
|
|
show_char_name: bool,
|
2023-04-11 14:46:36 +00:00
|
|
|
) -> (ChatType<String>, String) {
|
2022-09-12 12:07:11 +00:00
|
|
|
let info = lookup_fn(&msg);
|
2022-09-09 15:27:21 +00:00
|
|
|
|
2024-02-03 16:32:49 +00:00
|
|
|
let name_format_or_complex = |complex, uid: &Uid| match info.player_info.get(uid).cloned() {
|
2024-02-02 22:02:57 +00:00
|
|
|
Some(pi) => {
|
|
|
|
if complex {
|
|
|
|
insert_alias(info.you == *uid, pi, localization)
|
|
|
|
} else {
|
|
|
|
pi.player_alias
|
|
|
|
}
|
|
|
|
},
|
2022-09-29 09:59:17 +00:00
|
|
|
None => info
|
|
|
|
.entity_name
|
|
|
|
.get(uid)
|
|
|
|
.cloned()
|
2024-02-03 20:19:03 +00:00
|
|
|
.expect("client didn't provided enough info"),
|
2022-09-29 09:59:17 +00:00
|
|
|
};
|
|
|
|
|
2024-02-02 22:02:57 +00:00
|
|
|
// Some messages do suffer from complicated logic of insert_alias.
|
|
|
|
// This includes every notification-like message, like death.
|
|
|
|
let name_format = |uid: &Uid| name_format_or_complex(false, uid);
|
2024-02-02 18:25:46 +00:00
|
|
|
|
2024-02-03 00:05:38 +00:00
|
|
|
// This is a hack, kind of.
|
|
|
|
//
|
|
|
|
// Current implementation just checks if our player is humanoid, and if so,
|
|
|
|
// we take the body_type of its character and assume it as grammatical gender.
|
|
|
|
//
|
|
|
|
// In short,
|
|
|
|
// body_type of character
|
|
|
|
// -> sex of character
|
|
|
|
// -> gender of player.
|
|
|
|
// -> grammatical gender for use in messages.
|
|
|
|
//
|
|
|
|
// This is obviously, wrong, but it's good enough approximation, after all,
|
|
|
|
// players do choose their characters.
|
|
|
|
//
|
|
|
|
// In the future, we will want special GUI where players can specify their
|
|
|
|
// gender (and change it!), and we do want to handle more genders than just
|
|
|
|
// male and female.
|
|
|
|
//
|
|
|
|
// Ideally, the system should handle following (if we exclude plurals):
|
|
|
|
// - Female
|
|
|
|
// - Male
|
|
|
|
// - Neuter (or fallback Female)
|
|
|
|
// - Neuter (or fallback Male)
|
|
|
|
// - Intermediate (or fallback Female)
|
|
|
|
// - Intermediate (or fallback Male)
|
|
|
|
// and maybe more, not sure.
|
|
|
|
//
|
|
|
|
// What is supported by language and what is not, as well as maybe how to
|
|
|
|
// convert genders into strings to match, should go into _manifest.ron file
|
|
|
|
//
|
|
|
|
// So let's say language only supports male and female, we will convert all
|
|
|
|
// genders to these, using some fallbacks, and pass it.
|
|
|
|
//
|
|
|
|
// If the language can represent Female, Male and Neuter, we can pass these.
|
|
|
|
//
|
|
|
|
// Exact design of such a complex system is honestly up to discussion.
|
2024-02-03 17:56:17 +00:00
|
|
|
let gender_str = |uid: &Uid| {
|
|
|
|
if let Some(pi) = info.player_info.get(uid) {
|
|
|
|
match pi.character.as_ref().and_then(|c| c.gender) {
|
|
|
|
Some(Gender::Feminine) => "she".to_owned(),
|
|
|
|
Some(Gender::Masculine) => "he".to_owned(),
|
2024-02-04 16:42:18 +00:00
|
|
|
None => "??".to_owned(),
|
2024-02-03 16:32:49 +00:00
|
|
|
}
|
2024-02-03 17:56:17 +00:00
|
|
|
} else {
|
2024-02-03 16:32:49 +00:00
|
|
|
"??".to_owned()
|
2024-02-03 17:56:17 +00:00
|
|
|
}
|
2024-02-03 00:05:38 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// This is where the most fun begings.
|
|
|
|
//
|
|
|
|
// Unlike people, "items" can have their own gender, which is completely
|
|
|
|
// independent of everything, including common sense.
|
|
|
|
//
|
|
|
|
// For example, word "masculinity" can be feminine in some languages,
|
|
|
|
// as well as word "boy", and vice versa.
|
|
|
|
//
|
|
|
|
// So we can't rely on body_type, at all. And even if we did try, our
|
|
|
|
// body_type isn't even always represents animal sex, there are some
|
|
|
|
// animals that use body_type to represent their kind, like different
|
|
|
|
// types of Fox ("male" fox is forest, "female" is arctic one).
|
|
|
|
// And what about Mindflayer? They do have varied body_type, but do they
|
|
|
|
// even have concept of gender?
|
|
|
|
//
|
|
|
|
// Our use case is probably less cryptic, after all we are limited by
|
|
|
|
// mostly sentient things, but that doesn't help at all.
|
|
|
|
//
|
|
|
|
// Common example is word "spider", which can be feminine in one languages
|
|
|
|
// and masculine in other, and sometimes even neuter.
|
|
|
|
//
|
|
|
|
// Oh, and I want to add that we are talking about grammatical genders, and
|
|
|
|
// languages define their own grammar. There are languages that have more
|
|
|
|
// than three grammatical genders, there are languages that don't have
|
|
|
|
// male/female distinction and instead realy on animacy/non-animacy.
|
|
|
|
// What has an animacy and what doesn't is for language to decide.
|
|
|
|
// There are languages as well that mix these concepts and may have neuter,
|
|
|
|
// female, masculine with animacy, masculine with animacy. Some languages
|
|
|
|
// have their own scheme of things that arbitrarily picks noun-class per
|
|
|
|
// noun.
|
|
|
|
// Don't get me wrong. *All* languages do pick the gender for the word
|
|
|
|
// arbitrary as I showed at the beginning, it's just some languages have
|
|
|
|
// not just different mapping, but different gender set as well.
|
|
|
|
//
|
|
|
|
// The *only* option we have is fetch the gender per each name entry from
|
|
|
|
// localization files.
|
|
|
|
//
|
|
|
|
// I'm not 100% sure what should be the implementation of it, but I imagine
|
|
|
|
// that Stats::name() should be changed to include a way to reference where
|
|
|
|
// to grab the gender associated with this name, so translation then can
|
|
|
|
// pick right article or use right adjective/verb connected with NPC in the
|
|
|
|
// context of the message.
|
|
|
|
let _gender_str_npc = || "idk".to_owned();
|
2024-02-02 18:25:46 +00:00
|
|
|
|
|
|
|
let message_format = |from: &Uid, content: &Content, group: Option<&String>| {
|
2024-02-02 22:02:57 +00:00
|
|
|
let alias = name_format_or_complex(true, from);
|
|
|
|
|
2024-01-18 00:22:29 +00:00
|
|
|
let name = if let Some(pi) = info.player_info.get(from).cloned()
|
|
|
|
&& show_char_name
|
|
|
|
{
|
2022-09-29 09:59:17 +00:00
|
|
|
pi.character.map(|c| c.name)
|
2022-09-09 15:27:21 +00:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2024-02-02 22:02:57 +00:00
|
|
|
|
2023-04-11 22:51:07 +00:00
|
|
|
let message = localization.get_content(content);
|
2024-02-02 22:02:57 +00:00
|
|
|
|
|
|
|
let line = match group {
|
|
|
|
Some(group) => match name {
|
|
|
|
Some(name) => localization.get_msg_ctx(
|
|
|
|
"hud-chat-message-in-group-with-name",
|
|
|
|
&i18n::fluent_args! {
|
|
|
|
"group" => group,
|
|
|
|
"alias" => alias,
|
|
|
|
"name" => name,
|
|
|
|
"msg" => message,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
None => {
|
|
|
|
localization.get_msg_ctx("hud-chat-message-in-group", &i18n::fluent_args! {
|
|
|
|
"group" => group,
|
|
|
|
"alias" => alias,
|
|
|
|
"msg" => message,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
},
|
|
|
|
None => match name {
|
|
|
|
Some(name) => {
|
|
|
|
localization.get_msg_ctx("hud-chat-message-with-name", &i18n::fluent_args! {
|
|
|
|
"alias" => alias,
|
|
|
|
"name" => name,
|
|
|
|
"msg" => message,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
None => localization.get_msg_ctx("hud-chat-message", &i18n::fluent_args! {
|
|
|
|
"alias" => alias,
|
|
|
|
"msg" => message,
|
|
|
|
}),
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
line.into_owned()
|
2022-09-09 15:27:21 +00:00
|
|
|
};
|
|
|
|
|
2022-09-29 09:59:17 +00:00
|
|
|
let new_msg = match &msg.chat_type {
|
2023-04-11 22:51:07 +00:00
|
|
|
ChatType::Online(uid) => localization
|
2022-09-29 09:59:17 +00:00
|
|
|
.get_msg_ctx("hud-chat-online_msg", &i18n::fluent_args! {
|
2024-02-02 18:25:46 +00:00
|
|
|
"user_gender" => gender_str(uid),
|
2022-09-29 09:59:17 +00:00
|
|
|
"name" => name_format(uid),
|
|
|
|
})
|
|
|
|
.into_owned(),
|
2023-04-11 22:51:07 +00:00
|
|
|
ChatType::Offline(uid) => localization
|
2022-09-29 09:59:17 +00:00
|
|
|
.get_msg_ctx("hud-chat-offline_msg", &i18n::fluent_args! {
|
2024-02-02 18:25:46 +00:00
|
|
|
"user_gender" => gender_str(uid),
|
|
|
|
"name" => name_format(uid),
|
2022-09-29 09:59:17 +00:00
|
|
|
})
|
|
|
|
.into_owned(),
|
2024-02-02 18:25:46 +00:00
|
|
|
ChatType::CommandError
|
|
|
|
| ChatType::CommandInfo
|
2024-02-03 20:19:03 +00:00
|
|
|
| ChatType::Meta
|
2024-02-02 18:25:46 +00:00
|
|
|
| ChatType::FactionMeta(_)
|
|
|
|
| ChatType::GroupMeta(_) => localization.get_content(msg.content()),
|
2022-09-29 09:59:17 +00:00
|
|
|
ChatType::Tell(from, to) => {
|
2024-02-02 22:02:57 +00:00
|
|
|
// If `from` is you, it means you're writing to someone
|
|
|
|
// and you want to see who you're writing to.
|
|
|
|
//
|
|
|
|
// Otherwise, someone writes to you, and you want to see
|
|
|
|
// who is that person that's writing to you.
|
|
|
|
let (key, person_to_show) = if info.you == *from {
|
|
|
|
("hud-chat-tell-to", to)
|
2022-09-29 09:59:17 +00:00
|
|
|
} else {
|
2024-02-02 22:02:57 +00:00
|
|
|
("hud-chat-tell-from", from)
|
|
|
|
};
|
|
|
|
|
|
|
|
localization
|
|
|
|
.get_msg_ctx(key, &i18n::fluent_args! {
|
|
|
|
"alias" => name_format(person_to_show),
|
|
|
|
"user_gender" => gender_str(person_to_show),
|
2024-02-06 12:44:52 +00:00
|
|
|
"msg" => localization.get_content(msg.content()),
|
2024-02-02 22:02:57 +00:00
|
|
|
})
|
|
|
|
.into_owned()
|
2022-09-09 15:27:21 +00:00
|
|
|
},
|
2024-02-02 18:25:46 +00:00
|
|
|
ChatType::Say(uid) | ChatType::Region(uid) | ChatType::World(uid) => {
|
|
|
|
message_format(uid, msg.content(), None)
|
|
|
|
},
|
|
|
|
ChatType::Group(uid, descriptor) | ChatType::Faction(uid, descriptor) => {
|
|
|
|
message_format(uid, msg.content(), Some(descriptor))
|
|
|
|
},
|
|
|
|
ChatType::Npc(uid) | ChatType::NpcSay(uid) => message_format(uid, msg.content(), None),
|
2023-04-11 14:46:36 +00:00
|
|
|
ChatType::NpcTell(from, to) => {
|
2024-02-02 22:02:57 +00:00
|
|
|
// If `from` is you, it means you're writing to someone
|
|
|
|
// and you want to see who you're writing to.
|
|
|
|
//
|
|
|
|
// Otherwise, someone writes to you, and you want to see
|
|
|
|
// who is that person that's writing to you.
|
|
|
|
//
|
|
|
|
// Hopefully, no gendering needed, because for npc, we
|
|
|
|
// simply don't know.
|
|
|
|
let (key, person_to_show) = if info.you == *from {
|
|
|
|
("hud-chat-tell-to-npc", to)
|
2022-09-29 09:59:17 +00:00
|
|
|
} else {
|
2024-02-02 22:02:57 +00:00
|
|
|
("hud-chat-tell-from-npc", from)
|
|
|
|
};
|
|
|
|
|
|
|
|
localization
|
|
|
|
.get_msg_ctx(key, &i18n::fluent_args! {
|
|
|
|
"alias" => name_format(person_to_show),
|
2024-02-06 12:44:52 +00:00
|
|
|
"msg" => localization.get_content(msg.content()),
|
2024-02-02 22:02:57 +00:00
|
|
|
})
|
|
|
|
.into_owned()
|
2022-09-09 15:27:21 +00:00
|
|
|
},
|
2022-09-29 09:59:17 +00:00
|
|
|
ChatType::Kill(kill_source, victim) => {
|
2024-02-02 18:25:46 +00:00
|
|
|
localize_kill_message(kill_source, victim, name_format, gender_str, localization)
|
|
|
|
},
|
|
|
|
};
|
2022-09-29 09:59:17 +00:00
|
|
|
|
2024-02-02 18:25:46 +00:00
|
|
|
(msg.chat_type, new_msg)
|
|
|
|
}
|
2022-09-29 09:59:17 +00:00
|
|
|
|
2024-02-02 18:25:46 +00:00
|
|
|
fn localize_kill_message(
|
|
|
|
kill_source: &KillSource,
|
|
|
|
victim: &Uid,
|
|
|
|
name_format: impl Fn(&Uid) -> String,
|
|
|
|
gender_str: impl Fn(&Uid) -> String,
|
|
|
|
localization: &Localization,
|
|
|
|
) -> String {
|
|
|
|
match kill_source {
|
|
|
|
// PvP deaths
|
|
|
|
KillSource::Player(attacker, kill_type) => {
|
|
|
|
let key = match kill_type {
|
|
|
|
KillType::Melee => "hud-chat-pvp_melee_kill_msg",
|
|
|
|
KillType::Projectile => "hud-chat-pvp_ranged_kill_msg",
|
|
|
|
KillType::Explosion => "hud-chat-pvp_explosion_kill_msg",
|
|
|
|
KillType::Energy => "hud-chat-pvp_energy_kill_msg",
|
|
|
|
KillType::Other => "hud-chat-pvp_other_kill_msg",
|
2024-02-03 17:56:17 +00:00
|
|
|
KillType::Buff(buff_kind) => {
|
2024-02-03 20:19:03 +00:00
|
|
|
let buff_ident = get_buff_ident(*buff_kind);
|
2024-02-03 17:56:17 +00:00
|
|
|
|
2024-02-03 20:19:03 +00:00
|
|
|
return localization
|
|
|
|
.get_attr_ctx(
|
|
|
|
"hud-chat-died_of_pvp_buff_msg",
|
|
|
|
buff_ident,
|
|
|
|
&i18n::fluent_args! {
|
|
|
|
"victim" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
"attacker" => name_format(attacker),
|
|
|
|
"attacker_gender" => gender_str(attacker),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.into_owned();
|
2024-02-03 17:56:17 +00:00
|
|
|
},
|
2024-02-02 18:25:46 +00:00
|
|
|
};
|
|
|
|
localization.get_msg_ctx(key, &i18n::fluent_args! {
|
|
|
|
"victim" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
"attacker" => name_format(attacker),
|
|
|
|
"attacker_gender" => gender_str(attacker),
|
|
|
|
})
|
|
|
|
},
|
|
|
|
// PvE deaths
|
|
|
|
KillSource::NonPlayer(attacker_name, kill_type) => {
|
|
|
|
let key = match kill_type {
|
|
|
|
KillType::Melee => "hud-chat-npc_melee_kill_msg",
|
|
|
|
KillType::Projectile => "hud-chat-npc_ranged_kill_msg",
|
|
|
|
KillType::Explosion => "hud-chat-npc_explosion_kill_msg",
|
|
|
|
KillType::Energy => "hud-chat-npc_energy_kill_msg",
|
|
|
|
KillType::Other => "hud-chat-npc_other_kill_msg",
|
2024-02-03 17:56:17 +00:00
|
|
|
KillType::Buff(buff_kind) => {
|
2024-02-03 20:19:03 +00:00
|
|
|
let buff_ident = get_buff_ident(*buff_kind);
|
2024-02-03 17:56:17 +00:00
|
|
|
|
2024-02-03 20:19:03 +00:00
|
|
|
return localization
|
|
|
|
.get_attr_ctx(
|
|
|
|
"hud-chat-died_of_npc_buff_msg",
|
|
|
|
buff_ident,
|
|
|
|
&i18n::fluent_args! {
|
|
|
|
"victim" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
"attacker" => attacker_name,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.into_owned();
|
2024-02-03 17:56:17 +00:00
|
|
|
},
|
2024-02-02 18:25:46 +00:00
|
|
|
};
|
|
|
|
localization.get_msg_ctx(key, &i18n::fluent_args! {
|
|
|
|
"victim" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
"attacker" => attacker_name,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
// Other deaths
|
|
|
|
KillSource::FallDamage => {
|
|
|
|
localization.get_msg_ctx("hud-chat-fall_kill_msg", &i18n::fluent_args! {
|
|
|
|
"name" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
})
|
|
|
|
},
|
|
|
|
KillSource::Suicide => {
|
|
|
|
localization.get_msg_ctx("hud-chat-suicide_msg", &i18n::fluent_args! {
|
|
|
|
"name" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
})
|
|
|
|
},
|
2024-02-03 17:56:17 +00:00
|
|
|
KillSource::NonExistent(KillType::Buff(buff_kind)) => {
|
|
|
|
let buff_ident = get_buff_ident(*buff_kind);
|
|
|
|
|
|
|
|
let s = localization
|
|
|
|
.get_attr_ctx(
|
|
|
|
"hud-chat-died_of_buff_nonexistent_msg",
|
|
|
|
buff_ident,
|
|
|
|
&i18n::fluent_args! {
|
|
|
|
"victim" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.into_owned();
|
|
|
|
Cow::Owned(s)
|
|
|
|
},
|
2024-02-02 18:25:46 +00:00
|
|
|
KillSource::NonExistent(_) | KillSource::Other => {
|
|
|
|
localization.get_msg_ctx("hud-chat-default_death_msg", &i18n::fluent_args! {
|
|
|
|
"name" => name_format(victim),
|
|
|
|
"victim_gender" => gender_str(victim),
|
|
|
|
})
|
|
|
|
},
|
|
|
|
}
|
|
|
|
.into_owned()
|
|
|
|
}
|
|
|
|
|
2024-02-03 20:19:03 +00:00
|
|
|
/// Determines .attr for `hud-chat-died-of-buff` messages
|
2024-02-02 18:25:46 +00:00
|
|
|
fn get_buff_ident(buff: BuffKind) -> &'static str {
|
|
|
|
match buff {
|
|
|
|
BuffKind::Burning => "burning",
|
|
|
|
BuffKind::Bleeding => "bleeding",
|
|
|
|
BuffKind::Cursed => "curse",
|
|
|
|
BuffKind::Crippled => "crippled",
|
|
|
|
BuffKind::Frozen => "frozen",
|
|
|
|
BuffKind::Regeneration
|
|
|
|
| BuffKind::Saturation
|
|
|
|
| BuffKind::Potion
|
|
|
|
| BuffKind::Agility
|
|
|
|
| BuffKind::CampfireHeal
|
|
|
|
| BuffKind::EnergyRegen
|
|
|
|
| BuffKind::IncreaseMaxEnergy
|
|
|
|
| BuffKind::IncreaseMaxHealth
|
|
|
|
| BuffKind::Invulnerability
|
|
|
|
| BuffKind::ProtectingWard
|
|
|
|
| BuffKind::Frenzied
|
|
|
|
| BuffKind::Hastened
|
|
|
|
| BuffKind::Fortitude
|
|
|
|
| BuffKind::Reckless
|
|
|
|
| BuffKind::Flame
|
|
|
|
| BuffKind::Frigid
|
|
|
|
| BuffKind::Lifesteal
|
|
|
|
// | BuffKind::SalamanderAspect
|
|
|
|
| BuffKind::ImminentCritical
|
|
|
|
| BuffKind::Fury
|
|
|
|
| BuffKind::Sunderer
|
|
|
|
| BuffKind::Defiance
|
|
|
|
| BuffKind::Bloodfeast
|
2024-02-17 04:40:42 +00:00
|
|
|
| BuffKind::Berserk
|
2024-03-28 23:41:31 +00:00
|
|
|
| BuffKind::ScornfulTaunt
|
|
|
|
| BuffKind::Tenacity => {
|
2024-02-02 18:25:46 +00:00
|
|
|
tracing::error!("Player was killed by a positive buff!");
|
|
|
|
"mysterious"
|
|
|
|
},
|
|
|
|
BuffKind::Wet
|
|
|
|
| BuffKind::Ensnared
|
|
|
|
| BuffKind::Poisoned
|
|
|
|
| BuffKind::Parried
|
|
|
|
| BuffKind::PotionSickness
|
|
|
|
| BuffKind::Polymorphed
|
2024-02-24 23:50:27 +00:00
|
|
|
| BuffKind::Heatstroke
|
2024-02-25 18:42:12 +00:00
|
|
|
| BuffKind::Rooted
|
2024-02-25 19:58:09 +00:00
|
|
|
| BuffKind::Winded
|
2024-03-05 04:24:29 +00:00
|
|
|
| BuffKind::Concussion
|
|
|
|
| BuffKind::Staggered => {
|
2024-02-02 18:25:46 +00:00
|
|
|
tracing::error!("Player was killed by a debuff that doesn't do damage!");
|
|
|
|
"mysterious"
|
|
|
|
},
|
|
|
|
}
|
2022-09-12 12:07:11 +00:00
|
|
|
}
|
|
|
|
|
2024-02-03 20:19:03 +00:00
|
|
|
/// Used for inserting spacing for mod badge icon next to alias
|
|
|
|
// TODO: consider passing '$is_you' to hud-chat-message strings along with
|
|
|
|
// $spacing variable, for more flexible translations.
|
2024-02-02 22:02:57 +00:00
|
|
|
fn insert_alias(_replace_you: bool, info: PlayerInfo, _localization: &Localization) -> String {
|
2023-01-28 01:45:05 +00:00
|
|
|
// Leave space for a mod badge icon.
|
|
|
|
const MOD_SPACING: &str = " ";
|
2024-02-02 22:02:57 +00:00
|
|
|
|
|
|
|
if info.is_moderator {
|
|
|
|
format!("{}{}", MOD_SPACING, info.player_alias)
|
2024-02-03 20:19:03 +00:00
|
|
|
} else {
|
|
|
|
info.player_alias
|
2022-09-12 12:07:11 +00:00
|
|
|
}
|
2022-09-09 15:27:21 +00:00
|
|
|
}
|
2024-01-16 21:07:36 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
#[allow(unused)] use super::*;
|
|
|
|
use common::comp::{
|
|
|
|
inventory::item::{all_items_expect, ItemDesc, ItemI18n},
|
|
|
|
Content,
|
|
|
|
};
|
|
|
|
use i18n::LocalizationHandle;
|
|
|
|
|
|
|
|
// item::tests::ensure_item_localization tests that we have Content for
|
|
|
|
// each item. This tests that we actually have at least English translation
|
|
|
|
// for this Content.
|
|
|
|
#[test]
|
|
|
|
fn test_item_text() {
|
|
|
|
let manifest = ItemI18n::new_expect();
|
|
|
|
let localization = LocalizationHandle::load_expect("en").read();
|
|
|
|
let items = all_items_expect();
|
|
|
|
|
|
|
|
for item in items {
|
|
|
|
let (name, desc) = item.i18n(&manifest);
|
|
|
|
|
|
|
|
// check i18n for item name
|
|
|
|
let Content::Key(key) = name else {
|
|
|
|
panic!("name is expected to be Key, please fix the test");
|
|
|
|
};
|
|
|
|
localization.try_msg(&key).unwrap_or_else(|| {
|
|
|
|
panic!("'{key}' name doesn't have i18n");
|
|
|
|
});
|
|
|
|
|
|
|
|
// check i18n for item desc
|
|
|
|
let Content::Attr(key, attr) = desc else {
|
|
|
|
panic!("desc is expected to be Attr, please fix the test");
|
|
|
|
};
|
|
|
|
localization.try_attr(&key, &attr).unwrap_or_else(|| {
|
|
|
|
panic!("'{key}' description doesn't have i18n");
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|