1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

l10n: port stty for translation + add french

Co-authored-by: Daniel Hofstetter <daniel.hofstetter@42dh.com>
This commit is contained in:
Sylvestre Ledru 2025-06-23 19:03:34 +02:00
parent 05eb7ee374
commit 95e3d6e92c
3 changed files with 180 additions and 38 deletions

View file

@ -1,4 +1,25 @@
stty-about = Print or change terminal characteristics. stty-usage = "stty [-F DEVICE | --file=DEVICE] [SETTING]...
stty-usage = stty [-F DEVICE | --file=DEVICE] [SETTING]... or: stty [-F DEVICE | --file=DEVICE] [-a|--all]
stty [-F DEVICE | --file=DEVICE] [-a|--all] or: stty [-F DEVICE | --file=DEVICE] [-g|--save]"
stty [-F DEVICE | --file=DEVICE] [-g|--save]
stty-about = "Print or change terminal characteristics."
stty-option-all = "print all current settings in human-readable form"
stty-option-save = "print all current settings in a stty-readable form"
stty-option-file = "open and use the specified DEVICE instead of stdin"
stty-option-settings = "settings to change"
stty-error-options-mutually-exclusive = "the options for verbose and stty-readable output styles are mutually exclusive"
stty-error-output-style-no-modes = "when specifying an output style, modes may not be set"
stty-error-missing-argument = "missing argument to '{$arg}'"
stty-error-invalid-speed = "invalid {$arg} '{$speed}'"
stty-error-invalid-argument = "invalid argument '{$arg}'"
stty-error-invalid-integer-argument = "invalid integer argument: {$value}"
stty-error-invalid-integer-argument-value-too-large = "invalid integer argument: {$value}: Value too large for defined data type"
# Output format strings
stty-output-speed = speed {$speed} baud;
stty-output-rows-columns = rows {$rows}; columns {$columns};
stty-output-line = line = {$line};
stty-output-undef = <undef>
stty-output-min-time = min = {$min}; time = {$time};

View file

@ -0,0 +1,25 @@
stty-usage = "stty [-F PÉRIPHÉRIQUE | --file=PÉRIPHÉRIQUE] [PARAMÈTRE]...
ou: stty [-F PÉRIPHÉRIQUE | --file=PÉRIPHÉRIQUE] [-a|--all]
ou: stty [-F PÉRIPHÉRIQUE | --file=PÉRIPHÉRIQUE] [-g|--save]"
stty-about = "Afficher ou modifier les caractéristiques du terminal."
stty-option-all = "afficher tous les paramètres actuels sous forme lisible"
stty-option-save = "afficher tous les paramètres actuels sous forme lisible par stty"
stty-option-file = "ouvrir et utiliser le PÉRIPHÉRIQUE spécifié au lieu de stdin"
stty-option-settings = "paramètres à modifier"
stty-error-options-mutually-exclusive = "les options pour les styles de sortie verbeux et lisible par stty s'excluent mutuellement"
stty-error-output-style-no-modes = "lors de la spécification d'un style de sortie, les modes ne peuvent pas être définis"
stty-error-missing-argument = "argument manquant pour '{$arg}'"
stty-error-invalid-speed = "{$arg} invalide '{$speed}'"
stty-error-invalid-argument = "argument invalide '{$arg}'"
stty-error-invalid-integer-argument = "argument entier invalide : {$value}"
stty-error-invalid-integer-argument-value-too-large = "argument entier invalide : {$value} : Valeur trop grande pour le type de données défini"
# Chaînes de format de sortie
stty-output-speed = vitesse {$speed} bauds ;
stty-output-rows-columns = lignes {$rows} ; colonnes {$columns} ;
stty-output-line = ligne = {$line} ;
stty-output-undef = <indéfini>
stty-output-min-time = min = {$min} ; temps = {$time} ;

View file

