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

l10n: port rm for translation + add french

This commit is contained in:
Sylvestre Ledru 2025-06-23 19:05:15 +02:00
parent 05eb7ee374
commit e79bc8790b
5 changed files with 181 additions and 41 deletions

1
Cargo.lock generated
View file

@ -3388,6 +3388,7 @@ version = "0.1.0"
dependencies = [
"clap",
"libc",
"thiserror 2.0.12",
"uucore",
"windows-sys 0.60.2",
]

View file

@ -18,6 +18,7 @@ workspace = true
path = "src/rm.rs"
[dependencies]
thiserror = { workspace = true }
clap = { workspace = true }
uucore = { workspace = true, features = ["fs"] }

View file

@ -12,3 +12,35 @@ rm-after-help = By default, rm does not remove directories. Use the --recursive
Note that if you use rm to remove a file, it might be possible to recover
some of its contents, given sufficient expertise and/or time. For greater
assurance that the contents are truly unrecoverable, consider using shred.
# Help text for options
rm-help-force = ignore nonexistent files and arguments, never prompt
rm-help-prompt-always = prompt before every removal
rm-help-prompt-once = prompt once before removing more than three files, or when removing recursively.
Less intrusive than -i, while still giving some protection against most mistakes
rm-help-interactive = prompt according to WHEN: never, once (-I), or always (-i). Without WHEN,
prompts always
rm-help-one-file-system = when removing a hierarchy recursively, skip any directory that is on a file
system different from that of the corresponding command line argument (NOT
IMPLEMENTED)
rm-help-no-preserve-root = do not treat '/' specially
rm-help-preserve-root = do not remove '/' (default)
rm-help-recursive = remove directories and their contents recursively
rm-help-dir = remove empty directories
rm-help-verbose = explain what is being done
# Error messages
rm-error-missing-operand = missing operand
Try '{$util_name} --help' for more information.
rm-error-invalid-interactive-argument = Invalid argument to interactive ({$arg})
rm-error-cannot-remove-no-such-file = cannot remove {$file}: No such file or directory
rm-error-cannot-remove-permission-denied = cannot remove {$file}: Permission denied
rm-error-cannot-remove-is-directory = cannot remove {$file}: Is a directory
rm-error-dangerous-recursive-operation = it is dangerous to operate recursively on '/'
rm-error-use-no-preserve-root = use --no-preserve-root to override this failsafe
rm-error-refusing-to-remove-directory = refusing to remove '.' or '..' directory: skipping '{$path}'
rm-error-cannot-remove = cannot remove {$file}
# Verbose messages
rm-verbose-removed = removed {$file}
rm-verbose-removed-directory = removed directory {$file}

View file

