mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Simplified localisation logic
This commit is contained in:
parent
3484e156d1
commit
3582d86c70
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -6692,6 +6692,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"tracing",
|
"tracing",
|
||||||
"unic-langid",
|
"unic-langid",
|
||||||
|
"veloren-common",
|
||||||
"veloren-common-assets",
|
"veloren-common-assets",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -7173,7 +7174,6 @@ dependencies = [
|
|||||||
name = "veloren-voxygen-i18n-helpers"
|
name = "veloren-voxygen-i18n-helpers"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.12.3",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"veloren-client-i18n",
|
"veloren-client-i18n",
|
||||||
"veloren-common",
|
"veloren-common",
|
||||||
|
@ -7,6 +7,7 @@ version = "0.13.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Assets
|
# Assets
|
||||||
|
common = {package = "veloren-common", path = "../../common"}
|
||||||
common-assets = {package = "veloren-common-assets", path = "../../common/assets"}
|
common-assets = {package = "veloren-common-assets", path = "../../common/assets"}
|
||||||
ron = "0.8"
|
ron = "0.8"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
@ -19,6 +19,7 @@ use std::{borrow::Cow, io};
|
|||||||
use assets::{source::DirEntry, AssetExt, AssetGuard, AssetHandle, ReloadWatcher, SharedString};
|
use assets::{source::DirEntry, AssetExt, AssetGuard, AssetHandle, ReloadWatcher, SharedString};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
// Re-export because I don't like prefix
|
// Re-export because I don't like prefix
|
||||||
|
use common::comp::Content;
|
||||||
use common_assets as assets;
|
use common_assets as assets;
|
||||||
|
|
||||||
// Re-export for argument creation
|
// Re-export for argument creation
|
||||||
@ -331,6 +332,23 @@ impl LocalizationGuard {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Localize the given context.
|
||||||
|
pub fn get_content(&self, content: &Content) -> String {
|
||||||
|
match content {
|
||||||
|
Content::Plain(text) => text.clone(),
|
||||||
|
Content::Localized { key, seed, args } => self
|
||||||
|
.get_variation_ctx(
|
||||||
|
key,
|
||||||
|
*seed,
|
||||||
|
&args
|
||||||
|
.iter()
|
||||||
|
.map(|(k, content)| (k, self.get_content(content)))
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.into_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a localized text from the variation of given key with given
|
/// Get a localized text from the variation of given key with given
|
||||||
/// arguments
|
/// arguments
|
||||||
///
|
///
|
||||||
|
@ -183,6 +183,9 @@ impl<G> ChatType<G> {
|
|||||||
// - In-game notes/books (we could add a variant that allows structuring complex, novel textual
|
// - In-game notes/books (we could add a variant that allows structuring complex, novel textual
|
||||||
// information as a syntax tree or some other intermediate format that can be localised by the
|
// information as a syntax tree or some other intermediate format that can be localised by the
|
||||||
// client)
|
// client)
|
||||||
|
// TODO: We probably want to have this type be able to represent similar things to
|
||||||
|
// `fluent::FluentValue`, such as numeric values, so that they can be properly localised in whatever
|
||||||
|
// manner is required.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum Content {
|
pub enum Content {
|
||||||
/// The content is a plaintext string that should be shown to the user
|
/// The content is a plaintext string that should be shown to the user
|
||||||
@ -239,16 +242,6 @@ impl Content {
|
|||||||
Self::Localized { .. } => None,
|
Self::Localized { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn localize<F>(&self, i18n_variation: F) -> String
|
|
||||||
where
|
|
||||||
F: Fn(&str, u16, &HashMap<String, Content>) -> String,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Content::Plain(text) => text.to_string(),
|
|
||||||
Content::Localized { key, seed, args } => i18n_variation(key, *seed, args),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores chat text, type
|
// Stores chat text, type
|
||||||
|
@ -11,4 +11,3 @@ common = {package = "veloren-common", path = "../../common"}
|
|||||||
i18n = {package = "veloren-client-i18n", path = "../../client/i18n"}
|
i18n = {package = "veloren-client-i18n", path = "../../client/i18n"}
|
||||||
# Utility
|
# Utility
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
hashbrown = { version = "0.12" }
|
|
||||||
|
@ -4,50 +4,18 @@ use common::comp::{
|
|||||||
BuffKind, ChatMsg, ChatType, Content,
|
BuffKind, ChatMsg, ChatType, Content,
|
||||||
};
|
};
|
||||||
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
use common_net::msg::{ChatTypeContext, PlayerInfo};
|
||||||
use hashbrown::HashMap;
|
|
||||||
use i18n::Localization;
|
use i18n::Localization;
|
||||||
|
|
||||||
pub fn make_localizer(
|
|
||||||
localization: &Localization,
|
|
||||||
) -> impl Fn(&str, u16, &HashMap<String, Content>) -> String + Copy + '_ {
|
|
||||||
fn get(
|
|
||||||
localization: &Localization,
|
|
||||||
key: &str,
|
|
||||||
seed: u16,
|
|
||||||
args: &HashMap<String, Content>,
|
|
||||||
) -> String {
|
|
||||||
localization
|
|
||||||
.get_variation_ctx(
|
|
||||||
key,
|
|
||||||
seed,
|
|
||||||
&args
|
|
||||||
.iter()
|
|
||||||
.map(|(k, v)| {
|
|
||||||
(
|
|
||||||
k,
|
|
||||||
v.localize(move |key, seed, args| get(localization, key, seed, args)),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
.into_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
move |key: &str, seed: u16, args: &HashMap<String, Content>| get(localization, key, seed, args)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn localize_chat_message(
|
pub fn localize_chat_message(
|
||||||
msg: ChatMsg,
|
msg: ChatMsg,
|
||||||
lookup_fn: impl Fn(&ChatMsg) -> ChatTypeContext,
|
lookup_fn: impl Fn(&ChatMsg) -> ChatTypeContext,
|
||||||
localisation: &Localization,
|
localization: &Localization,
|
||||||
show_char_name: bool,
|
show_char_name: bool,
|
||||||
) -> (ChatType<String>, String) {
|
) -> (ChatType<String>, String) {
|
||||||
let info = lookup_fn(&msg);
|
let info = lookup_fn(&msg);
|
||||||
|
|
||||||
let localizer = make_localizer(localisation);
|
|
||||||
|
|
||||||
let name_format = |uid: &common::uid::Uid| match info.player_alias.get(uid).cloned() {
|
let name_format = |uid: &common::uid::Uid| match info.player_alias.get(uid).cloned() {
|
||||||
Some(pi) => insert_alias(info.you == *uid, pi, localisation),
|
Some(pi) => insert_alias(info.you == *uid, pi, localization),
|
||||||
None => info
|
None => info
|
||||||
.entity_name
|
.entity_name
|
||||||
.get(uid)
|
.get(uid)
|
||||||
@ -62,7 +30,7 @@ pub fn localize_chat_message(
|
|||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let message = content.localize(localizer);
|
let message = localization.get_content(content);
|
||||||
match (group, name) {
|
match (group, name) {
|
||||||
(Some(group), None) => format!("({group}) [{alias}]: {message}"),
|
(Some(group), None) => format!("({group}) [{alias}]: {message}"),
|
||||||
(None, None) => format!("[{alias}]: {message}"),
|
(None, None) => format!("[{alias}]: {message}"),
|
||||||
@ -72,29 +40,35 @@ pub fn localize_chat_message(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let new_msg = match &msg.chat_type {
|
let new_msg = match &msg.chat_type {
|
||||||
ChatType::Online(uid) => localisation
|
ChatType::Online(uid) => localization
|
||||||
.get_msg_ctx("hud-chat-online_msg", &i18n::fluent_args! {
|
.get_msg_ctx("hud-chat-online_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(uid),
|
"name" => name_format(uid),
|
||||||
})
|
})
|
||||||
.into_owned(),
|
.into_owned(),
|
||||||
ChatType::Offline(uid) => localisation
|
ChatType::Offline(uid) => localization
|
||||||
.get_msg_ctx("hud-chat-offline_msg", &i18n::fluent_args! {
|
.get_msg_ctx("hud-chat-offline_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(uid
|
"name" => name_format(uid
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
.into_owned(),
|
.into_owned(),
|
||||||
ChatType::CommandError => msg.content().localize(localizer),
|
ChatType::CommandError => localization.get_content(msg.content()),
|
||||||
ChatType::CommandInfo => msg.content().localize(localizer),
|
ChatType::CommandInfo => localization.get_content(msg.content()),
|
||||||
ChatType::FactionMeta(_) => msg.content().localize(localizer),
|
ChatType::FactionMeta(_) => localization.get_content(msg.content()),
|
||||||
ChatType::GroupMeta(_) => msg.content().localize(localizer),
|
ChatType::GroupMeta(_) => localization.get_content(msg.content()),
|
||||||
ChatType::Tell(from, to) => {
|
ChatType::Tell(from, to) => {
|
||||||
let from_alias = name_format(from);
|
let from_alias = name_format(from);
|
||||||
let to_alias = name_format(to);
|
let to_alias = name_format(to);
|
||||||
// TODO: internationalise
|
// TODO: internationalise
|
||||||
if *from == info.you {
|
if *from == info.you {
|
||||||
format!("To [{to_alias}]: {}", msg.content().localize(localizer))
|
format!(
|
||||||
|
"To [{to_alias}]: {}",
|
||||||
|
localization.get_content(msg.content())
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("From [{from_alias}]: {}", msg.content().localize(localizer))
|
format!(
|
||||||
|
"From [{from_alias}]: {}",
|
||||||
|
localization.get_content(msg.content())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChatType::Say(uid) => message_format(uid, msg.content(), None),
|
ChatType::Say(uid) => message_format(uid, msg.content(), None),
|
||||||
@ -111,12 +85,18 @@ pub fn localize_chat_message(
|
|||||||
let to_alias = name_format(to);
|
let to_alias = name_format(to);
|
||||||
// TODO: internationalise
|
// TODO: internationalise
|
||||||
if *from == info.you {
|
if *from == info.you {
|
||||||
format!("To [{to_alias}]: {}", msg.content().localize(localizer))
|
format!(
|
||||||
|
"To [{to_alias}]: {}",
|
||||||
|
localization.get_content(msg.content())
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
format!("From [{from_alias}]: {}", msg.content().localize(localizer))
|
format!(
|
||||||
|
"From [{from_alias}]: {}",
|
||||||
|
localization.get_content(msg.content())
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ChatType::Meta => msg.content().localize(localizer),
|
ChatType::Meta => localization.get_content(msg.content()),
|
||||||
ChatType::Kill(kill_source, victim) => {
|
ChatType::Kill(kill_source, victim) => {
|
||||||
let i18n_buff = |buff| match buff {
|
let i18n_buff = |buff| match buff {
|
||||||
BuffKind::Burning => "hud-outcome-burning",
|
BuffKind::Burning => "hud-outcome-burning",
|
||||||
@ -155,9 +135,9 @@ pub fn localize_chat_message(
|
|||||||
// Buff deaths
|
// Buff deaths
|
||||||
KillSource::Player(attacker, KillType::Buff(buff_kind)) => {
|
KillSource::Player(attacker, KillType::Buff(buff_kind)) => {
|
||||||
let i18n_buff = i18n_buff(*buff_kind);
|
let i18n_buff = i18n_buff(*buff_kind);
|
||||||
let buff = localisation.get_msg(i18n_buff);
|
let buff = localization.get_msg(i18n_buff);
|
||||||
|
|
||||||
localisation.get_msg_ctx("hud-chat-died_of_pvp_buff_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-died_of_pvp_buff_msg", &i18n::fluent_args! {
|
||||||
"victim" => name_format(victim),
|
"victim" => name_format(victim),
|
||||||
"died_of_buff" => buff,
|
"died_of_buff" => buff,
|
||||||
"attacker" => name_format(attacker),
|
"attacker" => name_format(attacker),
|
||||||
@ -165,9 +145,9 @@ pub fn localize_chat_message(
|
|||||||
},
|
},
|
||||||
KillSource::NonPlayer(attacker_name, KillType::Buff(buff_kind)) => {
|
KillSource::NonPlayer(attacker_name, KillType::Buff(buff_kind)) => {
|
||||||
let i18n_buff = i18n_buff(*buff_kind);
|
let i18n_buff = i18n_buff(*buff_kind);
|
||||||
let buff = localisation.get_msg(i18n_buff);
|
let buff = localization.get_msg(i18n_buff);
|
||||||
|
|
||||||
localisation.get_msg_ctx("hud-chat-died_of_npc_buff_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-died_of_npc_buff_msg", &i18n::fluent_args! {
|
||||||
"victim" => name_format(victim),
|
"victim" => name_format(victim),
|
||||||
"died_of_buff" => buff,
|
"died_of_buff" => buff,
|
||||||
"attacker" => attacker_name,
|
"attacker" => attacker_name,
|
||||||
@ -175,9 +155,9 @@ pub fn localize_chat_message(
|
|||||||
},
|
},
|
||||||
KillSource::NonExistent(KillType::Buff(buff_kind)) => {
|
KillSource::NonExistent(KillType::Buff(buff_kind)) => {
|
||||||
let i18n_buff = i18n_buff(*buff_kind);
|
let i18n_buff = i18n_buff(*buff_kind);
|
||||||
let buff = localisation.get_msg(i18n_buff);
|
let buff = localization.get_msg(i18n_buff);
|
||||||
|
|
||||||
localisation.get_msg_ctx(
|
localization.get_msg_ctx(
|
||||||
"hud-chat-died_of_buff_nonexistent_msg",
|
"hud-chat-died_of_buff_nonexistent_msg",
|
||||||
&i18n::fluent_args! {
|
&i18n::fluent_args! {
|
||||||
"victim" => name_format(victim),
|
"victim" => name_format(victim),
|
||||||
@ -195,7 +175,7 @@ pub fn localize_chat_message(
|
|||||||
KillType::Other => "hud-chat-pvp_other_kill_msg",
|
KillType::Other => "hud-chat-pvp_other_kill_msg",
|
||||||
&KillType::Buff(_) => unreachable!("handled above"),
|
&KillType::Buff(_) => unreachable!("handled above"),
|
||||||
};
|
};
|
||||||
localisation.get_msg_ctx(key, &i18n::fluent_args! {
|
localization.get_msg_ctx(key, &i18n::fluent_args! {
|
||||||
"victim" => name_format(victim),
|
"victim" => name_format(victim),
|
||||||
"attacker" => name_format(attacker),
|
"attacker" => name_format(attacker),
|
||||||
})
|
})
|
||||||
@ -210,30 +190,30 @@ pub fn localize_chat_message(
|
|||||||
KillType::Other => "hud-chat-npc_other_kill_msg",
|
KillType::Other => "hud-chat-npc_other_kill_msg",
|
||||||
&KillType::Buff(_) => unreachable!("handled above"),
|
&KillType::Buff(_) => unreachable!("handled above"),
|
||||||
};
|
};
|
||||||
localisation.get_msg_ctx(key, &i18n::fluent_args! {
|
localization.get_msg_ctx(key, &i18n::fluent_args! {
|
||||||
"victim" => name_format(victim),
|
"victim" => name_format(victim),
|
||||||
"attacker" => attacker_name,
|
"attacker" => attacker_name,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// Other deaths
|
// Other deaths
|
||||||
KillSource::Environment(environment) => {
|
KillSource::Environment(environment) => {
|
||||||
localisation.get_msg_ctx("hud-chat-environment_kill_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-environment_kill_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(victim),
|
"name" => name_format(victim),
|
||||||
"environment" => environment,
|
"environment" => environment,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
KillSource::FallDamage => {
|
KillSource::FallDamage => {
|
||||||
localisation.get_msg_ctx("hud-chat-fall_kill_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-fall_kill_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(victim),
|
"name" => name_format(victim),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
KillSource::Suicide => {
|
KillSource::Suicide => {
|
||||||
localisation.get_msg_ctx("hud-chat-suicide_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-suicide_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(victim),
|
"name" => name_format(victim),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
KillSource::NonExistent(_) | KillSource::Other => {
|
KillSource::NonExistent(_) | KillSource::Other => {
|
||||||
localisation.get_msg_ctx("hud-chat-default_death_msg", &i18n::fluent_args! {
|
localization.get_msg_ctx("hud-chat-default_death_msg", &i18n::fluent_args! {
|
||||||
"name" => name_format(victim),
|
"name" => name_format(victim),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -245,14 +225,14 @@ pub fn localize_chat_message(
|
|||||||
(msg.chat_type, new_msg)
|
(msg.chat_type, new_msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_alias(you: bool, info: PlayerInfo, localisation: &Localization) -> String {
|
fn insert_alias(you: bool, info: PlayerInfo, localization: &Localization) -> String {
|
||||||
const YOU: &str = "hud-chat-you";
|
const YOU: &str = "hud-chat-you";
|
||||||
// Leave space for a mod badge icon.
|
// Leave space for a mod badge icon.
|
||||||
const MOD_SPACING: &str = " ";
|
const MOD_SPACING: &str = " ";
|
||||||
match (info.is_moderator, you) {
|
match (info.is_moderator, you) {
|
||||||
(false, false) => info.player_alias,
|
(false, false) => info.player_alias,
|
||||||
(false, true) => localisation.get_msg(YOU).to_string(),
|
(false, true) => localization.get_msg(YOU).to_string(),
|
||||||
(true, false) => format!("{}{}", MOD_SPACING, info.player_alias),
|
(true, false) => format!("{}{}", MOD_SPACING, info.player_alias),
|
||||||
(true, true) => format!("{}{}", MOD_SPACING, &localisation.get_msg(YOU),),
|
(true, true) => format!("{}{}", MOD_SPACING, &localization.get_msg(YOU),),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ use conrod_core::{
|
|||||||
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
widget_ids, Color, Colorable, Positionable, Sizeable, Widget, WidgetCommon,
|
||||||
};
|
};
|
||||||
use i18n::Localization;
|
use i18n::Localization;
|
||||||
use i18n_helpers::make_localizer;
|
|
||||||
use keyboard_keynames::key_layout::KeyLayout;
|
use keyboard_keynames::key_layout::KeyLayout;
|
||||||
|
|
||||||
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
const MAX_BUBBLE_WIDTH: f64 = 250.0;
|
||||||
@ -535,7 +534,7 @@ impl<'a> Widget for Overhead<'a> {
|
|||||||
// Speech bubble
|
// Speech bubble
|
||||||
if let Some(bubble) = self.bubble {
|
if let Some(bubble) = self.bubble {
|
||||||
let dark_mode = self.settings.speech_bubble_dark_mode;
|
let dark_mode = self.settings.speech_bubble_dark_mode;
|
||||||
let bubble_contents: String = bubble.content().localize(make_localizer(self.i18n));
|
let bubble_contents: String = self.i18n.get_content(bubble.content());
|
||||||
let (text_color, shadow_color) = bubble_color(bubble, dark_mode);
|
let (text_color, shadow_color) = bubble_color(bubble, dark_mode);
|
||||||
let mut text = Text::new(&bubble_contents)
|
let mut text = Text::new(&bubble_contents)
|
||||||
.color(text_color)
|
.color(text_color)
|
||||||
|
Loading…
Reference in New Issue
Block a user