tiger_lib/data/
customloca.rs1use crate::block::Block;
2use crate::context::ScopeContext;
3use crate::data::localization::Language;
4use crate::db::{Db, DbKind};
5use crate::everything::Everything;
6use crate::game::GameFlags;
7use crate::item::{Item, ItemLoader};
8use crate::report::{ErrorKey, warn};
9use crate::scopes::Scopes;
10use crate::token::Token;
11use crate::tooltipped::Tooltipped;
12use crate::validate::validate_modifiers_with_base;
13use crate::validator::Validator;
14
15#[cfg(feature = "eu5")]
16const INVALID_LOC_HANDLING: &[&str] = &["return_empty", "fallback_to_next_entry", "return_loc_key"];
17
18#[derive(Clone, Debug)]
19pub struct CustomLocalization {}
20
21inventory::submit! {
22 ItemLoader::Normal(GameFlags::jomini(), Item::CustomLocalization, CustomLocalization::add)
23}
24
25impl CustomLocalization {
26 pub fn add(db: &mut Db, key: Token, block: Block) {
27 db.add(Item::CustomLocalization, key, block, Box::new(Self {}));
28 }
29}
30
31impl DbKind for CustomLocalization {
32 fn validate(&self, key: &Token, block: &Block, data: &Everything) {
33 let mut vd = Validator::new(block, data);
34
35 let mut sc;
36 if let Some(token) = vd.field_value("type") {
37 if token.is("all") {
38 sc = ScopeContext::new(Scopes::all(), token);
39 } else if let Some(scopes) = Scopes::from_snake_case(token.as_str()) {
40 sc = ScopeContext::new(scopes, token);
41 } else {
42 warn(ErrorKey::Scopes).msg("unknown scope type").loc(token).push();
43 sc = ScopeContext::new(Scopes::all(), token);
44 }
45 } else {
46 sc = ScopeContext::new(Scopes::all(), key);
47 }
48 sc.set_strict_scopes(false);
50 vd.field_bool("log_loc_errors");
51 vd.field_bool("random_valid");
52
53 #[cfg(feature = "eu5")]
54 vd.field_choice("if_invalid_loc", INVALID_LOC_HANDLING);
55
56 if block.has_key("parent") {
57 vd.field_item("parent", Item::CustomLocalization);
58 vd.req_field("suffix");
59 vd.field_value("suffix");
60 return;
62 }
63 vd.req_field("type");
64
65 vd.multi_field_validated_block("text", |block, data| {
66 let mut vd = Validator::new(block, data);
67 vd.field_effect("setup_scope", Tooltipped::No, &mut sc);
68 vd.field_trigger("trigger", Tooltipped::No, &mut sc);
69 vd.field_validated_block_sc("weight_multiplier", &mut sc, validate_modifiers_with_base);
70
71 vd.req_field("localization_key");
72 vd.field_value("localization_key");
74 vd.field_bool("fallback");
75 });
76 }
77}
78
79impl CustomLocalization {
80 #[allow(clippy::too_many_arguments)] pub fn validate_custom_call(
82 key: &Token,
83 block: &Block,
84 data: &Everything,
85 caller: &Token,
86 scopes: Scopes,
87 lang: Option<Language>,
88 suffix_str: &str,
89 suffix_token: Option<&Token>,
90 ) {
91 if let Some(token) = block.get_field_value("type")
92 && let Some(this_scopes) = Scopes::from_snake_case(token.as_str())
93 && !scopes.contains(this_scopes)
94 {
95 let msg =
96 format!("custom localization {key} is for {this_scopes} but context is {scopes}");
97 warn(ErrorKey::Scopes).msg(msg).loc(caller).push();
98 }
99
100 if let Some(parent) = block.get_field_value("parent") {
101 if let Some(suffix) = block.get_field_value("suffix")
102 && let Some((key, block)) =
103 data.get_key_block(Item::CustomLocalization, parent.as_str())
104 {
105 let suffix_str = format!("{suffix_str}{suffix}");
106 let suffix_token = if suffix_token.is_some() { suffix_token } else { Some(suffix) };
107 Self::validate_custom_call(
108 key,
109 block,
110 data,
111 caller,
112 scopes,
113 lang,
114 &suffix_str,
115 suffix_token,
116 );
117 }
118 } else {
119 for block in block.get_field_blocks("text") {
120 if let Some(key) = block.get_field_value("localization_key") {
121 if let Some(token) = suffix_token {
122 let loca = format!("{key}{suffix_str}");
123 data.localization.verify_exists_implied_lang(&loca, token, lang);
124 } else {
125 data.localization.verify_exists_lang(key, lang);
126 }
127 }
128 }
129 }
130 }
131}