@ -15,6 +15,7 @@ use nix::sys::termios::{
cfgetospeed, cfsetospeed, tcgetattr, tcsetattr, cfgetospeed, cfsetospeed, tcgetattr, tcsetattr,
}; };
use nix::{ioctl_read_bad, ioctl_write_ptr_bad}; use nix::{ioctl_read_bad, ioctl_write_ptr_bad};
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::{self, Stdout, stdout}; use std::io::{self, Stdout, stdout};
use std::os::fd::{AsFd, BorrowedFd}; use std::os::fd::{AsFd, BorrowedFd};
@ -22,7 +23,7 @@ use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use uucore::error::{UResult, USimpleError}; use uucore::error::{UResult, USimpleError};
use uucore::format_usage; use uucore::format_usage;
use uucore::locale::get_message; use uucore::locale::{get_message, get_message_with_args};
#[cfg(not(any( #[cfg(not(any(
target_os = "freebsd", target_os = "freebsd",
@ -104,8 +105,8 @@ enum Device {
} }
enum ControlCharMappingError { enum ControlCharMappingError {
IntOutOfRange, IntOutOfRange(String),
MultipleChars, MultipleChars(String),
} }
enum SpecialSetting { enum SpecialSetting {
@ -226,14 +227,14 @@ fn stty(opts: &Options) -> UResult<()> {
if opts.save && opts.all { if opts.save && opts.all {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
"the options for verbose and stty-readable output styles are mutually exclusive", get_message("stty-error-options-mutually-exclusive"),
)); ));
} }
if opts.settings.is_some() && (opts.save || opts.all) { if opts.settings.is_some() && (opts.save || opts.all) {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
"when specifying an output style, modes may not be set", get_message("stty-error-output-style-no-modes"),
)); ));
} }
@ -248,18 +249,26 @@ fn stty(opts: &Options) -> UResult<()> {
if let Some(mapping) = args_iter.next() { if let Some(mapping) = args_iter.next() {
let cc_mapping = string_to_control_char(mapping).map_err(|e| { let cc_mapping = string_to_control_char(mapping).map_err(|e| {
let message = match e { let message = match e {
ControlCharMappingError::IntOutOfRange => format!( ControlCharMappingError::IntOutOfRange(val) => get_message_with_args(
"invalid integer argument: '{mapping}': Value too large for defined data type" "stty-error-invalid-integer-argument-value-too-large",
HashMap::from([("value".to_string(), format!("'{}'", val))]),
),
ControlCharMappingError::MultipleChars(val) => get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{}'", val))]),
), ),
ControlCharMappingError::MultipleChars => {
format!("invalid integer argument: '{mapping}'")
}
}; };
USimpleError::new(1, message) USimpleError::new(1, message)
})?; })?;
valid_args.push(ArgOptions::Mapping((char_index, cc_mapping))); valid_args.push(ArgOptions::Mapping((char_index, cc_mapping)));
} else { } else {
return Err(USimpleError::new(1, format!("missing argument to '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
// ispeed/ospeed baud rate setting // ispeed/ospeed baud rate setting
} else if *arg == "ispeed" || *arg == "ospeed" { } else if *arg == "ispeed" || *arg == "ospeed" {
@ -268,11 +277,26 @@ fn stty(opts: &Options) -> UResult<()> {
if let Some(baud_flag) = string_to_baud(speed) { if let Some(baud_flag) = string_to_baud(speed) {
valid_args.push(ArgOptions::Flags(baud_flag)); valid_args.push(ArgOptions::Flags(baud_flag));
} else { } else {
return Err(USimpleError::new(1, format!("invalid {arg} '{speed}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-speed",
HashMap::from([
("arg".to_string(), arg.to_string()),
("speed".to_string(), speed.to_string()),
]),
),
));
} }
} }
None => { None => {
return Err(USimpleError::new(1, format!("missing argument to '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
} }
// baud rate setting // baud rate setting
@ -288,7 +312,13 @@ fn stty(opts: &Options) -> UResult<()> {
AllFlags::OutputFlags((flag, remove)) => check_flag_group(flag, remove), AllFlags::OutputFlags((flag, remove)) => check_flag_group(flag, remove),
}; };
if remove_group { if remove_group {
return Err(USimpleError::new(1, format!("invalid argument '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
valid_args.push(flag.into()); valid_args.push(flag.into());
} else if *arg == "rows" { } else if *arg == "rows" {
@ -298,11 +328,20 @@ fn stty(opts: &Options) -> UResult<()> {
} else { } else {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!("invalid integer argument: '{rows}'"), get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{}'", rows))]),
),
)); ));
} }
} else { } else {
return Err(USimpleError::new(1, format!("missing argument to '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
} else if *arg == "columns" || *arg == "cols" { } else if *arg == "columns" || *arg == "cols" {
if let Some(cols) = args_iter.next() { if let Some(cols) = args_iter.next() {
@ -311,17 +350,32 @@ fn stty(opts: &Options) -> UResult<()> {
} else { } else {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!("invalid integer argument: '{cols}'"), get_message_with_args(
"stty-error-invalid-integer-argument",
HashMap::from([("value".to_string(), format!("'{}'", cols))]),
),
)); ));
} }
} else { } else {
return Err(USimpleError::new(1, format!("missing argument to '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-missing-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
} else if *arg == "size" { } else if *arg == "size" {
valid_args.push(ArgOptions::Print(PrintSetting::Size)); valid_args.push(ArgOptions::Print(PrintSetting::Size));
// not a valid option // not a valid option
} else { } else {
return Err(USimpleError::new(1, format!("invalid argument '{arg}'"))); return Err(USimpleError::new(
1,
get_message_with_args(
"stty-error-invalid-argument",
HashMap::from([("arg".to_string(), arg.to_string())]),
),
));
} }
} }
@ -391,7 +445,13 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
target_os = "netbsd", target_os = "netbsd",
target_os = "openbsd" target_os = "openbsd"
))] ))]
print!("speed {speed} baud; "); print!(
"{} ",
get_message_with_args(
"stty-output-speed",
HashMap::from([("speed".to_string(), speed.to_string())])
)
);
// Other platforms need to use the baud rate enum, so printing the right value // Other platforms need to use the baud rate enum, so printing the right value
// becomes slightly more complicated. // becomes slightly more complicated.
@ -405,7 +465,13 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
)))] )))]
for (text, baud_rate) in BAUD_RATES { for (text, baud_rate) in BAUD_RATES {
if *baud_rate == speed { if *baud_rate == speed {
print!("speed {text} baud; "); print!(
"{} ",
get_message_with_args(
"stty-output-speed",
HashMap::from([("speed".to_string(), text.to_string())])
)
);
break; break;
} }
} }
@ -413,7 +479,16 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
if opts.all { if opts.all {
let mut size = TermSize::default(); let mut size = TermSize::default();
unsafe { tiocgwinsz(opts.file.as_raw_fd(), &raw mut size)? }; unsafe { tiocgwinsz(opts.file.as_raw_fd(), &raw mut size)? };
print!("rows {}; columns {}; ", size.rows, size.columns); print!(
"{} ",
get_message_with_args(
"stty-output-rows-columns",
HashMap::from([
("rows".to_string(), size.rows.to_string()),
("columns".to_string(), size.columns.to_string())
])
)
);
} }
#[cfg(any(target_os = "linux", target_os = "redox"))] #[cfg(any(target_os = "linux", target_os = "redox"))]
@ -422,7 +497,13 @@ fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
// so we get the underlying libc::termios struct to get that information. // so we get the underlying libc::termios struct to get that information.
let libc_termios: nix::libc::termios = termios.clone().into(); let libc_termios: nix::libc::termios = termios.clone().into();
let line = libc_termios.c_line; let line = libc_termios.c_line;
print!("line = {line};"); print!(
"{}",
get_message_with_args(
"stty-output-line",
HashMap::from([("line".to_string(), line.to_string())])
)
);
} }
println!(); println!();
@ -498,7 +579,7 @@ fn string_to_flag(option: &str) -> Option<AllFlags> {
fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> { fn control_char_to_string(cc: nix::libc::cc_t) -> nix::Result<String> {
if cc == 0 { if cc == 0 {
return Ok("<undef>".to_string()); return Ok(get_message("stty-output-undef"));
} }
let (meta_prefix, code) = if cc >= 0x80 { let (meta_prefix, code) = if cc >= 0x80 {
@ -535,9 +616,20 @@ fn print_control_chars(termios: &Termios, opts: &Options) -> nix::Result<()> {
); );
} }
println!( println!(
"min = {}; time = {};", "{}",
termios.control_chars[SpecialCharacterIndices::VMIN as usize], get_message_with_args(
termios.control_chars[SpecialCharacterIndices::VTIME as usize] "stty-output-min-time",
HashMap::from([
(
"min".to_string(),
termios.control_chars[SpecialCharacterIndices::VMIN as usize].to_string()
),
(
"time".to_string(),
termios.control_chars[SpecialCharacterIndices::VTIME as usize].to_string()
)
])
)
); );
Ok(()) Ok(())
} }
@ -682,14 +774,18 @@ fn string_to_control_char(s: &str) -> Result<u8, ControlCharMappingError> {
let ascii_num = if let Some(hex) = s.strip_prefix("0x") { let ascii_num = if let Some(hex) = s.strip_prefix("0x") {
u32::from_str_radix(hex, 16).ok() u32::from_str_radix(hex, 16).ok()
} else if let Some(octal) = s.strip_prefix("0") { } else if let Some(octal) = s.strip_prefix("0") {
u32::from_str_radix(octal, 8).ok() if octal.is_empty() {
Some(0)
} else {
u32::from_str_radix(octal, 8).ok()
}
} else { } else {
s.parse::<u32>().ok() s.parse::<u32>().ok()
}; };
if let Some(val) = ascii_num { if let Some(val) = ascii_num {
if val > 255 { if val > 255 {
return Err(ControlCharMappingError::IntOutOfRange); return Err(ControlCharMappingError::IntOutOfRange(s.to_string()));
} else { } else {
return Ok(val as u8); return Ok(val as u8);
} }
@ -706,7 +802,7 @@ fn string_to_control_char(s: &str) -> Result<u8, ControlCharMappingError> {
Ok((c.to_ascii_uppercase() as u8).wrapping_sub(b'@')) Ok((c.to_ascii_uppercase() as u8).wrapping_sub(b'@'))
} }
(Some(c), None) => Ok(c as u8), (Some(c), None) => Ok(c as u8),
(Some(_), Some(_)) => Err(ControlCharMappingError::MultipleChars), (Some(_), Some(_)) => Err(ControlCharMappingError::MultipleChars(s.to_string())),
_ => unreachable!("No arguments provided: must have been caught earlier"), _ => unreachable!("No arguments provided: must have been caught earlier"),
} }
} }
@ -721,14 +817,14 @@ pub fn uu_app() -> Command {
Arg::new(options::ALL) Arg::new(options::ALL)
.short('a') .short('a')
.long(options::ALL) .long(options::ALL)
.help("print all current settings in human-readable form") .help(get_message("stty-option-all"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::SAVE) Arg::new(options::SAVE)
.short('g') .short('g')
.long(options::SAVE) .long(options::SAVE)
.help("print all current settings in a stty-readable form") .help(get_message("stty-option-save"))
.action(ArgAction::SetTrue), .action(ArgAction::SetTrue),
) )
.arg( .arg(
@ -737,13 +833,13 @@ pub fn uu_app() -> Command {
.long(options::FILE) .long(options::FILE)
.value_hint(clap::ValueHint::FilePath) .value_hint(clap::ValueHint::FilePath)
.value_name("DEVICE") .value_name("DEVICE")
.help("open and use the specified DEVICE instead of stdin"), .help(get_message("stty-option-file")),
) )
.arg( .arg(
Arg::new(options::SETTINGS) Arg::new(options::SETTINGS)
.action(ArgAction::Append) .action(ArgAction::Append)
.allow_hyphen_values(true) .allow_hyphen_values(true)
.help("settings to change"), .help(get_message("stty-option-settings")),
) )
} }