1use crate::config::{GetLang, Mode, LIB_CFG};
7use crate::error::LibCfgError;
8#[cfg(feature = "lang-detection")]
9use lingua;
10#[cfg(feature = "lang-detection")]
11use lingua::IsoCode639_1;
12use parking_lot::RwLock;
13use std::borrow::Cow;
14use std::collections::BTreeMap;
15use std::env;
16#[cfg(feature = "lang-detection")]
17use std::str::FromStr;
18#[cfg(target_family = "windows")]
19use windows_sys::Win32::Globalization::GetUserDefaultLocaleName;
20#[cfg(target_family = "windows")]
21use windows_sys::Win32::System::SystemServices::LOCALE_NAME_MAX_LENGTH;
22
23pub const ENV_VAR_TPNOTE_SCHEME: &str = "TPNOTE_SCHEME";
26
27pub const ENV_VAR_TPNOTE_EXTENSION_DEFAULT: &str = "TPNOTE_EXTENSION_DEFAULT";
30
31pub const ENV_VAR_TPNOTE_LANG: &str = "TPNOTE_LANG";
36
37pub const ENV_VAR_TPNOTE_LANG_PLUS_ALL: &str = "+all";
40
41pub const ENV_VAR_TPNOTE_LANG_DETECTION: &str = "TPNOTE_LANG_DETECTION";
45
46pub const ENV_VAR_TPNOTE_USER: &str = "TPNOTE_USER";
50
51const ENV_VAR_LOGNAME: &str = "LOGNAME";
53
54const ENV_VAR_USERNAME: &str = "USERNAME";
56
57const ENV_VAR_USER: &str = "USER";
59
60#[cfg(not(target_family = "windows"))]
62const ENV_VAR_LANG: &str = "LANG";
63
64#[derive(Debug)]
67#[allow(dead_code)]
68pub(crate) struct Settings {
69 pub current_scheme: usize,
71 pub author: String,
73 pub lang: String,
76 pub extension_default: String,
78 pub get_lang_filter: GetLang,
80 pub map_lang_filter_btmap: Option<BTreeMap<String, String>>,
84}
85
86const DEFAULT_SETTINGS: Settings = Settings {
87 current_scheme: 0,
88 author: String::new(),
89 lang: String::new(),
90 extension_default: String::new(),
91 get_lang_filter: GetLang {
92 mode: Mode::Disabled,
93 language_candidates: vec![],
94 relative_distance_min: 0.0,
95 consecutive_words_min: 0,
96 words_total_percentage_min: 0,
97 },
98 map_lang_filter_btmap: None,
99};
100
101impl Default for Settings {
102 #[cfg(not(any(test, doc)))]
103 fn default() -> Self {
105 DEFAULT_SETTINGS
106 }
107
108 #[cfg(any(test, doc))]
109 fn default() -> Self {
112 let mut settings = DEFAULT_SETTINGS;
113 settings.author = String::from("testuser");
114 settings.lang = String::from("ab-AB");
115 settings.extension_default = String::from("md");
116 settings
117 }
118}
119
120#[cfg(not(test))]
122pub(crate) static SETTINGS: RwLock<Settings> = RwLock::new(DEFAULT_SETTINGS);
123
124#[cfg(test)]
125pub(crate) static SETTINGS: RwLock<Settings> = RwLock::new(DEFAULT_SETTINGS);
127
128pub fn set_test_default_settings() -> Result<(), LibCfgError> {
132 let mut settings = SETTINGS.write();
133 settings.update(SchemeSource::Force("default"), None)
134}
135
136#[derive(Debug, Clone)]
138pub(crate) enum SchemeSource<'a> {
139 Force(&'a str),
141 SchemeSyncDefault,
143 SchemeNewDefault(&'a str),
145}
146
147impl Settings {
148 pub(crate) fn update(
164 &mut self,
165 scheme_source: SchemeSource,
166 force_lang: Option<&str>,
167 ) -> Result<(), LibCfgError> {
168 self.update_current_scheme(scheme_source)?;
169 self.update_author();
170 self.update_extension_default();
171 self.update_lang(force_lang);
172 self.update_get_lang_filter(force_lang.is_some());
173 self.update_map_lang_filter_btmap();
174 self.update_env_lang_detection(force_lang.is_some());
175
176 log::trace!(
177 "`SETTINGS` updated (reading config + env. vars.):\n{:#?}",
178 self
179 );
180
181 if let Mode::Error(e) = &self.get_lang_filter.mode {
182 Err(e.clone())
183 } else {
184 Ok(())
185 }
186 }
187
188 fn update_current_scheme(&mut self, scheme_source: SchemeSource) -> Result<(), LibCfgError> {
190 let lib_cfg = LIB_CFG.read_recursive();
191
192 let scheme = match scheme_source {
193 SchemeSource::Force(s) => Cow::Borrowed(s),
194 SchemeSource::SchemeSyncDefault => Cow::Borrowed(&*lib_cfg.scheme_sync_default),
195 SchemeSource::SchemeNewDefault(s) => match env::var(ENV_VAR_TPNOTE_SCHEME) {
196 Ok(ed_env) if !ed_env.is_empty() => Cow::Owned(ed_env),
197 Err(_) | Ok(_) => Cow::Borrowed(s),
198 },
199 };
200 self.current_scheme = lib_cfg.scheme_idx(scheme.as_ref())?;
201 Ok(())
202 }
203
204 fn update_author(&mut self) {
207 let author = env::var(ENV_VAR_TPNOTE_USER).unwrap_or_else(|_| {
208 env::var(ENV_VAR_LOGNAME).unwrap_or_else(|_| {
209 env::var(ENV_VAR_USERNAME)
210 .unwrap_or_else(|_| env::var(ENV_VAR_USER).unwrap_or_default())
211 })
212 });
213
214 self.author = author;
216 }
217
218 fn update_extension_default(&mut self) {
222 let ext = match env::var(ENV_VAR_TPNOTE_EXTENSION_DEFAULT) {
224 Ok(ed_env) if !ed_env.is_empty() => ed_env,
225 Err(_) | Ok(_) => {
226 let lib_cfg = LIB_CFG.read_recursive();
227 lib_cfg.scheme[self.current_scheme]
228 .filename
229 .extension_default
230 .to_string()
231 }
232 };
233 self.extension_default = ext;
234 }
235
236 fn update_lang(&mut self, force_lang: Option<&str>) {
240 if let Some(l) = force_lang {
242 if !l.is_empty() {
243 self.lang = l.to_string();
244 return;
245 }
246 }
247
248 let mut lang = String::new();
251 let tpnotelang = env::var(ENV_VAR_TPNOTE_LANG).ok();
253 #[cfg(not(target_family = "windows"))]
255 if let Some(tpnotelang) = tpnotelang {
256 lang = tpnotelang;
257 } else {
258 if let Ok(lang_env) = env::var(ENV_VAR_LANG) {
261 if !lang_env.is_empty() {
262 let mut language = "";
264 let mut territory = "";
266 if let Some((l, lang_env)) = lang_env.split_once('_') {
267 language = l;
268 if let Some((t, _codeset)) = lang_env.split_once('.') {
269 territory = t;
270 }
271 }
272 lang = language.to_string();
273 lang.push('-');
274 lang.push_str(territory);
275 }
276 }
277 }
278
279 #[cfg(target_family = "windows")]
282 if let Some(tpnotelang) = tpnotelang {
283 lang = tpnotelang;
284 } else {
285 let mut buf = [0u16; LOCALE_NAME_MAX_LENGTH as usize];
286 let len = unsafe { GetUserDefaultLocaleName(buf.as_mut_ptr(), buf.len() as i32) };
287 if len > 0 {
288 lang = String::from_utf16_lossy(&buf[..((len - 1) as usize)]);
289 }
290 };
291
292 self.lang = lang;
294 }
295
296 #[cfg(feature = "lang-detection")]
305 fn update_get_lang_filter(&mut self, force_lang: bool) {
306 use crate::config::Mode;
307
308 {
309 let lib_cfg = LIB_CFG.read_recursive();
310 let current_scheme = &lib_cfg.scheme[self.current_scheme];
311
312 self.get_lang_filter = current_scheme.tmpl.filter.get_lang.clone();
314 } if force_lang {
318 self.get_lang_filter.mode = Mode::Disabled;
319 return;
320 }
321
322 if matches!(self.get_lang_filter.mode, Mode::Disabled) {
324 return;
325 }
326
327 let iso_codes = &mut self.get_lang_filter.language_candidates;
329
330 if iso_codes.is_empty() {
332 return;
333 }
334
335 if !self.lang.is_empty() {
338 if let Some((lang_subtag, _)) = self.lang.split_once('-') {
339 if let Ok(iso_code) = IsoCode639_1::from_str(lang_subtag) {
340 if !iso_codes.contains(&iso_code) {
341 iso_codes.push(iso_code);
342 }
343 }
344 }
345 }
346
347 if iso_codes.len() <= 1 {
349 self.get_lang_filter.mode = Mode::Error(LibCfgError::NotEnoughLanguageCodes {
350 language_code: iso_codes[0].to_string(),
351 })
352 }
353 }
354
355 #[cfg(not(feature = "lang-detection"))]
356 fn update_get_lang_filter(&mut self, _force_lang: bool) {
358 self.get_lang_filter.mode = Mode::Disabled;
359 }
360
361 fn update_map_lang_filter_btmap(&mut self) {
365 let mut btm = BTreeMap::new();
366 let lib_cfg = LIB_CFG.read_recursive();
367 for l in &lib_cfg.scheme[self.current_scheme].tmpl.filter.map_lang {
368 if l.len() >= 2 {
369 btm.insert(l[0].to_string(), l[1].to_string());
370 };
371 }
372 if !self.lang.is_empty() {
374 if let Some((lang_subtag, _)) = self.lang.split_once('-') {
375 if !lang_subtag.is_empty() && !btm.contains_key(lang_subtag) {
377 btm.insert(lang_subtag.to_string(), self.lang.to_string());
378 }
379 };
380 }
381
382 self.map_lang_filter_btmap = Some(btm);
384 }
385
386 #[cfg(feature = "lang-detection")]
392 fn update_env_lang_detection(&mut self, force_lang: bool) {
393 use crate::config::Mode;
394
395 if let Ok(env_var) = env::var(ENV_VAR_TPNOTE_LANG_DETECTION) {
396 if env_var.is_empty() {
397 self.get_lang_filter.mode = Mode::Disabled;
399 self.map_lang_filter_btmap = None;
400 log::debug!(
401 "Empty env. var. `{}` disables the `lang-detection` feature.",
402 ENV_VAR_TPNOTE_LANG_DETECTION
403 );
404 return;
405 }
406
407 let mut hm: BTreeMap<String, String> = BTreeMap::new();
409 let mut all_languages_selected = false;
410 let iso_codes = env_var
411 .split(',')
412 .map(|t| {
413 let t = t.trim();
414 if let Some((lang_subtag, _)) = t.split_once('-') {
415 if !lang_subtag.is_empty() && !hm.contains_key(lang_subtag) {
417 hm.insert(lang_subtag.to_string(), t.to_string());
418 };
419 lang_subtag
420 } else {
421 t
422 }
423 })
424 .filter(|&l| {
426 if l == ENV_VAR_TPNOTE_LANG_PLUS_ALL {
427 all_languages_selected = true;
428 false
430 } else {
431 true
433 }
434 })
435 .map(|l| {
436 IsoCode639_1::from_str(l.trim()).map_err(|_| {
437 let mut all_langs = lingua::Language::all()
440 .iter()
441 .map(|l| {
442 let mut s = l.iso_code_639_1().to_string();
443 s.push_str(", ");
444 s
445 })
446 .collect::<Vec<String>>();
447 all_langs.sort();
448 let mut all_langs = all_langs.into_iter().collect::<String>();
449 all_langs.truncate(all_langs.len() - ", ".len());
450 LibCfgError::ParseLanguageCode {
452 language_code: l.into(),
453 all_langs,
454 }
455 })
456 })
457 .collect::<Result<Vec<IsoCode639_1>, LibCfgError>>();
458
459 match iso_codes {
460 Ok(mut iso_codes) => {
462 if !self.lang.is_empty() {
465 if let Some(lang_subtag) = self.lang.split('-').next() {
466 if let Ok(iso_code) = IsoCode639_1::from_str(lang_subtag) {
467 if !iso_codes.contains(&iso_code) {
468 iso_codes.push(iso_code);
469 }
470 if lang_subtag != self.lang && !hm.contains_key(lang_subtag) {
472 hm.insert(lang_subtag.to_string(), self.lang.to_string());
473 }
474 }
475 }
476 }
477
478 if all_languages_selected {
480 self.get_lang_filter.language_candidates = vec![];
481 if matches!(self.get_lang_filter.mode, Mode::Disabled) {
482 self.get_lang_filter.mode = Mode::Multilingual;
483 }
484 } else {
485 match iso_codes.len() {
486 0 => self.get_lang_filter.mode = Mode::Disabled,
487 1 => {
488 self.get_lang_filter.mode =
489 Mode::Error(LibCfgError::NotEnoughLanguageCodes {
490 language_code: iso_codes[0].to_string(),
491 })
492 }
493 _ => {
494 self.get_lang_filter.language_candidates = iso_codes;
495 if matches!(self.get_lang_filter.mode, Mode::Disabled) {
496 self.get_lang_filter.mode = Mode::Multilingual;
497 }
498 }
499 }
500 }
501 self.map_lang_filter_btmap = Some(hm);
502 }
503 Err(e) =>
505 {
507 self.get_lang_filter.mode = Mode::Error(e);
508 }
509 }
510
511 if force_lang {
514 self.get_lang_filter.mode = Mode::Disabled;
515 }
516 }
517 }
518
519 #[cfg(not(feature = "lang-detection"))]
521 fn update_env_lang_detection(&mut self, _force_lang: bool) {
522 if let Ok(env_var) = env::var(ENV_VAR_TPNOTE_LANG_DETECTION) {
523 if !env_var.is_empty() {
524 self.get_lang_filter.mode = Mode::Disabled;
525 self.map_lang_filter_btmap = None;
526 log::debug!(
527 "Ignoring the env. var. `{}`. The `lang-detection` feature \
528 is not included in this build.",
529 ENV_VAR_TPNOTE_LANG_DETECTION
530 );
531 }
532 }
533 }
534}
535#[cfg(test)]
536mod tests {
537 use super::*;
538 #[test]
542 fn test_update_author_setting() {
543 let mut settings = Settings::default();
544 unsafe {
545 env::set_var(ENV_VAR_LOGNAME, "testauthor");
546 }
547 settings.update_author();
548 assert_eq!(settings.author, "testauthor");
549 }
550
551 #[test]
552 fn test_update_extension_default_setting() {
553 let mut settings = Settings::default();
554 unsafe {
555 env::set_var(ENV_VAR_TPNOTE_EXTENSION_DEFAULT, "markdown");
556 }
557 settings.update_extension_default();
558 assert_eq!(settings.extension_default, "markdown");
559
560 let mut settings = Settings::default();
561 unsafe {
562 std::env::remove_var(ENV_VAR_TPNOTE_EXTENSION_DEFAULT);
563 }
564 settings.update_extension_default();
565 assert_eq!(settings.extension_default, "md");
566 }
567
568 #[test]
569 #[cfg(not(target_family = "windows"))]
570 fn test_update_lang_setting() {
571 let mut settings = Settings::default();
573 unsafe {
574 env::remove_var(ENV_VAR_TPNOTE_LANG);
575 env::set_var(ENV_VAR_LANG, "en_GB.UTF-8");
576 }
577 settings.update_lang(None);
578 assert_eq!(settings.lang, "en-GB");
579
580 let mut settings = Settings::default();
582 unsafe {
583 env::remove_var(ENV_VAR_TPNOTE_LANG);
584 env::set_var(ENV_VAR_LANG, "");
585 }
586 settings.update_lang(None);
587 assert_eq!(settings.lang, "");
588
589 let mut settings = Settings::default();
591 unsafe {
592 env::set_var(ENV_VAR_TPNOTE_LANG, "it-IT");
593 env::set_var(ENV_VAR_LANG, "en_GB.UTF-8");
594 }
595 settings.update_lang(None);
596 assert_eq!(settings.lang, "it-IT");
597 }
598
599 #[test]
600 #[cfg(feature = "lang-detection")]
601 fn test_update_get_lang_filter_setting() {
602 let mut settings = Settings {
604 lang: "en-GB".to_string(),
605 ..Default::default()
606 };
607 settings.update_get_lang_filter(false);
608
609 let output_get_lang_filter = settings
610 .get_lang_filter
611 .language_candidates
612 .iter()
613 .map(|l| {
614 let mut l = l.to_string();
615 l.push(' ');
616 l
617 })
618 .collect::<String>();
619 assert_eq!(output_get_lang_filter, "en fr de ");
620
621 let mut settings = Settings {
624 lang: "it-IT".to_string(),
625 ..Default::default()
626 };
627 settings.update_get_lang_filter(false);
628
629 let output_get_lang_filter = settings
630 .get_lang_filter
631 .language_candidates
632 .iter()
633 .map(|l| {
634 let mut l = l.to_string();
635 l.push(' ');
636 l
637 })
638 .collect::<String>();
639 assert_eq!(output_get_lang_filter, "en fr de it ");
640 }
641
642 #[test]
643 fn test_update_map_lang_filter_hmap_setting() {
644 let mut settings = Settings {
646 lang: "it-IT".to_string(),
647 ..Default::default()
648 };
649 settings.update_map_lang_filter_btmap();
650
651 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
652
653 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
654 assert_eq!(output_map_lang_filter.get("et").unwrap(), "et-ET");
655 assert_eq!(output_map_lang_filter.get("it").unwrap(), "it-IT");
656
657 let mut settings = Settings {
660 lang: "it".to_string(),
661 ..Default::default()
662 };
663 settings.update_map_lang_filter_btmap();
664
665 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
666
667 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
668 assert_eq!(output_map_lang_filter.get("et").unwrap(), "et-ET");
669 assert_eq!(output_map_lang_filter.get("it"), None);
670 }
671
672 #[test]
673 #[cfg(feature = "lang-detection")]
674 fn test_update_env_lang_detection() {
675 let mut settings = Settings {
678 lang: "en-GB".to_string(),
679 ..Default::default()
680 };
681 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "fr-FR, de-DE, hu") };
682 settings.update_env_lang_detection(false);
683
684 let output_get_lang_filter = settings
685 .get_lang_filter
686 .language_candidates
687 .iter()
688 .map(|l| {
689 let mut l = l.to_string();
690 l.push(' ');
691 l
692 })
693 .collect::<String>();
694 assert_eq!(output_get_lang_filter, "fr de hu en ");
695
696 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
697 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
698 assert_eq!(output_map_lang_filter.get("fr").unwrap(), "fr-FR");
699 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-GB");
700
701 let mut settings = Settings {
704 lang: "en-GB".to_string(),
705 ..Default::default()
706 };
707 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "de-DE, de-AT, en-US") };
708 settings.update_env_lang_detection(false);
709
710 let output_get_lang_filter = settings
711 .get_lang_filter
712 .language_candidates
713 .iter()
714 .map(|l| {
715 let mut l = l.to_string();
716 l.push(' ');
717 l
718 })
719 .collect::<String>();
720 assert_eq!(output_get_lang_filter, "de de en ");
721
722 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
723 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
724 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-US");
725
726 let mut settings = Settings {
729 lang: "en-GB".to_string(),
730 ..Default::default()
731 };
732 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "de-DE, +all, en-US") };
733 settings.update_env_lang_detection(false);
734
735 assert!(settings.get_lang_filter.language_candidates.is_empty());
736
737 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
738 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
739 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-US");
740
741 let mut settings = Settings {
744 lang: "en-GB".to_string(),
745 ..Default::default()
746 };
747 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "de-DE, de-AT, en") };
748 settings.update_env_lang_detection(false);
749
750 let output_get_lang_filter = settings
751 .get_lang_filter
752 .language_candidates
753 .iter()
754 .map(|l| {
755 let mut l = l.to_string();
756 l.push(' ');
757 l
758 })
759 .collect::<String>();
760 assert_eq!(output_get_lang_filter, "de de en ");
761
762 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
763 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
764 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-GB");
765
766 let mut settings = Settings {
769 lang: "en-GB".to_string(),
770 ..Default::default()
771 };
772 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "de-DE, +all, de-AT, en") };
773 settings.update_env_lang_detection(false);
774
775 assert!(settings.get_lang_filter.language_candidates.is_empty());
776
777 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
778 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
779 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-GB");
780
781 let mut settings = Settings {
783 lang: "en-GB".to_string(),
784 ..Default::default()
785 };
786 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "fr-FR, de-DE, hu") };
787 settings.update_env_lang_detection(true);
788
789 assert_eq!(settings.get_lang_filter.mode, Mode::Disabled);
791
792 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
793 assert_eq!(output_map_lang_filter.get("de").unwrap(), "de-DE");
794 assert_eq!(output_map_lang_filter.get("fr").unwrap(), "fr-FR");
795 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-GB");
796
797 let mut settings = Settings {
800 lang: "".to_string(),
801 ..Default::default()
802 };
803 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "") };
804 settings.update_env_lang_detection(false);
805
806 assert_eq!(settings.get_lang_filter.mode, Mode::Disabled);
807 assert!(settings.map_lang_filter_btmap.is_none());
808
809 let mut settings = Settings {
812 lang: "xy-XY".to_string(),
813 ..Default::default()
814 };
815 unsafe { env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "en-GB, fr") };
816 settings.update_env_lang_detection(false);
817
818 let output_get_lang_filter = settings
819 .get_lang_filter
820 .language_candidates
821 .iter()
822 .map(|l| {
823 let mut l = l.to_string();
824 l.push(' ');
825 l
826 })
827 .collect::<String>();
828 assert_eq!(output_get_lang_filter, "en fr ");
829
830 let output_map_lang_filter = settings.map_lang_filter_btmap.unwrap();
831 assert_eq!(output_map_lang_filter.get("en").unwrap(), "en-GB");
832
833 let mut settings = Settings {
836 lang: "en-GB".to_string(),
837 ..Default::default()
838 };
839 unsafe {
840 env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "de-DE, xy-XY");
841 }
842 settings.update_env_lang_detection(false);
843
844 assert!(matches!(settings.get_lang_filter.mode, Mode::Error(..)));
845 assert!(settings.map_lang_filter_btmap.is_none());
846 let mut settings = Settings {
849 lang: "en-GB".to_string(),
850 ..Default::default()
851 };
852 unsafe {
853 env::set_var(ENV_VAR_TPNOTE_LANG_DETECTION, "");
854 }
855 settings.update_env_lang_detection(false);
856
857 assert!(matches!(settings.get_lang_filter.mode, Mode::Disabled));
858 assert!(settings.map_lang_filter_btmap.is_none());
859 }
860}