Compare commits

..

34 Commits
v1.0.0 ... main

Author SHA1 Message Date
ElBe
21d4ba85e9
Merge pull request #5 from ElBe-Development/dependabot/github_actions/actions/setup-python-5
Bump actions/setup-python from 4 to 5
2025-01-24 12:53:05 +01:00
ElBe
1addf7b72a
Merge pull request #11 from ElBe-Development/dependabot/pip/pre-commit-4.1.0
Bump pre-commit from 3.5.0 to 4.1.0
2025-01-23 21:28:44 +01:00
ElBe
7251484eaa
Merge pull request #7 from ElBe-Development/dependabot/github_actions/actions/dependency-review-action-4
Bump actions/dependency-review-action from 3 to 4
2025-01-23 21:26:25 +01:00
dependabot[bot]
1a749cb6ab
Bump pre-commit from 3.5.0 to 4.1.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.5.0 to 4.1.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.5.0...v4.1.0)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-23 20:26:23 +00:00
ElBe
1ac8dcf6a5
Merge pull request #8 from ElBe-Development/dependabot/github_actions/codecov/codecov-action-4
Bump codecov/codecov-action from 3 to 4
2025-01-23 21:26:03 +01:00
ElBe
3d649300c7
Merge pull request #4 from ElBe-Development/dependabot/github_actions/actions/labeler-5
Bump actions/labeler from 4 to 5
2025-01-23 21:24:35 +01:00
dependabot[bot]
b9a8a54232
Bump codecov/codecov-action from 3 to 4
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: codecov/codecov-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 13:04:46 +00:00
dependabot[bot]
a79508348c
Bump actions/dependency-review-action from 3 to 4
Bumps [actions/dependency-review-action](https://github.com/actions/dependency-review-action) from 3 to 4.
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](https://github.com/actions/dependency-review-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/dependency-review-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 12:33:50 +00:00
dependabot[bot]
152f973edd
Bump actions/setup-python from 4 to 5
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 4 to 5.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-06 12:54:42 +00:00
dependabot[bot]
39228823bd
Bump actions/labeler from 4 to 5
Bumps [actions/labeler](https://github.com/actions/labeler) from 4 to 5.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-05 12:41:40 +00:00
ElBe
57bb936433
Bump pre-commit from 3.4.0 to 3.5.0
Bump pre-commit from 3.4.0 to 3.5.0
2023-10-23 20:18:53 +02:00
dependabot[bot]
f2caa5c3b1
Bump pre-commit from 3.4.0 to 3.5.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 12:44:34 +00:00
ElBe
163e31bb45 Added t!() macro 2023-10-06 07:39:56 +02:00
ElBe
a8fd02158b Fixed yaml syntax error 2023-09-15 15:13:42 +02:00
ElBe
a85b394b1e Added one single missing bang 2023-09-15 15:10:31 +02:00
ElBe
21f8c781ee Fixed license field 2023-09-15 07:23:25 +02:00
ElBe
3f69ad6aaf Bump version 2023-09-15 07:19:36 +02:00
ElBe
e011a01b31 Bump pre-commit from 3.3.2 to 3.4.0 2023-09-15 07:18:17 +02:00
ElBe
70f5e4b28b Bump actions/checkout from 3 to 4 2023-09-15 07:17:22 +02:00
ElBe
5f1952f362 Fixed license and bump dependencies 2023-09-15 07:14:05 +02:00
ElBe
97b67a7713 Renamed error import 2023-09-15 07:13:25 +02:00
ElBe
31a390f25f Fixed tests being run 2023-09-15 07:13:05 +02:00
ElBe
25ecd37d7d Added codecov 2023-09-15 07:12:39 +02:00
ElBe
195b9edc34 Fixed indent 2023-09-14 19:40:18 +02:00
ElBe
f50157eae0 Updated justfile 2023-09-14 19:38:03 +02:00
ElBe
4e8f910351 Added struct field documentation 2023-09-14 19:33:36 +02:00
ElBe
9e0a4d087b Bump version 2023-09-14 19:17:01 +02:00
ElBe
e18a62267f Formatted files 2023-09-14 19:15:40 +02:00
ElBe
6fd9e66ce8 Implemented errors 2023-09-14 19:14:34 +02:00
ElBe
53682cf1b7 Added errors 2023-09-14 18:34:47 +02:00
ElBe
5db6014654 Updated documentation 2023-09-14 17:17:48 +02:00
ElBe
6e7b2e9cc5 Fixed badge 2023-09-14 17:16:46 +02:00
ElBe
2b76f50d4c Fixed spelling mistake 2023-09-14 17:14:54 +02:00
ElBe
66363879c8 Converted tabs to spaces and fixed tests 2023-09-14 17:08:58 +02:00
18 changed files with 633 additions and 143 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` ad `cargo clippy` to verify it works. 4. Test your changes. Run `cargo fmt`, `cargo check` and `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.

42
.github/README.md vendored
View File

@ -1,11 +1,11 @@
<h1 align="center"> <h1 align="center">
localizer-rs localizer-rs
</h1> </h1>
<h3 align="center"> <h3 align="center">
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/qstash-rs"> <img src="https://img.shields.io/crates/v/localizer-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,60 +38,48 @@ 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 ```rust,ignore
use localizer_rs;
use localizer_rs; ```
```
2. Create a new config object: 2. Create a new config object:
```rust ```rust,ignore
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 ```rust,ignore
localizer_rs::t!(config, "key", "placeholder" ="value");
config.t("key", vec!["placeholder", "value"]); ```
```
## Example ## Example
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 ```rust,ignore
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!("{:}", config.t("error", vec![("details", "Path not found")])); println!("{:}", localizer_rs::t!(config, "error", "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,6 +5,9 @@
| 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 Normal file
View File

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

14
.github/workflows/codecov_workflow.yml vendored Normal file
View File

@ -0,0 +1,14 @@
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@v3 - uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4 uses: actions/setup-python@v5
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@v3 - uses: actions/checkout@v4
- 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@v3 uses: actions/checkout@v4
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@v3 uses: actions/dependency-review-action@v4

View File

@ -20,6 +20,6 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- uses: actions/labeler@v4 - uses: actions/labeler@v5
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@v3 uses: actions/checkout@v4
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@v3 - uses: actions/checkout@v4
- 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.0.0" version = "1.2.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-file = "LICENSE.txt" license = "MIT"
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.106" serde_json = "1.0.107"

10
codecov.yml Normal file
View File

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

View File

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

View File

@ -1,10 +1,20 @@
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!("{:}", config.t("error", vec![("details", "Something went wrong when trying to do stuff")])); println!(
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!("{:}", config.t("all", vec![])); println!("{:}", localizer_rs::t!(config, "all"));
} }

View File

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

159
src/errors.rs Normal file
View File

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

72
tests/errors.rs Normal file
View File

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