Skip to main content

lingora_core/config/
args.rs

1use std::path::PathBuf;
2
3use clap::*;
4
5use crate::{
6    config::config_inclusion_style::ConfigInclusionStyle, domain::Locale, error::LingoraError,
7};
8
9/// Core command-line arguments shared between `lingora-cli` and `lingora-tui`.
10///
11/// These arguments represent settings that can be overridden when running
12/// `lingora-cli` and `lingora-tui` from the command line. They allow users to:
13///
14/// - Point to a specific configuration file (or otherwise rely on auto-discovery of `Lingora.toml`)
15/// - Supplement or override the translation files and locales defined by the configuration.
16/// - Enable Rust source scanning for `dioxus_i18n` macro usage
17/// - Control how generated `I18nConfig` code includes locales
18#[derive(Debug, Parser)]
19pub struct CoreArgs {
20    /// Config file.
21    /// The config file contains attributes, most of which can also be overridden
22    /// by command line arguments.
23    /// If no config file is provided and `Lingora.toml` exists in the current
24    /// working directory then that will be used. If `Lingora.toml` doesn't exist
25    /// then sensible defaults will be used.
26    #[clap(long, default_value = None)]
27    pub(crate) config: Option<PathBuf>,
28
29    /// Paths to translation files or folders containing translation files.
30    /// Files or folders provided here will be added to those defined in
31    /// the 'Lingora.toml' configuration file.
32    #[clap(long, value_delimiter = ',')]
33    pub(crate) fluent_sources: Vec<PathBuf>,
34
35    /// Canonical locale.
36    /// This is expected to be defined in the Lingora.toml file, but can be
37    /// overriddem here.
38    #[clap(long, default_value = None)]
39    pub(crate) canonical: Option<Locale>,
40
41    /// Primary locales for the translation.
42    /// Supported translations are expected to be defined in the Lingora.toml
43    /// file. Any primaries defined here will be included in the analysis in
44    /// addition to those in the Lingora.toml config file.
45    #[arg(long, value_delimiter = ',')]
46    pub(crate) primaries: Vec<Locale>,
47
48    /// The paths for rust source files that may use dioxus_i18n macros.
49    /// If provided Lingora will analyse the source files for usage of the
50    /// `dioxus_i18n::t!`, `te!` and `tid!` macros. If parsable (const str)
51    /// it check that the identifier exists in the reference file and produce
52    /// a warning if it is missing.
53    #[clap(long, value_delimiter = ',')]
54    pub(crate) rust_sources: Vec<PathBuf>,
55
56    /// Define which dioxus_i18n::I18nConfig with_locale method will be used
57    /// during rendering of the config.rs code.
58    #[clap(long, default_value = None)]
59    pub(crate) config_inclusion: Option<ConfigInclusionStyle>,
60}
61
62impl std::str::FromStr for CoreArgs {
63    type Err = LingoraError;
64
65    fn from_str(s: &str) -> Result<Self, Self::Err> {
66        let value = s.split_whitespace();
67        let args = CoreArgs::try_parse_from(value)?;
68        Ok(args)
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use std::str::FromStr;
75
76    use pretty_assertions::assert_eq;
77
78    use super::*;
79
80    #[test]
81    fn no_config_file_by_default() {
82        let args = CoreArgs::from_str("").unwrap();
83        assert_eq!(args.config, None);
84    }
85
86    #[test]
87    fn user_can_provide_config_file() {
88        let args = CoreArgs::from_str("app_name --config=tests/data/i18n/Lingora.toml").unwrap();
89        assert_eq!(
90            args.config,
91            Some(PathBuf::from("tests/data/i18n/Lingora.toml"))
92        );
93    }
94
95    #[test]
96    fn no_additional_fluent_sources_by_default() {
97        let args = CoreArgs::from_str("").unwrap();
98        assert!(args.fluent_sources.is_empty());
99    }
100
101    #[test]
102    fn user_can_provide_fluents_sources() {
103        let args = CoreArgs::from_str("app_name --fluent-sources=tests/data/i18n").unwrap();
104        assert_eq!(args.fluent_sources, [PathBuf::from("tests/data/i18n")]);
105    }
106
107    #[test]
108    fn no_canonical_locale_by_default() {
109        let args = CoreArgs::from_str("").unwrap();
110        assert_eq!(args.canonical, None);
111    }
112
113    #[test]
114    fn user_can_provide_canonical_locale() {
115        let args = CoreArgs::from_str("app_name --canonical=en-GB").unwrap();
116        assert_eq!(args.canonical, Locale::from_str("en-GB").ok());
117    }
118
119    #[test]
120    fn no_additional_primary_locales_by_default() {
121        let args = CoreArgs::from_str("").unwrap();
122        assert!(args.primaries.is_empty())
123    }
124
125    #[test]
126    fn user_can_provide_additional_primary_locale() {
127        let args = CoreArgs::from_str("app_name --primaries=it-IT").unwrap();
128        assert_eq!(args.primaries, [Locale::from_str("it-IT").unwrap()])
129    }
130
131    #[test]
132    fn user_can_provide_multiple_additional_primary_locales() {
133        let args = CoreArgs::from_str("app_name --primaries=en-GB,en-US,it-IT").unwrap();
134        assert_eq!(
135            args.primaries,
136            [
137                Locale::from_str("en-GB").unwrap(),
138                Locale::from_str("en-US").unwrap(),
139                Locale::from_str("it-IT").unwrap()
140            ]
141        )
142    }
143}