diff --git a/src/uu/ln/locales/en-US.ftl b/src/uu/ln/locales/en-US.ftl index 7de0c171e..85315070d 100644 --- a/src/uu/ln/locales/en-US.ftl +++ b/src/uu/ln/locales/en-US.ftl @@ -11,3 +11,28 @@ ln-after-help = In the 1st form, create a link to TARGET with the name LINK_NAME When creating hard links, each TARGET must exist. Symbolic links can hold arbitrary text; if later resolved, a relative link is interpreted in relation to its parent directory. + +ln-help-force = remove existing destination files +ln-help-interactive = prompt whether to remove existing destination files +ln-help-no-dereference = treat LINK_NAME as a normal file if it is a + symbolic link to a directory +ln-help-logical = follow TARGETs that are symbolic links +ln-help-physical = make hard links directly to symbolic links +ln-help-symbolic = make symbolic links instead of hard links +ln-help-target-directory = specify the DIRECTORY in which to create the links +ln-help-no-target-directory = treat LINK_NAME as a normal file always +ln-help-relative = create symbolic links relative to link location +ln-help-verbose = print name of each linked file +ln-error-target-is-not-directory = target {$target} is not a directory +ln-error-same-file = {$file1} and {$file2} are the same file +ln-error-missing-destination = missing destination file operand after {$operand} +ln-error-extra-operand = extra operand {$operand} + Try '{$program} --help' for more information. +ln-error-could-not-update = Could not update {$target}: {$error} +ln-error-cannot-stat = cannot stat {$path}: No such file or directory +ln-error-will-not-overwrite = will not overwrite just-created '{$target}' with '{$source}' +ln-prompt-replace = replace {$file}? +ln-cannot-backup = cannot backup {$file} +ln-failed-to-access = failed to access {$file} +ln-failed-to-create-hard-link = failed to create hard link {$source} => {$dest} +ln-backup = backup: {$backup} diff --git a/src/uu/ln/locales/fr-FR.ftl b/src/uu/ln/locales/fr-FR.ftl new file mode 100644 index 000000000..483f15c92 --- /dev/null +++ b/src/uu/ln/locales/fr-FR.ftl @@ -0,0 +1,39 @@ +ln-about = Créer des liens entre fichiers +ln-usage = ln [OPTION]... [-T] CIBLE NOM_LIEN + ln [OPTION]... CIBLE + ln [OPTION]... CIBLE... RÉPERTOIRE + ln [OPTION]... -t RÉPERTOIRE CIBLE... +ln-after-help = Dans la 1ère forme, créer un lien vers CIBLE avec le nom NOM_LIEN. + Dans la 2ème forme, créer un lien vers CIBLE dans le répertoire courant. + Dans les 3ème et 4ème formes, créer des liens vers chaque CIBLE dans RÉPERTOIRE. + Créer des liens physiques par défaut, des liens symboliques avec --symbolic. + Par défaut, chaque destination (nom du nouveau lien) ne doit pas déjà exister. + Lors de la création de liens physiques, chaque CIBLE doit exister. Les liens symboliques + peuvent contenir du texte arbitraire ; s'ils sont résolus plus tard, un lien relatif est + interprété en relation avec son répertoire parent. + +ln-help-force = supprimer les fichiers de destination existants +ln-help-interactive = demander avant de supprimer les fichiers de destination existants +ln-help-no-dereference = traiter NOM_LIEN comme un fichier normal s'il s'agit d'un + lien symbolique vers un répertoire +ln-help-logical = suivre les CIBLEs qui sont des liens symboliques +ln-help-physical = créer des liens physiques directement vers les liens symboliques +ln-help-symbolic = créer des liens symboliques au lieu de liens physiques +ln-help-target-directory = spécifier le RÉPERTOIRE dans lequel créer les liens +ln-help-no-target-directory = toujours traiter NOM_LIEN comme un fichier normal +ln-help-relative = créer des liens symboliques relatifs à l'emplacement du lien +ln-help-verbose = afficher le nom de chaque fichier lié + +ln-error-target-is-not-directory = la cible {$target} n'est pas un répertoire +ln-error-same-file = {$file1} et {$file2} sont le même fichier +ln-error-missing-destination = opérande de fichier de destination manquant après {$operand} +ln-error-extra-operand = opérande supplémentaire {$operand} + Essayez « {$program} --help » pour plus d'informations. +ln-error-could-not-update = Impossible de mettre à jour {$target} : {$error} +ln-error-cannot-stat = impossible d'analyser {$path} : Aucun fichier ou répertoire de ce nom +ln-error-will-not-overwrite = ne remplacera pas le fichier « {$target} » qui vient d'être créé par « {$source} » +ln-prompt-replace = remplacer {$file} ? +ln-cannot-backup = impossible de sauvegarder {$file} +ln-failed-to-access = échec d'accès à {$file} +ln-failed-to-create-hard-link = échec de création du lien physique {$source} => {$dest} +ln-backup = sauvegarde : {$backup} diff --git a/src/uu/ln/src/ln.rs b/src/uu/ln/src/ln.rs index 960085200..cadc805ca 100644 --- a/src/uu/ln/src/ln.rs +++ b/src/uu/ln/src/ln.rs @@ -17,6 +17,7 @@ use std::ffi::OsString; use std::fs; use thiserror::Error; +use std::collections::HashMap; #[cfg(any(unix, target_os = "redox"))] use std::os::unix::fs::symlink; #[cfg(windows)] @@ -24,7 +25,7 @@ use std::os::windows::fs::{symlink_dir, symlink_file}; use std::path::{Path, PathBuf}; use uucore::backup_control::{self, BackupMode}; use uucore::fs::{MissingHandling, ResolveMode, canonicalize}; -use uucore::locale::get_message; +use uucore::locale::{get_message, get_message_with_args}; pub struct Settings { overwrite: OverwriteMode, @@ -48,20 +49,19 @@ pub enum OverwriteMode { #[derive(Error, Debug)] enum LnError { - #[error("target {} is not a directory", _0.quote())] + #[error("{}", get_message_with_args("ln-error-target-is-not-directory", HashMap::from([("target".to_string(), _0.quote().to_string())])))] TargetIsNotADirectory(PathBuf), #[error("")] SomeLinksFailed, - #[error("{} and {} are the same file", _0.quote(), _1.quote())] + #[error("{}", get_message_with_args("ln-error-same-file", HashMap::from([("file1".to_string(), _0.quote().to_string()), ("file2".to_string(), _1.quote().to_string())])))] SameFile(PathBuf, PathBuf), - #[error("missing destination file operand after {}", _0.quote())] + #[error("{}", get_message_with_args("ln-error-missing-destination", HashMap::from([("operand".to_string(), _0.quote().to_string())])))] MissingDestination(PathBuf), - #[error("extra operand {}\nTry '{} --help' for more information.", - format!("{_0:?}").trim_matches('"'), _1)] + #[error("{}", get_message_with_args("ln-error-extra-operand", HashMap::from([("operand".to_string(), format!("{_0:?}").trim_matches('"').to_string()), ("program".to_string(), _1.clone())])))] ExtraOperand(OsString, String), } @@ -157,31 +157,28 @@ pub fn uu_app() -> Command { Arg::new(options::FORCE) .short('f') .long(options::FORCE) - .help("remove existing destination files") + .help(get_message("ln-help-force")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::INTERACTIVE) .short('i') .long(options::INTERACTIVE) - .help("prompt whether to remove existing destination files") + .help(get_message("ln-help-interactive")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::NO_DEREFERENCE) .short('n') .long(options::NO_DEREFERENCE) - .help( - "treat LINK_NAME as a normal file if it is a \ - symbolic link to a directory", - ) + .help(get_message("ln-help-no-dereference")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::LOGICAL) .short('L') .long(options::LOGICAL) - .help("follow TARGETs that are symbolic links") + .help(get_message("ln-help-logical")) .overrides_with(options::PHYSICAL) .action(ArgAction::SetTrue), ) @@ -190,14 +187,14 @@ pub fn uu_app() -> Command { Arg::new(options::PHYSICAL) .short('P') .long(options::PHYSICAL) - .help("make hard links directly to symbolic links") + .help(get_message("ln-help-physical")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::SYMBOLIC) .short('s') .long(options::SYMBOLIC) - .help("make symbolic links instead of hard links") + .help(get_message("ln-help-symbolic")) // override added for https://github.com/uutils/coreutils/issues/2359 .overrides_with(options::SYMBOLIC) .action(ArgAction::SetTrue), @@ -207,7 +204,7 @@ pub fn uu_app() -> Command { Arg::new(options::TARGET_DIRECTORY) .short('t') .long(options::TARGET_DIRECTORY) - .help("specify the DIRECTORY in which to create the links") + .help(get_message("ln-help-target-directory")) .value_name("DIRECTORY") .value_hint(clap::ValueHint::DirPath) .conflicts_with(options::NO_TARGET_DIRECTORY), @@ -216,14 +213,14 @@ pub fn uu_app() -> Command { Arg::new(options::NO_TARGET_DIRECTORY) .short('T') .long(options::NO_TARGET_DIRECTORY) - .help("treat LINK_NAME as a normal file always") + .help(get_message("ln-help-no-target-directory")) .action(ArgAction::SetTrue), ) .arg( Arg::new(options::RELATIVE) .short('r') .long(options::RELATIVE) - .help("create symbolic links relative to link location") + .help(get_message("ln-help-relative")) .requires(options::SYMBOLIC) .action(ArgAction::SetTrue), ) @@ -231,7 +228,7 @@ pub fn uu_app() -> Command { Arg::new(options::VERBOSE) .short('v') .long(options::VERBOSE) - .help("print name of each linked file") + .help(get_message("ln-help-verbose")) .action(ArgAction::SetTrue), ) .arg( @@ -296,7 +293,16 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) // We need to clean the target if target_dir.is_file() { if let Err(e) = fs::remove_file(target_dir) { - show_error!("Could not update {}: {e}", target_dir.quote()); + show_error!( + "{}", + get_message_with_args( + "ln-error-could-not-update", + HashMap::from([ + ("target".to_string(), target_dir.quote().to_string()), + ("error".to_string(), e.to_string()) + ]) + ) + ); }; } #[cfg(windows)] @@ -305,7 +311,16 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) // considered as a dir // See test_ln::test_symlink_no_deref_dir if let Err(e) = fs::remove_dir(target_dir) { - show_error!("Could not update {}: {e}", target_dir.quote()); + show_error!( + "{}", + get_message_with_args( + "ln-error-could-not-update", + HashMap::from([ + ("target".to_string(), target_dir.quote().to_string()), + ("error".to_string(), e.to_string()) + ]) + ) + ); }; } target_dir.to_path_buf() @@ -322,7 +337,13 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) } } None => { - show_error!("cannot stat {}: No such file or directory", srcpath.quote()); + show_error!( + "{}", + get_message_with_args( + "ln-error-cannot-stat", + HashMap::from([("path".to_string(), srcpath.quote().to_string())]) + ) + ); all_successful = false; continue; } @@ -332,9 +353,14 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) if linked_destinations.contains(&targetpath) { // If the target file was already created in this ln call, do not overwrite show_error!( - "will not overwrite just-created '{}' with '{}'", - targetpath.display(), - srcpath.display() + "{}", + get_message_with_args( + "ln-error-will-not-overwrite", + HashMap::from([ + ("target".to_string(), targetpath.display().to_string()), + ("source".to_string(), srcpath.display().to_string()) + ]) + ) ); all_successful = false; } else if let Err(e) = link(srcpath, &targetpath, settings) { @@ -387,12 +413,23 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> { } } if let Some(ref p) = backup_path { - fs::rename(dst, p).map_err_context(|| format!("cannot backup {}", dst.quote()))?; + fs::rename(dst, p).map_err_context(|| { + get_message_with_args( + "ln-cannot-backup", + HashMap::from([("file".to_string(), dst.quote().to_string())]), + ) + })?; } match settings.overwrite { OverwriteMode::NoClobber => {} OverwriteMode::Interactive => { - if !prompt_yes!("replace {}?", dst.quote()) { + if !prompt_yes!( + "{}", + get_message_with_args( + "ln-prompt-replace", + HashMap::from([("file".to_string(), dst.quote().to_string())]) + ) + ) { return Err(LnError::SomeLinksFailed.into()); } @@ -416,16 +453,22 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> { // if we want to have an hard link, // source is a symlink and -L is passed // we want to resolve the symlink to create the hardlink - fs::canonicalize(&source) - .map_err_context(|| format!("failed to access {}", source.quote()))? + fs::canonicalize(&source).map_err_context(|| { + get_message_with_args( + "ln-failed-to-access", + HashMap::from([("file".to_string(), source.quote().to_string())]), + ) + })? } else { source.to_path_buf() }; fs::hard_link(p, dst).map_err_context(|| { - format!( - "failed to create hard link {} => {}", - source.quote(), - dst.quote() + get_message_with_args( + "ln-failed-to-create-hard-link", + HashMap::from([ + ("source".to_string(), source.quote().to_string()), + ("dest".to_string(), dst.quote().to_string()), + ]), ) })?; } @@ -433,7 +476,13 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> UResult<()> { if settings.verbose { print!("{} -> {}", dst.quote(), source.quote()); match backup_path { - Some(path) => println!(" (backup: {})", path.quote()), + Some(path) => println!( + " ({})", + get_message_with_args( + "ln-backup", + HashMap::from([("backup".to_string(), path.quote().to_string())]) + ) + ), None => println!(), } }