Compare commits

..

No commits in common. "main" and "v1.0.0" have entirely different histories.
main ... v1.0.0

18 changed files with 143 additions and 633 deletions

View File

@ -22,7 +22,7 @@ and a pull request. See below for making changes on your own.
1. Create a new issue with a summary of your proposed changes and more. 1. Create a new issue with a summary of your proposed changes and more.
2. Fork the repository. 2. Fork the repository.
3. Implement your changes 3. Implement your changes
4. Test your changes. Run `cargo fmt`, `cargo check` and `cargo clippy` to verify it works. 4. Test your changes. Run `cargo fmt`, `cargo check` ad `cargo clippy` to verify it works.
5. Create a pull request from your fork. 5. Create a pull request from your fork.
6. If it gets accepted, your changes will be in the next release. 6. If it gets accepted, your changes will be in the next release.

28
.github/README.md vendored
View File

@ -5,7 +5,7 @@
Localizer helps localize (translate) your rust applications using json files. Localizer helps localize (translate) your rust applications using json files.
</h3> </h3>
<p align="center"> <p align="center">
<img src="https://img.shields.io/crates/v/localizer-rs"> <img src="https://img.shields.io/crates/v/qstash-rs">
<img src="https://www.codefactor.io/repository/github/ElBe-Development/localizer-rs/badge"> <img src="https://www.codefactor.io/repository/github/ElBe-Development/localizer-rs/badge">
<img src="https://github.com/ElBe-Development/localizer-rs/actions/workflows/megalinter.yml/badge.svg?branch=main&event=push"> <img src="https://github.com/ElBe-Development/localizer-rs/actions/workflows/megalinter.yml/badge.svg?branch=main&event=push">
<img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit"> <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit">
@ -38,20 +38,26 @@ To use localizer-rs, you need a directory (eg. `translations`) with your transla
1. Import the localizer-rs crate: 1. Import the localizer-rs crate:
```rust,ignore ```rust
use localizer_rs; use localizer_rs;
``` ```
2. Create a new config object: 2. Create a new config object:
```rust,ignore ```rust
let config = localizer_rs::Config::new("translations", "en");
let config = localizer_rs::Config::new("DIRECTORY NAME", "LANGUAGE NAME");
``` ```
3. Translate your text: 3. Translate your text:
```rust,ignore ```rust
localizer_rs::t!(config, "key", "placeholder" ="value");
config.t("key", vec!["placeholder", "value"]);
``` ```
## Example ## Example
@ -59,27 +65,33 @@ To use localizer-rs, you need a directory (eg. `translations`) with your transla
With the following `en.json` file. With the following `en.json` file.
```json ```json
{ {
"error": "{{color.red}}{{bold}}Error:{{end}} Something went wrong: {{details}}." "error": "{{color.red}}{{bold}}Error:{{end}} Something went wrong: {{details}}."
} }
``` ```
And the following rust code. And the following rust code.
```rust,ignore ```rust
use localizer_rs; use localizer_rs;
fn main() { fn main() {
let config: localizer_rs::Config = localizer_rs::Config::new("translations", "en"); let config: localizer_rs::Config = localizer_rs::Config::new("translations", "en");
println!("{:}", localizer_rs::t!(config, "error", "details" = "Path not found")); println!("{:}", config.t("error", vec![("details", "Path not found")]));
} }
``` ```
You will get the following output: You will get the following output:
```bash ```bash
Error: Something went wrong: Path not found. Error: Something went wrong: Path not found.
``` ```
Where `Error:` is red and bold. Where `Error:` is red and bold.

3
.github/SECURITY.md vendored
View File