@ -0,0 +1,46 @@
rm-about = Supprimer (délier) le(s) FICHIER(s)
rm-usage = rm [OPTION]... FICHIER...
rm-after-help = Par défaut, rm ne supprime pas les répertoires. Utilisez l'option --recursive (-r ou -R)
pour supprimer également chaque répertoire listé, ainsi que tout son contenu
Pour supprimer un fichier dont le nom commence par un '-', par exemple '-foo',
utilisez une de ces commandes :
rm -- -foo
rm ./-foo
Notez que si vous utilisez rm pour supprimer un fichier, il pourrait être possible de récupérer
une partie de son contenu, avec suffisamment d'expertise et/ou de temps. Pour une meilleure
assurance que le contenu est vraiment irrécupérable, considérez utiliser shred.
# Texte d'aide pour les options
rm-help-force = ignorer les fichiers inexistants et les arguments, ne jamais demander
rm-help-prompt-always = demander avant chaque suppression
rm-help-prompt-once = demander une fois avant de supprimer plus de trois fichiers, ou lors d'une suppression récursive.
Moins intrusif que -i, tout en offrant une protection contre la plupart des erreurs
rm-help-interactive = demander selon QUAND : never, once (-I), ou always (-i). Sans QUAND,
demande toujours
rm-help-one-file-system = lors de la suppression récursive d'une hiérarchie, ignorer tout répertoire situé sur un
système de fichiers différent de celui de l'argument de ligne de commande correspondant (NON
IMPLÉMENTÉ)
rm-help-no-preserve-root = ne pas traiter '/' spécialement
rm-help-preserve-root = ne pas supprimer '/' (par défaut)
rm-help-recursive = supprimer les répertoires et leur contenu récursivement
rm-help-dir = supprimer les répertoires vides
rm-help-verbose = expliquer ce qui est fait
# Messages d'erreur
rm-error-missing-operand = opérande manquant
Essayez '{$util_name} --help' pour plus d'informations.
rm-error-invalid-interactive-argument = Argument invalide pour interactive ({$arg})
rm-error-cannot-remove-no-such-file = impossible de supprimer {$file} : Aucun fichier ou répertoire de ce type
rm-error-cannot-remove-permission-denied = impossible de supprimer {$file} : Permission refusée
rm-error-cannot-remove-is-directory = impossible de supprimer {$file} : C'est un répertoire
rm-error-dangerous-recursive-operation = il est dangereux d'opérer récursivement sur '/'
rm-error-use-no-preserve-root = utilisez --no-preserve-root pour outrepasser cette protection
rm-error-refusing-to-remove-directory = refus de supprimer le répertoire '.' ou '..' : ignorer '{$path}'
rm-error-cannot-remove = impossible de supprimer {$file}
# Messages verbeux
rm-verbose-removed = {$file} supprimé
rm-verbose-removed-directory = répertoire {$file} supprimé

View file

