Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@

target/

locale/posixutils-rs.pot
locale/*/LC_MESSAGES/posixutils-rs.mo
21 changes: 21 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: MIT

PROJECT_NAME = posixutils-rs

SRCS := $(shell find . -name '*.rs' -not -path './target/*' -not -path './*/tests/*')
POS := $(shell find locale -name '*.po')
MOS := $(POS:.po=.mo)

locale: $(MOS)

%.mo: %.po locale/${PROJECT_NAME}.pot
msgmerge $^ -o $<
msgfmt $< -o $@

locale/${PROJECT_NAME}.pot: $(SRCS)
cargo r --release --bin xgettext -- -n -p locale -d ${PROJECT_NAME} $^

clean:
rm -rf locale/${PROJECT_NAME}.pot
rm -rf $(MOS)
11 changes: 11 additions & 0 deletions i18n/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ bytemuck = { version = "1.17", features = ["derive"] }
byteorder = "1.5"
strum = "0.26"
strum_macros = "0.26"
proc-macro2 = { version = "1", features = ["span-locations"] }
quote = "1"
syn = { version = "2", features = ["parsing", "full"] }

[dev-dependencies]
tempfile = "3.10"
pretty_assertions = "1.4"

[lints]
workspace = true
Expand All @@ -26,3 +33,7 @@ path = "./gencat.rs"
[[bin]]
name = "iconv"
path = "./iconv.rs"

[[bin]]
name = "xgettext"
path = "./xgettext.rs"
2 changes: 1 addition & 1 deletion i18n/iconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use strum_macros::{Display, EnumIter, EnumString};
mod iconv_lib;

#[derive(Parser)]
#[command(version, about=gettext("iconv codeset conversion"))]
#[command(version, about=gettext("iconv - codeset conversion"))]
struct Args {
#[arg(short = 'c', help=gettext("Omit invalid characters of the input file from the output"))]
omit_invalid: bool,
Expand Down
1 change: 1 addition & 0 deletions i18n/tests/i18n-tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@

mod gencat;
mod iconv;
mod xgettext;
171 changes: 171 additions & 0 deletions i18n/tests/xgettext/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// SPDX-License-Identifier: MIT

use std::fs::{read_to_string, remove_file};
use std::path::Path;

use pretty_assertions::assert_eq;
use tempfile::tempdir;

use plib::testing::{run_test, TestPlan};

fn xgettext_test<P: AsRef<Path>, P2: AsRef<Path>>(
args: &[&str],
output_file: P,
expected_output_file: P2,
) {
let str_args: Vec<String> = args.iter().map(|s| String::from(*s)).collect();
run_test(TestPlan {
cmd: String::from("xgettext"),
args: str_args,
stdin_data: "".into(),
expected_out: "".into(),
expected_err: "".into(),
expected_exit_code: 0,
});

let output = read_to_string(output_file).expect("Unable to open po-file");
let expected_out = read_to_string(expected_output_file).unwrap();
assert_eq!(output, expected_out);
}

#[test]
fn test_xgettext_no_arg() {
run_test(TestPlan {
cmd: String::from("xgettext"),
args: vec![],
stdin_data: "".into(),
expected_out: "".into(),
expected_err: "xgettext: no input file given\n".into(),
expected_exit_code: 1,
});
}

#[test]
fn test_xgettext() {
let output_file = "messages.pot";
xgettext_test(
&["tests/xgettext/test_gettext.rs"],
output_file,
"tests/xgettext/test_gettext_no_lines.pot",
);
let _ = remove_file(output_file);
}

#[test]
fn test_xgettext_domain() {
let output_file = "domain.pot";
xgettext_test(
&["-d", "domain", "tests/xgettext/test_gettext.rs"],
output_file,
"tests/xgettext/test_gettext_no_lines.pot",
);
let _ = remove_file(output_file);
}

#[test]
fn test_xgettext_pathname() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_gettext.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_gettext_no_lines.pot",
);
}

#[test]
fn test_xgettext_domain_pathname() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-d",
"domain",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_gettext.rs",
],
temp_dir.path().join("domain.pot"),
"tests/xgettext/test_gettext_no_lines.pot",
);
}

#[test]
fn test_xgettext_pathname_lines() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-n",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_gettext.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_gettext.pot",
);
}

#[test]
fn test_clap() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-n",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_clap.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_clap.pot",
);
}

#[ignore]
#[test]
fn test_xgettext_ngettext() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-n",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_ngettext.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_ngettext.pot",
);
}

#[ignore]
#[test]
fn test_xgettext_pgettext() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-n",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_pgettext.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_pgettext.pot",
);
}

#[ignore]
#[test]
fn test_xgettext_npgettext() {
let temp_dir = tempdir().expect("Unable to create temporary directory");
xgettext_test(
&[
"-n",
"-p",
&temp_dir.path().to_str().unwrap(),
"tests/xgettext/test_npgettext.rs",
],
temp_dir.path().join("messages.pot"),
"tests/xgettext/test_npgettext.pot",
);
}
36 changes: 36 additions & 0 deletions i18n/tests/xgettext/test_clap.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#: tests/xgettext/test_clap.rs:29
msgid "Arguments for the utility"
msgstr ""

#: tests/xgettext/test_clap.rs:33
msgid "Print help"
msgstr ""

#: tests/xgettext/test_clap.rs:36
msgid "Print version"
msgstr ""

#: tests/xgettext/test_clap.rs:23
msgid "The utility to be invoked"
msgstr ""

#: tests/xgettext/test_clap.rs:19
msgid "Write timing output to standard error in POSIX format"
msgstr ""

#: tests/xgettext/test_clap.rs:10
msgid "time - time a simple command or give resource usage"
msgstr ""

#: tests/xgettext/test_clap.rs:11
msgid "{about}\n"
"\n"
"Usage: {usage}\n"
"\n"
"Arguments:\n"
"{positionals}\n"
"\n"
"Options:\n"
"{options}"
msgstr ""

38 changes: 38 additions & 0 deletions i18n/tests/xgettext/test_clap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use clap::Parser;

use gettextrs::{
bind_textdomain_codeset, bindtextdomain, gettext, setlocale, textdomain, LocaleCategory,
};

#[derive(Parser)]
#[command(
version,
about = gettext("time - time a simple command or give resource usage"),
help_template = gettext("{about}\n\nUsage: {usage}\n\nArguments:\n{positionals}\n\nOptions:\n{options}"),
disable_help_flag = true,
disable_version_flag = true,
)]
struct Args {
#[arg(
short,
long,
help = gettext("Write timing output to standard error in POSIX format")
)]
posix: bool,

#[arg(help = gettext("The utility to be invoked"))]
utility: String,

#[arg(
name = "ARGUMENT",
trailing_var_arg = true,
help = gettext("Arguments for the utility")
)]
arguments: Vec<String>,

#[arg(short, long, help = gettext("Print help"), action = clap::ArgAction::HelpLong)]
help: Option<bool>,

#[arg(short = 'V', long, help = gettext("Print version"), action = clap::ArgAction::Version)]
version: Option<bool>,
}
4 changes: 4 additions & 0 deletions i18n/tests/xgettext/test_gettext.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#: tests/xgettext/test_gettext.rs:6
msgid "Hello, world!"
msgstr ""

9 changes: 9 additions & 0 deletions i18n/tests/xgettext/test_gettext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use gettextrs::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// `gettext()` simultaneously marks a string for translation and translates
// it at runtime.
println!("Translated: {}", gettext("Hello, world!"));

Ok(())
}
3 changes: 3 additions & 0 deletions i18n/tests/xgettext/test_gettext_no_lines.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
msgid "Hello, world!"
msgstr ""

7 changes: 7 additions & 0 deletions i18n/tests/xgettext/test_ngettext.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#: tests/xgettext/test_ngettext.rs:7
#: tests/xgettext/test_ngettext.rs:8
msgid "One thing"
msgid_plural "Multiple things"
msgstr[0] ""
msgstr[1] ""

11 changes: 11 additions & 0 deletions i18n/tests/xgettext/test_ngettext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use gettextrs::*;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// gettext supports plurals, i.e. you can have different messages depending
// on the number of items the message mentions. This even works for
// languages that have more than one plural form, like Russian or Czech.
println!("Singular: {}", ngettext("One thing", "Multiple things", 1));
println!("Plural: {}", ngettext("One thing", "Multiple things", 2));

Ok(())
}
Loading