@ -5,9 +5,6 @@
| Version | Supported | | Version | Supported |
| -------- | ------------------ | | -------- | ------------------ |
| `v1.0.0` | :white_check_mark: | | `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 ## Reporting a Vulnerability

3
.github/errors.md vendored
View File

@ -1,3 +0,0 @@
# errors module
Module for dealing with errors.

View File

@ -1,14 +0,0 @@
name: Codecov
permissions: read-all
on:
[push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@ -16,9 +16,9 @@ jobs:
matrix: matrix:
python-version: ["3.8"] python-version: ["3.8"]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5 uses: actions/setup-python@v4
with: with:
python-version: ${{ matrix.python-version }} python-version: ${{ matrix.python-version }}
- name: Install dependencies from txt files - name: Install dependencies from txt files
@ -28,7 +28,7 @@ jobs:
install-rust-dependencies: install-rust-dependencies:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Install dependencies from Cargo.toml - name: Install dependencies from Cargo.toml
run: cargo update run: cargo update
- name: Install dev-dependencies from Cargo.toml - name: Install dev-dependencies from Cargo.toml
@ -39,8 +39,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repository - name: Checkout Repository
uses: actions/checkout@v4 uses: actions/checkout@v3
if: ${{ github.event_name != 'push' }} if: ${{ github.event_name != 'push' }}
- name: Dependency Review - name: Dependency Review
if: ${{ github.event_name != 'push' }} if: ${{ github.event_name != 'push' }}
uses: actions/dependency-review-action@v4 uses: actions/dependency-review-action@v3

View File

@ -20,6 +20,6 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/labeler@v5 - uses: actions/labeler@v4
with: with:
repo-token: "${{ secrets.GITHUB_TOKEN }}" repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -26,7 +26,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Checkout Code - name: Checkout Code
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }} token: ${{ secrets.PAT || secrets.GITHUB_TOKEN }}
fetch-depth: 0 fetch-depth: 0

View File

@ -11,7 +11,7 @@ jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v3
- name: Build - name: Build
run: cargo build --verbose run: cargo build --verbose
- name: Run tests - name: Run tests

View File

@ -1,7 +1,7 @@
[package] [package]
name = "localizer-rs" name = "localizer-rs"
description = "Localizer helps localize (translate) your rust applications using json files." description = "Localizer helps localize (translate) your rust applications using json files."
version = "1.2.0" version = "1.0.0"
authors = [ authors = [
"ElBe-Plaq <elbe.dev.plaq@gmail.com>" "ElBe-Plaq <elbe.dev.plaq@gmail.com>"
] ]
@ -10,7 +10,7 @@ rust-version = "1.69"
documentation = "https://docs.rs/localizer_rs/" documentation = "https://docs.rs/localizer_rs/"
readme = ".github/README.md" readme = ".github/README.md"
repository = "https://github.com/ElBe-Development/localizer-rs/" repository = "https://github.com/ElBe-Development/localizer-rs/"
license = "MIT" license-file = "LICENSE.txt"
keywords = ["i18n", "L10n", "json", "local", "translation"] keywords = ["i18n", "L10n", "json", "local", "translation"]
categories = [ categories = [
"internationalization", "internationalization",
@ -20,4 +20,4 @@ publish = true
[dependencies] [dependencies]
serde = "1.0.188" serde = "1.0.188"
serde_json = "1.0.107" serde_json = "1.0.106"

View File

@ -1,10 +0,0 @@
coverage:
status:
project:
default:
target: 50%
threshold: 1%
comment:
require_changes: true
require_ci_to_pass: false

View File

@ -1 +1 @@
pre-commit==4.1.0; python_version>='3.8' pre-commit==3.3.2; python_version>='3.8'

View File

@ -3,18 +3,8 @@ use localizer_rs;
fn main() { fn main() {
let config: localizer_rs::Config = localizer_rs::Config::new("translations", "en"); let config: localizer_rs::Config = localizer_rs::Config::new("translations", "en");
println!( println!("{:}", config.t("error", vec![("details", "Something went wrong when trying to do stuff")]));
"{:}", println!("{:}", config.t("success", vec![("balance", "$10"), ("user", "John Doe")]));
localizer_rs::t!(
config,
"error",
"details" = "Something went wrong when trying to do stuff"
)
);
println!(
"{:}",
localizer_rs::t!(config, "success", "balance" = "$10", "user" = "John Doe")
);
println!("{:}", localizer_rs::t!(config, "all")); println!("{:}", config.t("all", vec![]));
} }

View File

@ -10,7 +10,8 @@ build *ARGUMENTS:
# Removes temporary files # Removes temporary files
clean: clean:
cargo clean rm -rf target
rm -rf Tools/__pycache__
# Lints the rust source files # Lints the rust source files
lint *ARGUMENTS: lint *ARGUMENTS:

View File

@ -1,159 +0,0 @@
#![doc = include_str!("../.github/errors.md")]
// localizer-rs errors
// Version: 1.1.1
// Copyright (c) 2023-present ElBe Development.
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the 'Software'),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
////////////////////////////////
// IMPORTS AND USE STATEMENTS //
////////////////////////////////
use std::fmt;
///////////
// ERROR //
///////////
/// Error object.
///
/// Use [`Error::new()`] to create error objects instead of using this struct.
///
/// # Parameters
///
/// - `name`: The errors name.
/// - `description`: The error description.
/// - `exit_code`: The errors exit code.
///
/// # Returns
///
/// A new `Error` object with the specified name and description.
///
/// # Examples
///
/// ```rust
/// # use localizer_rs;
/// localizer_rs::errors::Error {
/// name: "name".to_owned(),
/// description: "description".to_owned(),
/// exit_code: 1
/// };
/// ```
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Error {
/// The errors name.
pub name: String,
/// The error description.
pub description: String,
/// The errors exit code.
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)
}
}
impl Error {
/// Creates a new error object.
///
/// # Parameters
///
/// - `name`: The errors name.
/// - `description`: The error description.
/// - `exit_code`: The errors exit code.
///
/// # Returns
///
/// A new `Error` object with the specified name and description.
///
/// # Examples
///
/// ```rust
/// # use localizer_rs;
/// localizer_rs::errors::Error::new("name", "description", 1);
/// ```
///
/// # See also
///
/// - [`Error`]
pub fn new(name: &str, description: &str, exit_code: i32) -> Error {
return Error {
name: name.to_owned(),
description: description.to_owned(),
exit_code: exit_code,
};
}
/// Raises the error and exits with the specified exit code.
///
/// # Parameters
///
/// - `self`: The error object.
/// - `details`: The error details.
///
/// # Aborts
///
/// Exits with the specified exit code.
///
/// # Examples
///
/// ```should_panic
/// # use localizer_rs;
/// # let error: localizer_rs::errors::Error = localizer_rs::errors::Error::new("name", "description", 1);
/// error.raise("Something went very wrong");
/// ```
///
/// # See also
///
/// - [`Error`]
pub fn raise(&self, details: &str) {
eprintln!("{}", self);
eprintln!("{}", details);
std::process::exit(self.exit_code);
}
}

View File

@ -1,6 +1,5 @@
#![doc = include_str!("../.github/README.md")]
// localizer-rs // localizer-rs
// Version: 1.2.0 // Version: 1.0.0
// Copyright (c) 2023-present ElBe Development. // Copyright (c) 2023-present ElBe Development.
@ -22,13 +21,6 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
/////////////
// EXPORTS //
/////////////
pub mod errors;
//////////////////////////////// ////////////////////////////////
// IMPORTS AND USE STATEMENTS // // IMPORTS AND USE STATEMENTS //
//////////////////////////////// ////////////////////////////////
@ -36,6 +28,7 @@ pub mod errors;
use std::fs::File; use std::fs::File;
use std::io::BufReader; use std::io::BufReader;
use std::path::Path; use std::path::Path;
use std::process::exit;
use serde_json; use serde_json;
@ -50,8 +43,7 @@ use serde_json;
/// ///
/// # Parameters /// # Parameters
/// ///
/// - `path`: The directory containing the translation files. /// - `path`: The directory containing the translation files. The directory is relative to the path the executable was executed from.
/// The directory is relative to the path the executable was executed from.
/// - `language`: The language to translate to. /// - `language`: The language to translate to.
/// ///
/// # Returns /// # Returns
@ -69,11 +61,8 @@ use serde_json;
/// ``` /// ```
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Config { pub struct Config {
/// The directory containing the translation files. The directory is relative to the path the
/// executable was executed from.
pub path: String, pub path: String,
/// The language to translate to. pub language: String
pub language: String,
} }
@ -86,8 +75,7 @@ impl Config {
/// ///
/// # Parameters /// # Parameters
/// ///
/// - `path`: The directory containing the translation files. /// - `path`: The directory containing the translation files. The directory is relative to the path the executable was executed from.
/// The directory is relative to the path the executable was executed from.
/// - `language`: The language to translate to. /// - `language`: The language to translate to.
/// ///
/// # Returns /// # Returns
@ -111,9 +99,8 @@ impl Config {
pub fn new(path: &str, language: &str) -> Config { pub fn new(path: &str, language: &str) -> Config {
let mut config: Config = Config { let mut config: Config = Config {
path: "".to_string(), path: "".to_string(),
language: "".to_string(), language: "".to_string()
} }.to_owned();
.to_owned();
config = config.set_language(language).to_owned(); config = config.set_language(language).to_owned();
config = config.set_path(path).to_owned(); config = config.set_path(path).to_owned();
@ -124,9 +111,8 @@ impl Config {
/// ///
/// # Parameters /// # Parameters
/// ///
/// - `self`: The config object. This must be mutable. /// - `self`: The config object.
/// - `str_path`: The directory containing the translation files. /// - `str_path`: The directory containing the translation files. The directory is relative to the path the executable was executed from.
/// The directory is relative to the path the executable was executed from.
/// ///
/// # Returns /// # Returns
/// ///
@ -140,7 +126,7 @@ impl Config {
/// ///
/// ```rust /// ```rust
/// # use localizer_rs; /// # use localizer_rs;
/// # let mut config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "language"); /// # let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "language");
/// config.set_path("examples"); /// config.set_path("examples");
/// ``` /// ```
/// ///
@ -153,26 +139,17 @@ impl Config {
match path.try_exists() { match path.try_exists() {
Ok(value) => { Ok(value) => {
if !value { if !value {
let error: errors::Error = eprintln!("Translation path {:?} does not exist", str_path);
errors::Error::new("OS Error", "Translation path was not found", 1); exit(1);
error.raise(format!("Path: {:?}", str_path).as_str());
} }
} },
Err(_error) => { Err(error) => {
let error: errors::Error = errors::Error::new("OS Error", "Could not open path", 2); eprintln!("Can't open translation path {:?}: {}", str_path, error);
error.raise(format!("Path: {:?}\nDetails: {}", str_path, _error).as_str()); exit(2);
} }
} }
self.path = String::from(match path.to_owned().to_str() { self.path = String::from(path.to_owned().to_str().expect("Expected valid path"));
Some(value) => value,
None => {
let error: errors::Error =
errors::Error::new("OS Error", "Path does not seem to be valid", 3);
error.raise(format!("Path: {:?}", str_path).as_str());
""
}
});
return self; return self;
} }
@ -180,7 +157,7 @@ impl Config {
/// ///
/// # Parameters /// # Parameters
/// ///
/// - `self`: The config object. This must be mutable. /// - `self`: The config object.
/// - `language`: The language to translate to. /// - `language`: The language to translate to.
/// ///
/// # Returns /// # Returns
@ -191,7 +168,7 @@ impl Config {
/// ///
/// ```rust /// ```rust
/// # use localizer_rs; /// # use localizer_rs;
/// # let mut config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "language"); /// # let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "language");
/// config.set_language("en"); /// config.set_language("en");
/// ``` /// ```
/// ///
@ -225,171 +202,46 @@ impl Config {
/// ///
/// # See also /// # See also
/// ///
/// - [`t!()`]
/// - [`Config`] /// - [`Config`]
pub fn t(&self, key: &str, arguments: Vec<(&str, &str)>) -> String { pub fn t(&self, key: &str, arguments: Vec<(&str, &str)>) -> String {
return self.translate(key, arguments); return self.translate::<serde_json::Value>(key, arguments);
} }
/// Translates the specified key in the language specified in the config. fn translate<T>(&self, key: &str, mut arguments: Vec<(&str, &str)>) -> String
/// where
/// # Parameters T: serde::Serialize + for<'de> serde::Deserialize<'de>
/// {
/// - `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![ let mut colors: Vec<(&str, &str)> = vec![
// Formatting codes // Formatting codes
("end", "\x1b[0m"), ("end", "\x1b[0m"), ("bold", "\x1b[1m"), ("italic", "\x1b[3m"), ("underline", "\x1b[4m"), ("overline", "\x1b[53m"),
("bold", "\x1b[1m"),
("italic", "\x1b[3m"),
("underline", "\x1b[4m"),
("overline", "\x1b[53m"),
// Foreground colors // Foreground colors
("color.black", "\x1b[30m"), ("color.black", "\x1b[30m"), ("color.red", "\x1b[31m"), ("color.green", "\x1b[32m"), ("color.yellow", "\x1b[33m"),
("color.red", "\x1b[31m"), ("color.blue", "\x1b[34m"), ("color.magenta", "\x1b[35m"), ("color.cyan", "\x1b[36m"), ("color.white", "\x1b[37m"),
("color.green", "\x1b[32m"),
("color.yellow", "\x1b[33m"),
("color.blue", "\x1b[34m"),
("color.magenta", "\x1b[35m"),
("color.cyan", "\x1b[36m"),
("color.white", "\x1b[37m"),
// Bright foreground colors // Bright foreground colors
("color.bright_black", "\x1b[90m"), ("color.bright_black", "\x1b[90m"), ("color.bright_red", "\x1b[91m"), ("color.bright_green", "\x1b[92m"),
("color.bright_red", "\x1b[91m"), ("color.bright_yellow", "\x1b[93m"), ("color.bright_blue", "\x1b[94m"), ("color.bright_magenta", "\x1b[95m"),
("color.bright_green", "\x1b[92m"), ("color.bright_cyan", "\x1b[96m"), ("color.bright_white", "\x1b[97m"),
("color.bright_yellow", "\x1b[93m"),
("color.bright_blue", "\x1b[94m"),
("color.bright_magenta", "\x1b[95m"),
("color.bright_cyan", "\x1b[96m"),
("color.bright_white", "\x1b[97m"),
// Background colors // Background colors
("back.black", "\x1b[40m"), ("back.black", "\x1b[40m"), ("back.red", "\x1b[41m"), ("back.green", "\x1b[42m"), ("back.yellow", "\x1b[43m"),
("back.red", "\x1b[41m"), ("back.blue", "\x1b[44m"), ("back.magenta", "\x1b[45m"), ("back.cyan", "\x1b[46m"), ("back.white", "\x1b[47m"),
("back.green", "\x1b[42m"),
("back.yellow", "\x1b[43m"),
("back.blue", "\x1b[44m"),
("back.magenta", "\x1b[45m"),
("back.cyan", "\x1b[46m"),
("back.white", "\x1b[47m"),
// Bright background colors // Bright background colors
("back.bright_black", "\x1b[100m"), ("back.bright_black", "\x1b[100m"), ("back.bright_red", "\x1b[101m"), ("back.bright_green", "\x1b[102m"),
("back.bright_red", "\x1b[101m"), ("back.bright_yellow", "\x1b[103m"), ("back.bright_blue", "\x1b[104m"), ("back.bright_magenta", "\x1b[105m"),
("back.bright_green", "\x1b[102m"), ("back.bright_cyan", "\x1b[106m"), ("back.bright_white", "\x1b[107m"),
("back.bright_yellow", "\x1b[103m"),
("back.bright_blue", "\x1b[104m"),
("back.bright_magenta", "\x1b[105m"),
("back.bright_cyan", "\x1b[106m"),
("back.bright_white", "\x1b[107m"),
]; ];
arguments.append(&mut colors); arguments.append(&mut colors);
let file: File = match File::open(Path::new( let file: File = File::open(Path::new(format!("./{}/{}.json", &self.path, &self.language).as_str())).unwrap();
format!("./{}/{}.json", &self.path, &self.language).as_str(),
)) {
Ok(value) => value,
Err(_error) => {
let error: errors::Error =
errors::Error::new("OS Error", "Could not open translation file", 4);
error.raise(
format!(
"File: ./{}/{}.json\nError: {}",
&self.path, &self.language, _error
)
.as_str(),
);
return "".to_owned();
}
};
let reader: BufReader<File> = BufReader::new(file); let reader: BufReader<File> = BufReader::new(file);
let json: serde_json::Value = match serde_json::to_value::<serde_json::Value>( let json: serde_json::Value = serde_json::to_value::<T>(serde_json::from_reader::<BufReader<File>, T>(reader).unwrap()).unwrap().to_owned();
match serde_json::from_reader::<BufReader<File>, serde_json::Value>(reader) {
Ok(value) => value,
Err(_error) => {
let error: errors::Error = errors::Error::new(
"Parsing error",
"Translation file could not be parsed",
5,
);
error.raise(
format!(
"File: ./{}/{}.json\nError: {}",
&self.path, &self.language, _error
)
.as_str(),
);
return "".to_owned();
}
},
) {
Ok(value) => value,
Err(_error) => {
let error: errors::Error =
errors::Error::new("Converting error", "Could not convert to json value", 6);
error.raise(
format!(
"File: ./{}/{}.json\nError: {}",
&self.path, &self.language, _error
)
.as_str(),
);
return "".to_owned();
}
}
.to_owned();
let mut result: String = match json[key].as_str() { let mut result: String = match json[key].as_str() {
Some(value) => value.to_string(), Some(value) => value.to_string(),
None => { None => "".to_string()
let error: errors::Error =
errors::Error::new("Indexing error", "Could not index json value", 6);
error.raise(
format!(
"Index: {}\nFile: ./{}/{}.json",
key, &self.path, &self.language
)
.as_str(),
);
return "".to_owned();
}
}; };
for (key, value) in arguments { for (key, value) in arguments {
@ -399,50 +251,3 @@ impl Config {
return result; 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)
}
};
}

View File

@ -1,72 +0,0 @@
// localizer-rs error tests
// Version: 1.1.1
// Copyright (c) 2023-present ElBe Development.
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the 'Software'),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
////////////////////////////////
// IMPORTS AND USE STATEMENTS //
////////////////////////////////
#[allow(unused_imports)]
use localizer_rs;
///////////
// TESTS //
///////////
#[cfg(test)]
mod tests {
#[test]
fn test_error() {
let error: localizer_rs::errors::Error =
localizer_rs::errors::Error::new("name", "description", 1);
assert_eq!(
error,
localizer_rs::errors::Error {
name: "name".to_owned(),
description: "description".to_owned(),
exit_code: 1
}
);
}
#[test]
#[ignore]
fn raise_helper() {
let error: localizer_rs::errors::Error =
localizer_rs::errors::Error::new("name", "description", 1);
error.raise("details");
}
#[test]
fn test_raise() {
let status = std::process::Command::new("cargo")
.args(&["test", "--", "--ignored"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.expect("Unable to run program");
assert_eq!(Some(1), status.code())
}
}

View File

@ -1,5 +1,5 @@
// localizer-rs tests // localizer-rs tests
// Version: 1.2.0 // Version: 1.0.0-alpha1
// Copyright (c) 2023-present ElBe Development. // Copyright (c) 2023-present ElBe Development.
@ -39,77 +39,40 @@ mod tests {
fn test_config() { fn test_config() {
let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en"); let config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en");
assert_eq!( assert_eq!(config, localizer_rs::Config {
config,
localizer_rs::Config {
path: "examples/translations".to_owned(), path: "examples/translations".to_owned(),
language: "en".to_owned() language: "en".to_owned()
} });
);
} }
#[test] #[test]
fn test_set_path() { fn test_set_path() {
let mut config: localizer_rs::Config = let mut config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en");
localizer_rs::Config::new("examples/translations", "en");
config.set_path("examples"); config.set_path("examples");
assert_eq!( assert_eq!(config, localizer_rs::Config {
config,
localizer_rs::Config {
path: "examples".to_owned(), path: "examples".to_owned(),
language: "en".to_owned() language: "en".to_owned()
} });
);
} }
#[test] #[test]
fn test_set_language() { fn test_set_language() {
let mut config: localizer_rs::Config = let mut config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en");
localizer_rs::Config::new("examples/translations", "en");
config.set_language("not_en"); config.set_language("not_en");
assert_eq!( assert_eq!(config, localizer_rs::Config {
config,
localizer_rs::Config {
path: "examples/translations".to_owned(), path: "examples/translations".to_owned(),
language: "not_en".to_owned() language: "not_en".to_owned()
} });
);
} }
#[test] #[test]
fn test_translate() { 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 config: localizer_rs::Config = localizer_rs::Config::new("examples/translations", "en");
let translation: String = config.t("error", vec![("details", "Something went wrong")]); let translation: String = config.t("error", vec![("details", "Something went wrong")]);
assert_eq!( assert_eq!(translation.as_str(), "\x1b[31m\x1b[1mError:\x1b[0m Something went wrong");
translation.as_str(),
"\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"
);
} }
} }