mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
Merge pull request #8175 from sylvestre/l10n-shuf
l10n: port shuf for translation + add french
This commit is contained in:
commit
ce617a5375
3 changed files with 87 additions and 19 deletions
|
@ -4,3 +4,22 @@ shuf-about = Shuffle the input by outputting a random permutation of input lines
|
||||||
shuf-usage = shuf [OPTION]... [FILE]
|
shuf-usage = shuf [OPTION]... [FILE]
|
||||||
shuf -e [OPTION]... [ARG]...
|
shuf -e [OPTION]... [ARG]...
|
||||||
shuf -i LO-HI [OPTION]...
|
shuf -i LO-HI [OPTION]...
|
||||||
|
|
||||||
|
# Help messages
|
||||||
|
shuf-help-echo = treat each ARG as an input line
|
||||||
|
shuf-help-input-range = treat each number LO through HI as an input line
|
||||||
|
shuf-help-head-count = output at most COUNT lines
|
||||||
|
shuf-help-output = write result to FILE instead of standard output
|
||||||
|
shuf-help-random-source = get random bytes from FILE
|
||||||
|
shuf-help-repeat = output lines can be repeated
|
||||||
|
shuf-help-zero-terminated = line delimiter is NUL, not newline
|
||||||
|
|
||||||
|
# Error messages
|
||||||
|
shuf-error-unexpected-argument = unexpected argument { $arg } found
|
||||||
|
shuf-error-failed-to-open-for-writing = failed to open { $file } for writing
|
||||||
|
shuf-error-failed-to-open-random-source = failed to open random source { $file }
|
||||||
|
shuf-error-read-error = read error
|
||||||
|
shuf-error-no-lines-to-repeat = no lines to repeat
|
||||||
|
shuf-error-start-exceeds-end = start exceeds end
|
||||||
|
shuf-error-missing-dash = missing '-'
|
||||||
|
shuf-error-write-failed = write failed
|
||||||
|
|
25
src/uu/shuf/locales/fr-FR.ftl
Normal file
25
src/uu/shuf/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
shuf-about = Mélanger l'entrée en affichant une permutation aléatoire des lignes d'entrée.
|
||||||
|
Chaque permutation de sortie est également probable.
|
||||||
|
Sans FICHIER, ou quand FICHIER est -, lire l'entrée standard.
|
||||||
|
shuf-usage = shuf [OPTION]... [FICHIER]
|
||||||
|
shuf -e [OPTION]... [ARG]...
|
||||||
|
shuf -i MIN-MAX [OPTION]...
|
||||||
|
|
||||||
|
# Messages d'aide
|
||||||
|
shuf-help-echo = traiter chaque ARG comme une ligne d'entrée
|
||||||
|
shuf-help-input-range = traiter chaque nombre de MIN à MAX comme une ligne d'entrée
|
||||||
|
shuf-help-head-count = afficher au maximum NOMBRE lignes
|
||||||
|
shuf-help-output = écrire le résultat dans FICHIER au lieu de la sortie standard
|
||||||
|
shuf-help-random-source = obtenir des octets aléatoires depuis FICHIER
|
||||||
|
shuf-help-repeat = les lignes de sortie peuvent être répétées
|
||||||
|
shuf-help-zero-terminated = le délimiteur de ligne est NUL, pas nouvelle ligne
|
||||||
|
|
||||||
|
# Messages d'erreur
|
||||||
|
shuf-error-unexpected-argument = argument inattendu { $arg } trouvé
|
||||||
|
shuf-error-failed-to-open-for-writing = échec de l'ouverture de { $file } en écriture
|
||||||
|
shuf-error-failed-to-open-random-source = échec de l'ouverture de la source aléatoire { $file }
|
||||||
|
shuf-error-read-error = erreur de lecture
|
||||||
|
shuf-error-no-lines-to-repeat = aucune ligne à répéter
|
||||||
|
shuf-error-start-exceeds-end = le début dépasse la fin
|
||||||
|
shuf-error-missing-dash = '-' manquant
|
||||||
|
shuf-error-write-failed = échec de l'écriture
|
|
@ -10,7 +10,7 @@ use clap::{Arg, ArgAction, Command};
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
use rand::seq::IndexedRandom;
|
use rand::seq::IndexedRandom;
|
||||||
use rand::{Rng, RngCore};
|
use rand::{Rng, RngCore};
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufWriter, Error, Read, Write, stdin, stdout};
|
use std::io::{BufWriter, Error, Read, Write, stdin, stdout};
|
||||||
|
@ -20,7 +20,7 @@ use std::str::FromStr;
|
||||||
use uucore::display::{OsWrite, Quotable};
|
use uucore::display::{OsWrite, Quotable};
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||||
use uucore::format_usage;
|
use uucore::format_usage;
|
||||||
use uucore::locale::get_message;
|
use uucore::locale::{get_message, get_message_with_args};
|
||||||
|
|
||||||
mod rand_read_adapter;
|
mod rand_read_adapter;
|
||||||
|
|
||||||
|
@ -71,7 +71,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
if let Some(second_file) = operands.next() {
|
if let Some(second_file) = operands.next() {
|
||||||
return Err(UUsageError::new(
|
return Err(UUsageError::new(
|
||||||
1,
|
1,
|
||||||
format!("unexpected argument {} found", second_file.quote()),
|
get_message_with_args(
|
||||||
|
"shuf-error-unexpected-argument",
|
||||||
|
HashMap::from([("arg".to_string(), second_file.quote().to_string())]),
|
||||||
|
),
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
Mode::Default(file.into())
|
Mode::Default(file.into())
|
||||||
|
@ -101,8 +104,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let mut output = BufWriter::new(match options.output {
|
let mut output = BufWriter::new(match options.output {
|
||||||
None => Box::new(stdout()) as Box<dyn OsWrite>,
|
None => Box::new(stdout()) as Box<dyn OsWrite>,
|
||||||
Some(ref s) => {
|
Some(ref s) => {
|
||||||
let file = File::create(s)
|
let file = File::create(s).map_err_context(|| {
|
||||||
.map_err_context(|| format!("failed to open {} for writing", s.quote()))?;
|
get_message_with_args(
|
||||||
|
"shuf-error-failed-to-open-for-writing",
|
||||||
|
HashMap::from([("file".to_string(), s.quote().to_string())]),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
Box::new(file) as Box<dyn OsWrite>
|
Box::new(file) as Box<dyn OsWrite>
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -114,8 +121,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
|
||||||
let mut rng = match options.random_source {
|
let mut rng = match options.random_source {
|
||||||
Some(ref r) => {
|
Some(ref r) => {
|
||||||
let file = File::open(r)
|
let file = File::open(r).map_err_context(|| {
|
||||||
.map_err_context(|| format!("failed to open random source {}", r.quote()))?;
|
get_message_with_args(
|
||||||
|
"shuf-error-failed-to-open-random-source",
|
||||||
|
HashMap::from([("file".to_string(), r.quote().to_string())]),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
WrappedRng::RngFile(rand_read_adapter::ReadRng::new(file))
|
WrappedRng::RngFile(rand_read_adapter::ReadRng::new(file))
|
||||||
}
|
}
|
||||||
None => WrappedRng::RngDefault(rand::rng()),
|
None => WrappedRng::RngDefault(rand::rng()),
|
||||||
|
@ -149,7 +160,7 @@ pub fn uu_app() -> Command {
|
||||||
Arg::new(options::ECHO)
|
Arg::new(options::ECHO)
|
||||||
.short('e')
|
.short('e')
|
||||||
.long(options::ECHO)
|
.long(options::ECHO)
|
||||||
.help("treat each ARG as an input line")
|
.help(get_message("shuf-help-echo"))
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.overrides_with(options::ECHO)
|
.overrides_with(options::ECHO)
|
||||||
.conflicts_with(options::INPUT_RANGE),
|
.conflicts_with(options::INPUT_RANGE),
|
||||||
|
@ -159,7 +170,7 @@ pub fn uu_app() -> Command {
|
||||||
.short('i')
|
.short('i')
|
||||||
.long(options::INPUT_RANGE)
|
.long(options::INPUT_RANGE)
|
||||||
.value_name("LO-HI")
|
.value_name("LO-HI")
|
||||||
.help("treat each number LO through HI as an input line")
|
.help(get_message("shuf-help-input-range"))
|
||||||
.value_parser(parse_range)
|
.value_parser(parse_range)
|
||||||
.conflicts_with(options::FILE_OR_ARGS),
|
.conflicts_with(options::FILE_OR_ARGS),
|
||||||
)
|
)
|
||||||
|
@ -169,7 +180,7 @@ pub fn uu_app() -> Command {
|
||||||
.long(options::HEAD_COUNT)
|
.long(options::HEAD_COUNT)
|
||||||
.value_name("COUNT")
|
.value_name("COUNT")
|
||||||
.action(ArgAction::Append)
|
.action(ArgAction::Append)
|
||||||
.help("output at most COUNT lines")
|
.help(get_message("shuf-help-head-count"))
|
||||||
.value_parser(usize::from_str),
|
.value_parser(usize::from_str),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -177,7 +188,7 @@ pub fn uu_app() -> Command {
|
||||||
.short('o')
|
.short('o')
|
||||||
.long(options::OUTPUT)
|
.long(options::OUTPUT)
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("write result to FILE instead of standard output")
|
.help(get_message("shuf-help-output"))
|
||||||
.value_parser(ValueParser::path_buf())
|
.value_parser(ValueParser::path_buf())
|
||||||
.value_hint(clap::ValueHint::FilePath),
|
.value_hint(clap::ValueHint::FilePath),
|
||||||
)
|
)
|
||||||
|
@ -185,7 +196,7 @@ pub fn uu_app() -> Command {
|
||||||
Arg::new(options::RANDOM_SOURCE)
|
Arg::new(options::RANDOM_SOURCE)
|
||||||
.long(options::RANDOM_SOURCE)
|
.long(options::RANDOM_SOURCE)
|
||||||
.value_name("FILE")
|
.value_name("FILE")
|
||||||
.help("get random bytes from FILE")
|
.help(get_message("shuf-help-random-source"))
|
||||||
.value_parser(ValueParser::path_buf())
|
.value_parser(ValueParser::path_buf())
|
||||||
.value_hint(clap::ValueHint::FilePath),
|
.value_hint(clap::ValueHint::FilePath),
|
||||||
)
|
)
|
||||||
|
@ -193,7 +204,7 @@ pub fn uu_app() -> Command {
|
||||||
Arg::new(options::REPEAT)
|
Arg::new(options::REPEAT)
|
||||||
.short('r')
|
.short('r')
|
||||||
.long(options::REPEAT)
|
.long(options::REPEAT)
|
||||||
.help("output lines can be repeated")
|
.help(get_message("shuf-help-repeat"))
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.overrides_with(options::REPEAT),
|
.overrides_with(options::REPEAT),
|
||||||
)
|
)
|
||||||
|
@ -201,7 +212,7 @@ pub fn uu_app() -> Command {
|
||||||
Arg::new(options::ZERO_TERMINATED)
|
Arg::new(options::ZERO_TERMINATED)
|
||||||
.short('z')
|
.short('z')
|
||||||
.long(options::ZERO_TERMINATED)
|
.long(options::ZERO_TERMINATED)
|
||||||
.help("line delimiter is NUL, not newline")
|
.help(get_message("shuf-help-zero-terminated"))
|
||||||
.action(ArgAction::SetTrue)
|
.action(ArgAction::SetTrue)
|
||||||
.overrides_with(options::ZERO_TERMINATED),
|
.overrides_with(options::ZERO_TERMINATED),
|
||||||
)
|
)
|
||||||
|
@ -218,7 +229,7 @@ fn read_input_file(filename: &Path) -> UResult<Vec<u8>> {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
stdin()
|
stdin()
|
||||||
.read_to_end(&mut data)
|
.read_to_end(&mut data)
|
||||||
.map_err_context(|| "read error".into())?;
|
.map_err_context(|| get_message("shuf-error-read-error"))?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
} else {
|
} else {
|
||||||
std::fs::read(filename).map_err_context(|| filename.maybe_quote().to_string())
|
std::fs::read(filename).map_err_context(|| filename.maybe_quote().to_string())
|
||||||
|
@ -250,15 +261,18 @@ trait Shufable {
|
||||||
|
|
||||||
impl<'a> Shufable for Vec<&'a [u8]> {
|
impl<'a> Shufable for Vec<&'a [u8]> {
|
||||||
type Item = &'a [u8];
|
type Item = &'a [u8];
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
(**self).is_empty()
|
(**self).is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
|
fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
|
||||||
// Note: "copied()" only copies the reference, not the entire [u8].
|
// Note: "copied()" only copies the reference, not the entire [u8].
|
||||||
// Returns None if the slice is empty. We checked this before, so
|
// Returns None if the slice is empty. We checked this before, so
|
||||||
// this is safe.
|
// this is safe.
|
||||||
(**self).choose(rng).unwrap()
|
(**self).choose(rng).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_shuffle<'b>(
|
fn partial_shuffle<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
rng: &'b mut WrappedRng,
|
rng: &'b mut WrappedRng,
|
||||||
|
@ -271,12 +285,15 @@ impl<'a> Shufable for Vec<&'a [u8]> {
|
||||||
|
|
||||||
impl<'a> Shufable for Vec<&'a OsStr> {
|
impl<'a> Shufable for Vec<&'a OsStr> {
|
||||||
type Item = &'a OsStr;
|
type Item = &'a OsStr;
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
(**self).is_empty()
|
(**self).is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
|
fn choose(&self, rng: &mut WrappedRng) -> Self::Item {
|
||||||
(**self).choose(rng).unwrap()
|
(**self).choose(rng).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_shuffle<'b>(
|
fn partial_shuffle<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
rng: &'b mut WrappedRng,
|
rng: &'b mut WrappedRng,
|
||||||
|
@ -288,12 +305,15 @@ impl<'a> Shufable for Vec<&'a OsStr> {
|
||||||
|
|
||||||
impl Shufable for RangeInclusive<usize> {
|
impl Shufable for RangeInclusive<usize> {
|
||||||
type Item = usize;
|
type Item = usize;
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
self.is_empty()
|
self.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn choose(&self, rng: &mut WrappedRng) -> usize {
|
fn choose(&self, rng: &mut WrappedRng) -> usize {
|
||||||
rng.random_range(self.clone())
|
rng.random_range(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_shuffle<'b>(
|
fn partial_shuffle<'b>(
|
||||||
&'b mut self,
|
&'b mut self,
|
||||||
rng: &'b mut WrappedRng,
|
rng: &'b mut WrappedRng,
|
||||||
|
@ -420,10 +440,14 @@ fn shuf_exec(
|
||||||
rng: &mut WrappedRng,
|
rng: &mut WrappedRng,
|
||||||
output: &mut BufWriter<Box<dyn OsWrite>>,
|
output: &mut BufWriter<Box<dyn OsWrite>>,
|
||||||
) -> UResult<()> {
|
) -> UResult<()> {
|
||||||
let ctx = || "write failed".to_string();
|
let ctx = || get_message("shuf-error-write-failed");
|
||||||
|
|
||||||
if opts.repeat {
|
if opts.repeat {
|
||||||
if input.is_empty() {
|
if input.is_empty() {
|
||||||
return Err(USimpleError::new(1, "no lines to repeat"));
|
return Err(USimpleError::new(
|
||||||
|
1,
|
||||||
|
get_message("shuf-error-no-lines-to-repeat"),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for _ in 0..opts.head_count {
|
for _ in 0..opts.head_count {
|
||||||
let r = input.choose(rng);
|
let r = input.choose(rng);
|
||||||
|
@ -449,10 +473,10 @@ fn parse_range(input_range: &str) -> Result<RangeInclusive<usize>, String> {
|
||||||
if begin <= end || begin == end + 1 {
|
if begin <= end || begin == end + 1 {
|
||||||
Ok(begin..=end)
|
Ok(begin..=end)
|
||||||
} else {
|
} else {
|
||||||
Err("start exceeds end".into())
|
Err(get_message("shuf-error-start-exceeds-end"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err("missing '-'".into())
|
Err(get_message("shuf-error-missing-dash"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue