mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-27 19:17:43 +00:00
Merge pull request #8112 from sylvestre/l10n-tr
l10n: port tr for translation + add french
This commit is contained in:
commit
c14aec47f0
5 changed files with 173 additions and 46 deletions
|
@ -1,3 +1,41 @@
|
|||
tr-about = Translate or delete characters
|
||||
tr-usage = tr [OPTION]... SET1 [SET2]
|
||||
tr-after-help = Translate, squeeze, and/or delete characters from standard input, writing to standard output.
|
||||
|
||||
# Help messages
|
||||
tr-help-complement = use the complement of SET1
|
||||
tr-help-delete = delete characters in SET1, do not translate
|
||||
tr-help-squeeze = replace each sequence of a repeated character that is listed in the last specified SET, with a single occurrence of that character
|
||||
tr-help-truncate-set1 = first truncate SET1 to length of SET2
|
||||
|
||||
# Error messages
|
||||
tr-error-missing-operand = missing operand
|
||||
tr-error-missing-operand-translating = missing operand after { $set }
|
||||
Two strings must be given when translating.
|
||||
tr-error-missing-operand-deleting-squeezing = missing operand after { $set }
|
||||
Two strings must be given when deleting and squeezing.
|
||||
tr-error-extra-operand-deleting-without-squeezing = extra operand { $operand }
|
||||
Only one string may be given when deleting without squeezing repeats.
|
||||
tr-error-extra-operand-simple = extra operand { $operand }
|
||||
tr-error-read-directory = read error: Is a directory
|
||||
tr-error-write-error = write error
|
||||
|
||||
# Warning messages
|
||||
tr-warning-unescaped-backslash = warning: an unescaped backslash at end of string is not portable
|
||||
tr-warning-ambiguous-octal-escape = the ambiguous octal escape \{ $origin_octal } is being interpreted as the 2-byte sequence \0{ $actual_octal_tail }, { $outstand_char }
|
||||
|
||||
# Sequence parsing error messages
|
||||
tr-error-missing-char-class-name = missing character class name '[::]'
|
||||
tr-error-missing-equivalence-class-char = missing equivalence class character '[==]'
|
||||
tr-error-multiple-char-repeat-in-set2 = only one [c*] repeat construct may appear in string2
|
||||
tr-error-char-repeat-in-set1 = the [c*] repeat construct may not appear in string1
|
||||
tr-error-invalid-repeat-count = invalid repeat count { $count } in [c*n] construct
|
||||
tr-error-empty-set2-when-not-truncating = when not truncating set1, string2 must be non-empty
|
||||
tr-error-class-except-lower-upper-in-set2 = when translating, the only character classes that may appear in set2 are 'upper' and 'lower'
|
||||
tr-error-class-in-set2-not-matched = when translating, every 'upper'/'lower' in set2 must be matched by a 'upper'/'lower' in the same position in set1
|
||||
tr-error-set1-longer-set2-ends-in-class = when translating with string1 longer than string2,
|
||||
the latter string must not end with a character class
|
||||
tr-error-complement-more-than-one-unique = when translating with complemented character classes,
|
||||
string2 must map all characters in the domain to one
|
||||
tr-error-backwards-range = range-endpoints of '{ $start }-{ $end }' are in reverse collating sequence order
|
||||
tr-error-multiple-char-in-equivalence = { $chars }: equivalence class operand must be a single character
|
||||
|
|
42
src/uu/tr/locales/fr-FR.ftl
Normal file
42
src/uu/tr/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,42 @@
|
|||
tr-about = Traduire ou supprimer des caractères
|
||||
tr-usage = tr [OPTION]... ENSEMBLE1 [ENSEMBLE2]
|
||||
tr-after-help = Traduire, compresser et/ou supprimer des caractères de l'entrée standard, en écrivant vers la sortie standard.
|
||||
|
||||
# Messages d'aide
|
||||
tr-help-complement = utiliser le complément d'ENSEMBLE1
|
||||
tr-help-delete = supprimer les caractères dans ENSEMBLE1, ne pas traduire
|
||||
tr-help-squeeze = remplacer chaque séquence d'un caractère répété qui est listé dans le dernier ENSEMBLE spécifié, avec une seule occurrence de ce caractère
|
||||
tr-help-truncate-set1 = d'abord tronquer ENSEMBLE1 à la longueur d'ENSEMBLE2
|
||||
|
||||
# Messages d'erreur
|
||||
tr-error-missing-operand = opérande manquant
|
||||
tr-error-missing-operand-translating = opérande manquant après { $set }
|
||||
Deux chaînes doivent être données lors de la traduction.
|
||||
tr-error-missing-operand-deleting-squeezing = opérande manquant après { $set }
|
||||
Deux chaînes doivent être données lors de la suppression et compression.
|
||||
tr-error-extra-operand-deleting-without-squeezing = opérande supplémentaire { $operand }
|
||||
Une seule chaîne peut être donnée lors de la suppression sans compression des répétitions.
|
||||
tr-error-extra-operand-simple = opérande supplémentaire { $operand }
|
||||
tr-error-read-directory = erreur de lecture : Est un répertoire
|
||||
tr-error-write-error = erreur d'écriture
|
||||
|
||||
# Messages d'avertissement
|
||||
tr-warning-unescaped-backslash = avertissement : une barre oblique inverse non échappée à la fin de la chaîne n'est pas portable
|
||||
tr-warning-ambiguous-octal-escape = l'échappement octal ambigu \{ $origin_octal } est en cours
|
||||
d'interprétation comme la séquence de 2 octets \0{ $actual_octal_tail }, { $outstand_char }
|
||||
|
||||
# Messages d'erreur d'analyse de séquence
|
||||
tr-error-missing-char-class-name = nom de classe de caractères manquant '[::]'
|
||||
tr-error-missing-equivalence-class-char = caractère de classe d'équivalence manquant '[==]'
|
||||
tr-error-multiple-char-repeat-in-set2 = seule une construction de répétition [c*] peut apparaître dans string2
|
||||
tr-error-char-repeat-in-set1 = la construction de répétition [c*] ne peut pas apparaître dans string1
|
||||
tr-error-invalid-repeat-count = nombre de répétitions invalide { $count } dans la construction [c*n]
|
||||
tr-error-empty-set2-when-not-truncating = quand on ne tronque pas set1, string2 doit être non-vide
|
||||
tr-error-class-except-lower-upper-in-set2 = lors de la traduction, les seules classes de caractères qui peuvent apparaître dans set2 sont 'upper' et 'lower'
|
||||
tr-error-class-in-set2-not-matched = lors de la traduction, chaque 'upper'/'lower' dans set2 doit être associé à un 'upper'/'lower' à la même position dans set1
|
||||
tr-error-set1-longer-set2-ends-in-class = lors de la traduction avec string1 plus long que string2,
|
||||
cette dernière chaîne ne doit pas se terminer par une classe de caractères
|
||||
tr-error-complement-more-than-one-unique = lors de la traduction avec des classes de caractères complémentées,
|
||||
string2 doit mapper tous les caractères du domaine vers un seul
|
||||
tr-error-backwards-range = les points de fin de plage de '{ $start }-{ $end }' sont dans l'ordre inverse de la séquence de collation
|
||||
tr-error-multiple-char-in-equivalence = { $chars } : l'opérande de classe d'équivalence doit être un seul caractère
|
|
@ -24,6 +24,7 @@ use std::{
|
|||
ops::Not,
|
||||
};
|
||||
use uucore::error::{FromIo, UError, UResult};
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
use uucore::show_warning;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -45,44 +46,65 @@ pub enum BadSequence {
|
|||
impl Display for BadSequence {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::MissingCharClassName => write!(f, "missing character class name '[::]'"),
|
||||
Self::MissingCharClassName => {
|
||||
write!(f, "{}", get_message("tr-error-missing-char-class-name"))
|
||||
}
|
||||
Self::MissingEquivalentClassChar => {
|
||||
write!(f, "missing equivalence class character '[==]'")
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message("tr-error-missing-equivalence-class-char")
|
||||
)
|
||||
}
|
||||
Self::MultipleCharRepeatInSet2 => {
|
||||
write!(f, "only one [c*] repeat construct may appear in string2")
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message("tr-error-multiple-char-repeat-in-set2")
|
||||
)
|
||||
}
|
||||
Self::CharRepeatInSet1 => {
|
||||
write!(f, "the [c*] repeat construct may not appear in string1")
|
||||
write!(f, "{}", get_message("tr-error-char-repeat-in-set1"))
|
||||
}
|
||||
Self::InvalidRepeatCount(count) => {
|
||||
write!(f, "invalid repeat count '{count}' in [c*n] construct")
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"tr-error-invalid-repeat-count",
|
||||
HashMap::from([("count".to_string(), format!("'{}'", count))])
|
||||
)
|
||||
)
|
||||
}
|
||||
Self::EmptySet2WhenNotTruncatingSet1 => {
|
||||
write!(f, "when not truncating set1, string2 must be non-empty")
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
get_message("tr-error-empty-set2-when-not-truncating")
|
||||
)
|
||||
}
|
||||
Self::ClassExceptLowerUpperInSet2 => {
|
||||
write!(
|
||||
f,
|
||||
"when translating, the only character classes that may appear in set2 are 'upper' and 'lower'"
|
||||
"{}",
|
||||
get_message("tr-error-class-except-lower-upper-in-set2")
|
||||
)
|
||||
}
|
||||
Self::ClassInSet2NotMatchedBySet1 => {
|
||||
write!(
|
||||
f,
|
||||
"when translating, every 'upper'/'lower' in set2 must be matched by a 'upper'/'lower' in the same position in set1"
|
||||
)
|
||||
write!(f, "{}", get_message("tr-error-class-in-set2-not-matched"))
|
||||
}
|
||||
Self::Set1LongerSet2EndsInClass => {
|
||||
write!(
|
||||
f,
|
||||
"when translating with string1 longer than string2,\nthe latter string must not end with a character class"
|
||||
"{}",
|
||||
get_message("tr-error-set1-longer-set2-ends-in-class")
|
||||
)
|
||||
}
|
||||
Self::ComplementMoreThanOneUniqueInSet2 => {
|
||||
write!(
|
||||
f,
|
||||
"when translating with complemented character classes,\nstring2 must map all characters in the domain to one"
|
||||
"{}",
|
||||
get_message("tr-error-complement-more-than-one-unique")
|
||||
)
|
||||
}
|
||||
Self::BackwardsRange { end, start } => {
|
||||
|
@ -94,17 +116,25 @@ impl Display for BadSequence {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
write!(
|
||||
f,
|
||||
"range-endpoints of '{}-{}' are in reverse collating sequence order",
|
||||
end_or_start_to_string(start),
|
||||
end_or_start_to_string(end)
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"tr-error-backwards-range",
|
||||
HashMap::from([
|
||||
("start".to_string(), end_or_start_to_string(start)),
|
||||
("end".to_string(), end_or_start_to_string(end))
|
||||
])
|
||||
)
|
||||
)
|
||||
}
|
||||
Self::MultipleCharInEquivalence(s) => write!(
|
||||
f,
|
||||
"{s}: equivalence class operand must be a single character"
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"tr-error-multiple-char-in-equivalence",
|
||||
HashMap::from([("chars".to_string(), s.clone())])
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -364,11 +394,25 @@ impl Sequence {
|
|||
let origin_octal: &str = std::str::from_utf8(input).unwrap();
|
||||
let actual_octal_tail: &str = std::str::from_utf8(&input[0..2]).unwrap();
|
||||
let outstand_char: char = char::from_u32(input[2] as u32).unwrap();
|
||||
show_warning!("the ambiguous octal escape \\{origin_octal} is being\n interpreted as the 2-byte sequence \\0{actual_octal_tail}, {outstand_char}");
|
||||
show_warning!(
|
||||
"{}",
|
||||
get_message_with_args(
|
||||
"tr-warning-ambiguous-octal-escape",
|
||||
HashMap::from([
|
||||
("origin_octal".to_string(), origin_octal.to_string()),
|
||||
(
|
||||
"actual_octal_tail".to_string(),
|
||||
actual_octal_tail.to_string()
|
||||
),
|
||||
("outstand_char".to_string(), outstand_char.to_string())
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
result
|
||||
},
|
||||
).parse(input)
|
||||
)
|
||||
.parse(input)
|
||||
}
|
||||
|
||||
fn parse_octal_two_digits(input: &[u8]) -> IResult<&[u8], u8> {
|
||||
|
@ -666,7 +710,7 @@ where
|
|||
|
||||
output
|
||||
.write_all(&output_buf)
|
||||
.map_err_context(|| "write error".into())?;
|
||||
.map_err_context(|| get_message("tr-error-write-error"))?;
|
||||
|
||||
buf.clear();
|
||||
output_buf.clear();
|
||||
|
|
|
@ -13,6 +13,7 @@ use clap::{Arg, ArgAction, Command, value_parser};
|
|||
use operation::{
|
||||
Sequence, SqueezeOperation, SymbolTranslator, TranslateOperation, translate_input,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::io::{BufWriter, Write, stdin, stdout};
|
||||
use uucore::display::Quotable;
|
||||
|
@ -20,7 +21,7 @@ use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
|||
use uucore::fs::is_stdin_directory;
|
||||
use uucore::{format_usage, os_str_as_bytes, show};
|
||||
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
mod options {
|
||||
pub const COMPLEMENT: &str = "complement";
|
||||
|
@ -53,15 +54,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let sets_len = sets.len();
|
||||
|
||||
if sets.is_empty() {
|
||||
return Err(UUsageError::new(1, "missing operand"));
|
||||
return Err(UUsageError::new(1, get_message("tr-error-missing-operand")));
|
||||
}
|
||||
|
||||
if !(delete_flag || squeeze_flag) && sets_len < 2 {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
format!(
|
||||
"missing operand after {}\nTwo strings must be given when translating.",
|
||||
sets[0].quote()
|
||||
get_message_with_args(
|
||||
"tr-error-missing-operand-translating",
|
||||
HashMap::from([("set".to_string(), sets[0].quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -69,29 +70,35 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if delete_flag & squeeze_flag && sets_len < 2 {
|
||||
return Err(UUsageError::new(
|
||||
1,
|
||||
format!(
|
||||
"missing operand after {}\nTwo strings must be given when deleting and squeezing.",
|
||||
sets[0].quote()
|
||||
get_message_with_args(
|
||||
"tr-error-missing-operand-deleting-squeezing",
|
||||
HashMap::from([("set".to_string(), sets[0].quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
if sets_len > 1 {
|
||||
let start = "extra operand";
|
||||
if delete_flag && !squeeze_flag {
|
||||
let op = sets[1].quote();
|
||||
let msg = if sets_len == 2 {
|
||||
format!(
|
||||
"{start} {op}\nOnly one string may be given when deleting without squeezing repeats.",
|
||||
get_message_with_args(
|
||||
"tr-error-extra-operand-deleting-without-squeezing",
|
||||
HashMap::from([("operand".to_string(), op.to_string())]),
|
||||
)
|
||||
} else {
|
||||
format!("{start} {op}")
|
||||
get_message_with_args(
|
||||
"tr-error-extra-operand-simple",
|
||||
HashMap::from([("operand".to_string(), op.to_string())]),
|
||||
)
|
||||
};
|
||||
return Err(UUsageError::new(1, msg));
|
||||
}
|
||||
if sets_len > 2 {
|
||||
let op = sets[2].quote();
|
||||
let msg = format!("{start} {op}");
|
||||
let msg = get_message_with_args(
|
||||
"tr-error-extra-operand-simple",
|
||||
HashMap::from([("operand".to_string(), op.to_string())]),
|
||||
);
|
||||
return Err(UUsageError::new(1, msg));
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +110,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
// The trailing backslash has a non-backslash character before it.
|
||||
show!(USimpleError::new(
|
||||
0,
|
||||
"warning: an unescaped backslash at end of string is not portable"
|
||||
get_message("tr-warning-unescaped-backslash")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +132,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
)?;
|
||||
|
||||
if is_stdin_directory(&stdin) {
|
||||
return Err(USimpleError::new(1, "read error: Is a directory"));
|
||||
return Err(USimpleError::new(1, get_message("tr-error-read-directory")));
|
||||
}
|
||||
|
||||
// '*_op' are the operations that need to be applied, in order.
|
||||
|
@ -156,7 +163,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
|
||||
buffered_stdout
|
||||
.flush()
|
||||
.map_err_context(|| "write error".into())?;
|
||||
.map_err_context(|| get_message("tr-error-write-error"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -173,7 +180,7 @@ pub fn uu_app() -> Command {
|
|||
.visible_short_alias('C')
|
||||
.short('c')
|
||||
.long(options::COMPLEMENT)
|
||||
.help("use the complement of SET1")
|
||||
.help(get_message("tr-help-complement"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::COMPLEMENT),
|
||||
)
|
||||
|
@ -181,7 +188,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::DELETE)
|
||||
.short('d')
|
||||
.long(options::DELETE)
|
||||
.help("delete characters in SET1, do not translate")
|
||||
.help(get_message("tr-help-delete"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::DELETE),
|
||||
)
|
||||
|
@ -189,11 +196,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::SQUEEZE)
|
||||
.long(options::SQUEEZE)
|
||||
.short('s')
|
||||
.help(
|
||||
"replace each sequence of a repeated character that is \
|
||||
listed in the last specified SET, with a single occurrence \
|
||||
of that character",
|
||||
)
|
||||
.help(get_message("tr-help-squeeze"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::SQUEEZE),
|
||||
)
|
||||
|
@ -201,7 +204,7 @@ pub fn uu_app() -> Command {
|
|||
Arg::new(options::TRUNCATE_SET1)
|
||||
.long(options::TRUNCATE_SET1)
|
||||
.short('t')
|
||||
.help("first truncate SET1 to length of SET2")
|
||||
.help(get_message("tr-help-truncate-set1"))
|
||||
.action(ArgAction::SetTrue)
|
||||
.overrides_with(options::TRUNCATE_SET1),
|
||||
)
|
||||
|
|
|
@ -1521,7 +1521,7 @@ fn test_multibyte_octal_sequence() {
|
|||
.args(&["-d", r"\501"])
|
||||
.pipe_in("(1Ł)")
|
||||
.succeeds()
|
||||
.stderr_is("tr: warning: the ambiguous octal escape \\501 is being\n interpreted as the 2-byte sequence \\050, 1\n")
|
||||
.stderr_is("tr: warning: the ambiguous octal escape \\501 is being interpreted as the 2-byte sequence \\050, 1\n")
|
||||
.stdout_is("Ł)");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue