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 if let Some(this_scopes) = Scopes::from_snake_case(token.as_str()) {
93 if !scopes.contains(this_scopes) {
94 let msg = format!(
95 "custom localization {key} is for {this_scopes} but context is {scopes}"
96 );
97 warn(ErrorKey::Scopes).msg(msg).loc(caller).push();
98 }
99 }
100 }
101
102 if let Some(parent) = block.get_field_value("parent") {
103 if let Some(suffix) = block.get_field_value("suffix") {
104 if let Some((key, block)) =
105 data.get_key_block(Item::CustomLocalization, parent.as_str())
106 {
107 let suffix_str = format!("{suffix_str}{suffix}");
108 let suffix_token =
109 if suffix_token.is_some() { suffix_token } else { Some(suffix) };
110 Self::validate_custom_call(
111 key,
112 block,
113 data,
114 caller,
115 scopes,
116 lang,
117 &suffix_str,
118 suffix_token,
119 );
120 }
121 }
122 } else {
123 for block in block.get_field_blocks("text") {
124 if let Some(key) = block.get_field_value("localization_key") {
125 if let Some(token) = suffix_token {
126 let loca = format!("{key}{suffix_str}");
127 data.localization.verify_exists_implied_lang(&loca, token, lang);
128 } else {
129 data.localization.verify_exists_lang(key, lang);
130 }
131 }
132 }
133 }
134 }
135}