@ -6,6 +6,7 @@
// spell-checker:ignore (path) eacces inacc rm-r4
use clap::{Arg, ArgAction, Command, builder::ValueParser, parser::ValueSource};
use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::fs::{self, Metadata};
use std::io::{IsTerminal, stdin};
@ -16,11 +17,38 @@ use std::os::unix::ffi::OsStrExt;
use std::os::unix::fs::PermissionsExt;
use std::path::MAIN_SEPARATOR;
use std::path::{Path, PathBuf};
use thiserror::Error;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
use uucore::locale::get_message;
use uucore::error::{FromIo, UError, UResult};
use uucore::locale::{get_message, get_message_with_args};
use uucore::{format_usage, os_str_as_bytes, prompt_yes, show_error};
#[derive(Debug, Error)]
enum RmError {
#[error("{}", get_message_with_args("rm-error-missing-operand",
HashMap::from([
("util_name".to_string(),
uucore::execution_phrase().to_string())
])))]
MissingOperand,
#[error("{}", get_message_with_args("rm-error-invalid-interactive-argument", HashMap::from([("arg".to_string(), _0.clone())])))]
InvalidInteractiveArgument(String),
#[error("{}", get_message_with_args("rm-error-cannot-remove-no-such-file", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
CannotRemoveNoSuchFile(String),
#[error("{}", get_message_with_args("rm-error-cannot-remove-permission-denied", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
CannotRemovePermissionDenied(String),
#[error("{}", get_message_with_args("rm-error-cannot-remove-is-directory", HashMap::from([("file".to_string(), _0.quote().to_string())])))]
CannotRemoveIsDirectory(String),
#[error("{}", get_message("rm-error-dangerous-recursive-operation"))]
DangerousRecursiveOperation,
#[error("{}", get_message("rm-error-use-no-preserve-root"))]
UseNoPreserveRoot,
#[error("{}", get_message_with_args("rm-error-refusing-to-remove-directory", HashMap::from([("path".to_string(), _0.to_string())])))]
RefusingToRemoveDirectory(String),
}
impl UError for RmError {}
#[derive(Eq, PartialEq, Clone, Copy)]
/// Enum, determining when the `rm` will prompt the user about the file deletion
pub enum InteractiveMode {
@ -117,7 +145,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if files.is_empty() && !force_flag {
// Still check by hand and not use clap
// Because "rm -f" is a thing
return Err(UUsageError::new(1, "missing operand"));
return Err(RmError::MissingOperand.into());
}
// If -f(--force) is before any -i (or variants) we want prompts else no prompts
@ -146,10 +174,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
"once" => InteractiveMode::Once,
"always" => InteractiveMode::Always,
val => {
return Err(USimpleError::new(
1,
format!("Invalid argument to interactive ({val})"),
));
return Err(RmError::InvalidInteractiveArgument(val.to_string()).into());
}
}
} else {
@ -206,31 +231,27 @@ pub fn uu_app() -> Command {
Arg::new(OPT_FORCE)
.short('f')
.long(OPT_FORCE)
.help("ignore nonexistent files and arguments, never prompt")
.help(get_message("rm-help-force"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_PROMPT_ALWAYS)
.short('i')
.help("prompt before every removal")
.help(get_message("rm-help-prompt-always"))
.overrides_with_all([OPT_PROMPT_ONCE, OPT_INTERACTIVE])
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_PROMPT_ONCE)
.short('I')
.help("prompt once before removing more than three files, or when removing recursively. \
Less intrusive than -i, while still giving some protection against most mistakes")
.help(get_message("rm-help-prompt-once"))
.overrides_with_all([OPT_PROMPT_ALWAYS, OPT_INTERACTIVE])
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_INTERACTIVE)
.long(OPT_INTERACTIVE)
.help(
"prompt according to WHEN: never, once (-I), or always (-i). Without WHEN, \
prompts always",
)
.help(get_message("rm-help-interactive"))
.value_name("WHEN")
.num_args(0..=1)
.require_equals(true)
@ -240,22 +261,19 @@ pub fn uu_app() -> Command {
.arg(
Arg::new(OPT_ONE_FILE_SYSTEM)
.long(OPT_ONE_FILE_SYSTEM)
.help(
"when removing a hierarchy recursively, skip any directory that is on a file \
system different from that of the corresponding command line argument (NOT \
IMPLEMENTED)",
).action(ArgAction::SetTrue),
.help(get_message("rm-help-one-file-system"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_NO_PRESERVE_ROOT)
.long(OPT_NO_PRESERVE_ROOT)
.help("do not treat '/' specially")
.help(get_message("rm-help-no-preserve-root"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_PRESERVE_ROOT)
.long(OPT_PRESERVE_ROOT)
.help("do not remove '/' (default)")
.help(get_message("rm-help-preserve-root"))
.action(ArgAction::SetTrue),
)
.arg(
@ -263,21 +281,21 @@ pub fn uu_app() -> Command {
.short('r')
.visible_short_alias('R')
.long(OPT_RECURSIVE)
.help("remove directories and their contents recursively")
.help(get_message("rm-help-recursive"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_DIR)
.short('d')
.long(OPT_DIR)
.help("remove empty directories")
.help(get_message("rm-help-dir"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(OPT_VERBOSE)
.short('v')
.long(OPT_VERBOSE)
.help("explain what is being done")
.help(get_message("rm-help-verbose"))
.action(ArgAction::SetTrue),
)
// From the GNU source code:
@ -337,8 +355,8 @@ pub fn remove(files: &[&OsStr], options: &Options) -> bool {
false
} else {
show_error!(
"cannot remove {}: No such file or directory",
filename.quote()
"{}",
RmError::CannotRemoveNoSuchFile(filename.to_string_lossy().to_string())
);
true
}
@ -425,7 +443,12 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
match fs::remove_dir_all(path) {
Ok(_) => return false,
Err(e) => {
let e = e.map_err_context(|| format!("cannot remove {}", path.quote()));
let e = e.map_err_context(|| {
get_message_with_args(
"rm-error-cannot-remove",
HashMap::from([("file".to_string(), path.quote().to_string())]),
)
});
show_error!("{e}");
return true;
}
@ -487,7 +510,12 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
error = true;
}
Err(e) if !error => {
let e = e.map_err_context(|| format!("cannot remove {}", path.quote()));
let e = e.map_err_context(|| {
get_message_with_args(
"rm-error-cannot-remove",
HashMap::from([("file".to_string(), path.quote().to_string())]),
)
});
show_error!("{e}");
error = true;
}
@ -497,7 +525,13 @@ fn remove_dir_recursive(path: &Path, options: &Options) -> bool {
// show another error message as we return from each level
// of the recursion.
}
Ok(_) if options.verbose => println!("removed directory {}", normalize(path).quote()),
Ok(_) if options.verbose => println!(
"{}",
get_message_with_args(
"rm-verbose-removed-directory",
HashMap::from([("file".to_string(), normalize(path).quote().to_string())])
)
),
Ok(_) => {}
}
@ -510,8 +544,8 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
let path = clean_trailing_slashes(path);
if path_is_current_or_parent_directory(path) {
show_error!(
"refusing to remove '.' or '..' directory: skipping '{}'",
path.display()
"{}",
RmError::RefusingToRemoveDirectory(path.display().to_string())
);
return true;
}
@ -522,13 +556,13 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
} else if options.dir && (!is_root || !options.preserve_root) {
had_err = remove_dir(path, options).bitor(had_err);
} else if options.recursive {
show_error!("it is dangerous to operate recursively on '{MAIN_SEPARATOR}'");
show_error!("use --no-preserve-root to override this failsafe");
show_error!("{}", RmError::DangerousRecursiveOperation);
show_error!("{}", RmError::UseNoPreserveRoot);
had_err = true;
} else {
show_error!(
"cannot remove {}: Is a directory", // GNU's rm error message does not include help
path.quote()
"{}",
RmError::CannotRemoveIsDirectory(path.to_string_lossy().to_string())
);
had_err = true;
}
@ -547,7 +581,10 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
// Called to remove a symlink_dir (windows) without "-r"/"-R" or "-d".
if !options.dir && !options.recursive {
show_error!("cannot remove {}: Is a directory", path.quote());
show_error!(
"{}",
RmError::CannotRemoveIsDirectory(path.to_string_lossy().to_string())
);
return true;
}
@ -555,12 +592,23 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
match fs::remove_dir(path) {
Ok(_) => {
if options.verbose {
println!("removed directory {}", normalize(path).quote());
println!(
"{}",
get_message_with_args(
"rm-verbose-removed-directory",
HashMap::from([("file".to_string(), normalize(path).quote().to_string())])
)
);
}
false
}
Err(e) => {
let e = e.map_err_context(|| format!("cannot remove {}", path.quote()));
let e = e.map_err_context(|| {
get_message_with_args(
"rm-error-cannot-remove",
HashMap::from([("file".to_string(), path.quote().to_string())]),
)
});
show_error!("{e}");
true
}
@ -572,13 +620,25 @@ fn remove_file(path: &Path, options: &Options) -> bool {
match fs::remove_file(path) {
Ok(_) => {
if options.verbose {
println!("removed {}", normalize(path).quote());
println!(
"{}",
get_message_with_args(
"rm-verbose-removed",
HashMap::from([(
"file".to_string(),
normalize(path).quote().to_string()
)])
)
);
}
}
Err(e) => {
if e.kind() == std::io::ErrorKind::PermissionDenied {
// GNU compatibility (rm/fail-eacces.sh)
show_error!("cannot remove {}: {}", path.quote(), "Permission denied");
show_error!(
"{}",
RmError::CannotRemovePermissionDenied(path.to_string_lossy().to_string())
);
} else {
show_error!("cannot remove {}: {e}", path.quote());
}