diff --git a/.github/README.md b/.github/README.md index 96e2920..c002a68 100644 --- a/.github/README.md +++ b/.github/README.md @@ -39,25 +39,19 @@ To use localizer-rs, you need a directory (eg. `translations`) with your transla 1. Import the localizer-rs crate: ```rust,ignore - use localizer_rs; - ``` 2. Create a new config object: ```rust,ignore - - let config = localizer_rs::Config::new("DIRECTORY NAME", "LANGUAGE NAME"); - + let config = localizer_rs::Config::new("translations", "en"); ``` 3. Translate your text: ```rust,ignore - - config.t("key", vec!["placeholder", "value"]); - + localizer_rs::t!(config, "key", "placeholder" ="value"); ``` ## Example @@ -65,33 +59,27 @@ To use localizer-rs, you need a directory (eg. `translations`) with your transla With the following `en.json` file. ```json - { "error": "{{color.red}}{{bold}}Error:{{end}} Something went wrong: {{details}}." } - ``` And the following rust code. ```rust,ignore - use localizer_rs; fn main() { let config: localizer_rs::Config = localizer_rs::Config::new("translations", "en"); - println!("{:}", config.t("error", vec![("details", "Path not found")])); + println!("{:}", localizer_rs::t!(config, "error", "details" = "Path not found")); } - ``` You will get the following output: ```bash - Error: Something went wrong: Path not found. - ``` Where `Error:` is red and bold. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 24a8ba8..455f52c 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -7,6 +7,7 @@ | `v1.0.0` | :white_check_mark: | | `v1.1.0` | :white_check_mark: | | `v1.1.1` | :white_check_mark: | +| `v1.2.0` | :white_check_mark: | ## Reporting a Vulnerability diff --git a/.github/errors.md b/.github/errors.md new file mode 100644 index 0000000..f114728 --- /dev/null +++ b/.github/errors.md @@ -0,0 +1,3 @@ +# errors module + +Module for dealing with errors. diff --git a/.github/workflows/codecov_workflow.yml b/.github/workflows/codecov_workflow.yml index c646b88..4a813bb 100644 --- a/.github/workflows/codecov_workflow.yml +++ b/.github/workflows/codecov_workflow.yml @@ -6,6 +6,7 @@ on: jobs: build: + runs-on: ubuntu-latest steps: - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v3 diff --git a/Cargo.toml b/Cargo.toml index a7ab734..fec7e1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "localizer-rs" description = "Localizer helps localize (translate) your rust applications using json files." -version = "1.1.1" +version = "1.2.0" authors = [ "ElBe-Plaq " ] diff --git a/examples/main.rs b/examples/main.rs index d73732e..726394d 100644 --- a/examples/main.rs +++ b/examples/main.rs @@ -5,15 +5,16 @@ fn main() { println!( "{:}", - config.t( + localizer_rs::t!( + config, "error", - vec![("details", "Something went wrong when trying to do stuff")] + "details" = "Something went wrong when trying to do stuff" ) ); println!( "{:}", - config.t("success", vec![("balance", "$10"), ("user", "John Doe")]) + localizer_rs::t!(config, "success", "balance" = "$10", "user" = "John Doe") ); - println!("{:}", config.t("all", vec![])); + println!("{:}", localizer_rs::t!(config, "all")); } diff --git a/src/errors.rs b/src/errors.rs index df53342..1509aae 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,3 +1,4 @@ +#![doc = include_str!("../.github/errors.md")] // localizer-rs errors // Version: 1.1.1 @@ -66,7 +67,31 @@ pub struct Error { pub exit_code: i32, } +/// Display implementation for the error object. impl fmt::Display for Error { + /// Format implementation for the error object. + /// + /// # Parameters + /// + /// - `self`: The error object. + /// - `f`: The [`fmt::Formatter`] to use. + /// + /// # Returns + /// + /// A [`fmt::Result`] containing the formatted error message. + /// + /// # Examples + /// + /// ```rust + /// # use localizer_rs; + /// # let error = localizer_rs::errors::Error::new("name", "description", 1); + /// println!("{}", error); + /// ``` + /// + /// # See also + /// + /// - [`fmt::Display`] + /// - [`Error`] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\x1b[31;1m{}\x1b[0m: {}", self.name, self.description) } diff --git a/src/lib.rs b/src/lib.rs index 256e99d..cab7a50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![doc = include_str!("../.github/README.md")] // localizer-rs -// Version: 1.1.1 +// Version: 1.2.0 // Copyright (c) 2023-present ElBe Development. @@ -159,8 +159,7 @@ impl Config { } } Err(_error) => { - let error: errors::Error = - errors::Error::new("OS Error", "Could not open path", 2); + let error: errors::Error = errors::Error::new("OS Error", "Could not open path", 2); error.raise(format!("Path: {:?}\nDetails: {}", str_path, _error).as_str()); } } @@ -226,15 +225,49 @@ impl Config { /// /// # See also /// + /// - [`t!()`] /// - [`Config`] pub fn t(&self, key: &str, arguments: Vec<(&str, &str)>) -> String { - return self.translate::(key, arguments); + return self.translate(key, arguments); } - fn translate(&self, key: &str, mut arguments: Vec<(&str, &str)>) -> String - where - T: serde::Serialize + for<'de> serde::Deserialize<'de>, - { + /// Translates the specified key in the language specified in the config. + /// + /// # Parameters + /// + /// - `self`: The config object. + /// - `key`: The key to translate to. + /// - `arguments`: The arguments to replace. + /// + /// # Returns + /// + /// A `String` containing the translated value. + /// + /// # Raises + /// + /// This method throws an exception and exits if + /// + /// - The translation file could not be found + /// - The translation file could not be opened + /// - The translation file could not be parsed + /// - The parsed json could not be converted to a json value + /// - The converted json could not be indexed + /// + /// # Examples + /// + /// ```rust + /// # use localizer_rs; + /// # let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); + /// config.translate("test", vec![]); + /// ``` + /// + /// # See also + /// + /// - [`t!()`] + /// - [`Config`] + /// - [`Config::t()`] + /// - [`serde_json`] + pub fn translate(&self, key: &str, mut arguments: Vec<(&str, &str)>) -> String { let mut colors: Vec<(&str, &str)> = vec![ // Formatting codes ("end", "\x1b[0m"), @@ -305,8 +338,8 @@ impl Config { }; let reader: BufReader = BufReader::new(file); - let json: serde_json::Value = match serde_json::to_value::( - match serde_json::from_reader::, T>(reader) { + let json: serde_json::Value = match serde_json::to_value::( + match serde_json::from_reader::, serde_json::Value>(reader) { Ok(value) => value, Err(_error) => { let error: errors::Error = errors::Error::new( @@ -366,3 +399,50 @@ impl Config { return result; } } + + +/// Translates the specified key in the language specified in the config. +/// +/// # Parameters +/// +/// - `config`: The config object. +/// - `key`: The key to translate to. +/// - `arguments`: Optional parameter. The arguments to replace. Has to be of type `"name" = "value"`. +/// +/// # Returns +/// +/// A `String` containing the translated value. +/// +/// # Examples +/// +/// ```rust +/// # use localizer_rs; +/// # let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); +/// localizer_rs::t!(config, "test"); +/// localizer_rs::t!(config, "test", "variable" = "content"); +/// ``` +/// +/// # See also +/// +/// - [`Config`] +/// - [`Config::t()`] +#[macro_export] +macro_rules! t { + ($config:expr, $key:expr) => { + { + $config.t($key, vec![]) + } + }; + + ($config:expr, $key:expr, $($argument_name:literal = $argument_value:literal),* $(,)?) => { + { + let mut arguments: Vec<(&str, &str)> = vec![]; + + $( + arguments.push(($argument_name, $argument_value)); + )* + + $config.t($key, arguments) + } + }; +} diff --git a/tests/lib.rs b/tests/lib.rs index 6c21014..aca7820 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,5 +1,5 @@ // localizer-rs tests -// Version: 1.1.1 +// Version: 1.2.0 // Copyright (c) 2023-present ElBe Development. @@ -80,6 +80,18 @@ mod tests { #[test] fn test_translate() { + let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); + let translation: String = + config.translate("error", vec![("details", "Something went wrong")]); + + assert_eq!( + translation.as_str(), + "\x1b[31m\x1b[1mError:\x1b[0m Something went wrong" + ); + } + + #[test] + fn test_translate_t() { let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); let translation: String = config.t("error", vec![("details", "Something went wrong")]); @@ -88,4 +100,16 @@ mod tests { "\x1b[31m\x1b[1mError:\x1b[0m Something went wrong" ); } + + #[test] + fn test_translate_macro() { + let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); + let translation: String = + localizer_rs::t!(config, "error", "details" = "Something went wrong"); + + assert_eq!( + translation.as_str(), + "\x1b[31m\x1b[1mError:\x1b[0m Something went wrong" + ); + } }