From ac265279fcff7310330cce7fed46cba63de7870e Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Sun, 8 Jun 2025 11:19:37 +0200 Subject: [PATCH] l10n: port truncate to translation + add french --- src/uu/truncate/locales/en-US.ftl | 15 +++++ src/uu/truncate/locales/fr-FR.ftl | 33 +++++++++++ src/uu/truncate/src/truncate.rs | 99 +++++++++++++++++++++---------- 3 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 src/uu/truncate/locales/fr-FR.ftl diff --git a/src/uu/truncate/locales/en-US.ftl b/src/uu/truncate/locales/en-US.ftl index b3ae2fcc4..f34142743 100644 --- a/src/uu/truncate/locales/en-US.ftl +++ b/src/uu/truncate/locales/en-US.ftl @@ -16,3 +16,18 @@ truncate-after-help = SIZE is an integer with an optional prefix and optional un '>' => at least '/' => round down to multiple of '%' => round up to multiple of + +# Help messages +truncate-help-io-blocks = treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED) +truncate-help-no-create = do not create files that do not exist +truncate-help-reference = base the size of each file on the size of RFILE +truncate-help-size = set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified + +# Error messages +truncate-error-missing-file-operand = missing file operand +truncate-error-cannot-open-no-device = cannot open { $filename } for writing: No such device or address +truncate-error-cannot-open-for-writing = cannot open { $filename } for writing +truncate-error-invalid-number = Invalid number: { $error } +truncate-error-must-specify-relative-size = you must specify a relative '--size' with '--reference' +truncate-error-division-by-zero = division by zero +truncate-error-cannot-stat-no-such-file = cannot stat { $filename }: No such file or directory diff --git a/src/uu/truncate/locales/fr-FR.ftl b/src/uu/truncate/locales/fr-FR.ftl new file mode 100644 index 000000000..4160cc337 --- /dev/null +++ b/src/uu/truncate/locales/fr-FR.ftl @@ -0,0 +1,33 @@ +truncate-about = Réduire ou étendre la taille de chaque fichier à la taille spécifiée. +truncate-usage = truncate [OPTION]... [FICHIER]... +truncate-after-help = TAILLE est un entier avec un préfixe optionnel et une unité optionnelle. + Les unités disponibles (K, M, G, T, P, E, Z, et Y) utilisent le format suivant : + 'KB' => 1000 (kilooctets) + 'K' => 1024 (kibioctets) + 'MB' => 1000*1000 (mégaoctets) + 'M' => 1024*1024 (mébioctets) + 'GB' => 1000*1000*1000 (gigaoctets) + 'G' => 1024*1024*1024 (gibioctets) + TAILLE peut aussi être préfixée par l'un des éléments suivants pour ajuster la taille de chaque + fichier basé sur sa taille actuelle : + '+' => étendre de + '-' => réduire de + '<' => au maximum + '>' => au minimum + '/' => arrondir vers le bas au multiple de + '%' => arrondir vers le haut au multiple de + +# Messages d'aide +truncate-help-io-blocks = traiter TAILLE comme le nombre de blocs I/O du fichier plutôt que des octets (NON IMPLÉMENTÉ) +truncate-help-no-create = ne pas créer les fichiers qui n'existent pas +truncate-help-reference = baser la taille de chaque fichier sur la taille de RFICHIER +truncate-help-size = définir ou ajuster la taille de chaque fichier selon TAILLE, qui est en octets sauf si --io-blocks est spécifié + +# Messages d'erreur +truncate-error-missing-file-operand = opérande de fichier manquant +truncate-error-cannot-open-no-device = impossible d'ouvrir { $filename } en écriture : Aucun périphérique ou adresse de ce type +truncate-error-cannot-open-for-writing = impossible d'ouvrir { $filename } en écriture +truncate-error-invalid-number = Nombre invalide : { $error } +truncate-error-must-specify-relative-size = vous devez spécifier une '--size' relative avec '--reference' +truncate-error-division-by-zero = division par zéro +truncate-error-cannot-stat-no-such-file = impossible d'obtenir les informations de { $filename } : Aucun fichier ou répertoire de ce type diff --git a/src/uu/truncate/src/truncate.rs b/src/uu/truncate/src/truncate.rs index 461ed8057..2521483cb 100644 --- a/src/uu/truncate/src/truncate.rs +++ b/src/uu/truncate/src/truncate.rs @@ -5,6 +5,7 @@ // spell-checker:ignore (ToDO) RFILE refsize rfilename fsize tsize use clap::{Arg, ArgAction, Command}; +use std::collections::HashMap; use std::fs::{OpenOptions, metadata}; use std::io::ErrorKind; #[cfg(unix)] @@ -13,7 +14,7 @@ use std::path::Path; use uucore::display::Quotable; use uucore::error::{FromIo, UResult, USimpleError, UUsageError}; use uucore::format_usage; -use uucore::locale::get_message; +use uucore::locale::{get_message, get_message_with_args}; use uucore::parser::parse_size::{ParseSizeError, parse_size_u64}; #[derive(Debug, Eq, PartialEq)] @@ -99,7 +100,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .unwrap_or_default(); if files.is_empty() { - Err(UUsageError::new(1, "missing file operand")) + Err(UUsageError::new( + 1, + get_message("truncate-error-missing-file-operand"), + )) } else { let io_blocks = matches.get_flag(options::IO_BLOCKS); let no_create = matches.get_flag(options::NO_CREATE); @@ -121,17 +125,14 @@ pub fn uu_app() -> Command { Arg::new(options::IO_BLOCKS) .short('o') .long(options::IO_BLOCKS) - .help( - "treat SIZE as the number of I/O blocks of the file rather than bytes \ - (NOT IMPLEMENTED)", - ) + .help(get_message("truncate-help-io-blocks")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_CREATE) .short('c') .long(options::NO_CREATE) - .help("do not create files that do not exist") + .help(get_message("truncate-help-no-create")) .action(ArgAction::SetTrue), ) .arg( @@ -139,7 +140,7 @@ pub fn uu_app() -> Command { .short('r') .long(options::REFERENCE) .required_unless_present(options::SIZE) - .help("base the size of each file on the size of RFILE") + .help(get_message("truncate-help-reference")) .value_name("RFILE") .value_hint(clap::ValueHint::FilePath), ) @@ -148,10 +149,7 @@ pub fn uu_app() -> Command { .short('s') .long(options::SIZE) .required_unless_present(options::REFERENCE) - .help( - "set or adjust the size of each file according to SIZE, which is in \ - bytes unless --io-blocks is specified", - ) + .help(get_message("truncate-help-size")) .value_name("SIZE"), ) .arg( @@ -181,20 +179,26 @@ fn file_truncate(filename: &str, create: bool, size: u64) -> UResult<()> { if metadata.file_type().is_fifo() { return Err(USimpleError::new( 1, - format!( - "cannot open {} for writing: No such device or address", - filename.quote() + get_message_with_args( + "truncate-error-cannot-open-no-device", + HashMap::from([("filename".to_string(), filename.quote().to_string())]), ), )); } } + let path = Path::new(filename); match OpenOptions::new().write(true).create(create).open(path) { Ok(file) => file.set_len(size), Err(e) if e.kind() == ErrorKind::NotFound && !create => Ok(()), Err(e) => Err(e), } - .map_err_context(|| format!("cannot open {} for writing", filename.quote())) + .map_err_context(|| { + get_message_with_args( + "truncate-error-cannot-open-for-writing", + HashMap::from([("filename".to_string(), filename.quote().to_string())]), + ) + }) } /// Truncate files to a size relative to a given file. @@ -221,33 +225,49 @@ fn truncate_reference_and_size( create: bool, ) -> UResult<()> { let mode = match parse_mode_and_size(size_string) { - Err(e) => return Err(USimpleError::new(1, format!("Invalid number: {e}"))), + Err(e) => { + return Err(USimpleError::new( + 1, + get_message_with_args( + "truncate-error-invalid-number", + HashMap::from([("error".to_string(), e.to_string())]), + ), + )); + } Ok(TruncateMode::Absolute(_)) => { return Err(USimpleError::new( 1, - String::from("you must specify a relative '--size' with '--reference'"), + get_message("truncate-error-must-specify-relative-size"), )); } Ok(m) => m, }; + if let TruncateMode::RoundDown(0) | TruncateMode::RoundUp(0) = mode { - return Err(USimpleError::new(1, "division by zero")); + return Err(USimpleError::new( + 1, + get_message("truncate-error-division-by-zero"), + )); } + let metadata = metadata(rfilename).map_err(|e| match e.kind() { ErrorKind::NotFound => USimpleError::new( 1, - format!( - "cannot stat {}: No such file or directory", - rfilename.quote() + get_message_with_args( + "truncate-error-cannot-stat-no-such-file", + HashMap::from([("filename".to_string(), rfilename.quote().to_string())]), ), ), _ => e.map_err_context(String::new), })?; + let fsize = metadata.len(); let tsize = mode.to_size(fsize); + for filename in filenames { file_truncate(filename, create, tsize)?; } + Ok(()) } @@ -272,17 +292,20 @@ fn truncate_reference_file_only( let metadata = metadata(rfilename).map_err(|e| match e.kind() { ErrorKind::NotFound => USimpleError::new( 1, - format!( - "cannot stat {}: No such file or directory", - rfilename.quote() + get_message_with_args( + "truncate-error-cannot-stat-no-such-file", + HashMap::from([("filename".to_string(), rfilename.quote().to_string())]), ), ), _ => e.map_err_context(String::new), })?; + let tsize = metadata.len(); + for filename in filenames { file_truncate(filename, create, tsize)?; } + Ok(()) } @@ -304,11 +327,23 @@ fn truncate_reference_file_only( /// /// If at least one file is a named pipe (also known as a fifo). fn truncate_size_only(size_string: &str, filenames: &[String], create: bool) -> UResult<()> { - let mode = parse_mode_and_size(size_string) - .map_err(|e| USimpleError::new(1, format!("Invalid number: {e}")))?; + let mode = parse_mode_and_size(size_string).map_err(|e| { + USimpleError::new( + 1, + get_message_with_args( + "truncate-error-invalid-number", + HashMap::from([("error".to_string(), e.to_string())]), + ), + ) + })?; + if let TruncateMode::RoundDown(0) | TruncateMode::RoundUp(0) = mode { - return Err(USimpleError::new(1, "division by zero")); + return Err(USimpleError::new( + 1, + get_message("truncate-error-division-by-zero"), + )); } + for filename in filenames { let fsize = match metadata(filename) { Ok(m) => { @@ -316,9 +351,9 @@ fn truncate_size_only(size_string: &str, filenames: &[String], create: bool) -> if m.file_type().is_fifo() { return Err(USimpleError::new( 1, - format!( - "cannot open {} for writing: No such device or address", - filename.quote() + get_message_with_args( + "truncate-error-cannot-open-no-device", + HashMap::from([("filename".to_string(), filename.quote().to_string())]), ), )); } @@ -330,6 +365,7 @@ fn truncate_size_only(size_string: &str, filenames: &[String], create: bool) -> // TODO: Fix duplicate call to stat file_truncate(filename, create, tsize)?; } + Ok(()) } @@ -341,6 +377,7 @@ fn truncate( filenames: &[String], ) -> UResult<()> { let create = !no_create; + // There are four possibilities // - reference file given and size given, // - reference file given but no size given,