mirror of
https://github.com/uutils/coreutils.git
synced 2025-07-07 21:45:01 +00:00
l10n: port touch for translation + add french
This commit is contained in:
parent
411874f34b
commit
c8066700a2
4 changed files with 173 additions and 51 deletions
|
@ -1,2 +1,29 @@
|
|||
touch-about = Update the access and modification times of each FILE to the current time.
|
||||
touch-usage = touch [OPTION]... [USER]
|
||||
touch-usage = touch [OPTION]... [FILE]...
|
||||
|
||||
# Help messages
|
||||
touch-help-help = Print help information.
|
||||
touch-help-access = change only the access time
|
||||
touch-help-timestamp = use [[CC]YY]MMDDhhmm[.ss] instead of the current time
|
||||
touch-help-date = parse argument and use it instead of current time
|
||||
touch-help-modification = change only the modification time
|
||||
touch-help-no-create = do not create any files
|
||||
touch-help-no-deref = affect each symbolic link instead of any referenced file (only for systems that can change the timestamps of a symlink)
|
||||
touch-help-reference = use this file's times instead of the current time
|
||||
touch-help-time = change only the specified time: "access", "atime", or "use" are equivalent to -a; "modify" or "mtime" are equivalent to -m
|
||||
|
||||
# Error messages
|
||||
touch-error-missing-file-operand = missing file operand
|
||||
Try '{ $help_command } --help' for more information.
|
||||
touch-error-setting-times-of = setting times of { $filename }
|
||||
touch-error-setting-times-no-such-file = setting times of { $filename }: No such file or directory
|
||||
touch-error-cannot-touch = cannot touch { $filename }
|
||||
touch-error-no-such-file-or-directory = No such file or directory
|
||||
touch-error-failed-to-get-attributes = failed to get attributes of { $path }
|
||||
touch-error-setting-times-of-path = setting times of { $path }
|
||||
touch-error-invalid-date-ts-format = invalid date ts format { $date }
|
||||
touch-error-invalid-date-format = invalid date format { $date }
|
||||
touch-error-unable-to-parse-date = Unable to parse date: { $date }
|
||||
touch-error-windows-stdout-path-failed = GetFinalPathNameByHandleW failed with code { $code }
|
||||
touch-error-invalid-filetime = Source has invalid access or modification time: { $time }
|
||||
touch-error-reference-file-inaccessible = failed to get attributes of { $path }: { $error }
|
||||
|
|
30
src/uu/touch/locales/fr-FR.ftl
Normal file
30
src/uu/touch/locales/fr-FR.ftl
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
touch-about = Mettre à jour les temps d'accès et de modification de chaque FICHIER avec l'heure actuelle.
|
||||
touch-usage = touch [OPTION]... [FICHIER]...
|
||||
|
||||
# Messages d'aide
|
||||
touch-help-help = Afficher les informations d'aide.
|
||||
touch-help-access = changer seulement le temps d'accès
|
||||
touch-help-timestamp = utiliser [[CC]AA]MMJJhhmm[.ss] au lieu de l'heure actuelle
|
||||
touch-help-date = analyser l'argument et l'utiliser au lieu de l'heure actuelle
|
||||
touch-help-modification = changer seulement le temps de modification
|
||||
touch-help-no-create = ne créer aucun fichier
|
||||
touch-help-no-deref = affecter chaque lien symbolique au lieu de tout fichier référencé (seulement pour les systèmes qui peuvent changer les horodatages d'un lien symbolique)
|
||||
touch-help-reference = utiliser les temps de ce fichier au lieu de l'heure actuelle
|
||||
touch-help-time = changer seulement le temps spécifié : "access", "atime", ou "use" sont équivalents à -a ; "modify" ou "mtime" sont équivalents à -m
|
||||
|
||||
# Messages d'erreur
|
||||
touch-error-missing-file-operand = opérande de fichier manquant
|
||||
Essayez '{ $help_command } --help' pour plus d'informations.
|
||||
touch-error-setting-times-of = définition des temps de { $filename }
|
||||
touch-error-setting-times-no-such-file = définition des temps de { $filename } : Aucun fichier ou répertoire de ce type
|
||||
touch-error-cannot-touch = impossible de toucher { $filename }
|
||||
touch-error-no-such-file-or-directory = Aucun fichier ou répertoire de ce type
|
||||
touch-error-failed-to-get-attributes = échec d'obtention des attributs de { $path }
|
||||
touch-error-setting-times-of-path = définition des temps de { $path }
|
||||
touch-error-invalid-date-ts-format = format de date ts invalide { $date }
|
||||
touch-error-invalid-date-format = format de date invalide { $date }
|
||||
touch-error-unable-to-parse-date = Impossible d'analyser la date : { $date }
|
||||
touch-error-windows-stdout-path-failed = GetFinalPathNameByHandleW a échoué avec le code { $code }
|
||||
touch-error-invalid-filetime = La source a un temps d'accès ou de modification invalide : { $time }
|
||||
touch-error-reference-file-inaccessible = échec d'obtention des attributs de { $path } : { $error }
|
|
@ -5,26 +5,28 @@
|
|||
|
||||
// spell-checker:ignore (misc) uioerror
|
||||
use filetime::FileTime;
|
||||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
use thiserror::Error;
|
||||
use uucore::display::Quotable;
|
||||
use uucore::error::{UError, UIoError};
|
||||
use uucore::locale::get_message_with_args;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TouchError {
|
||||
#[error("Unable to parse date: {0}")]
|
||||
#[error("{}", get_message_with_args("touch-error-unable-to-parse-date", HashMap::from([("date".to_string(), .0.clone())])))]
|
||||
InvalidDateFormat(String),
|
||||
|
||||
/// The source time couldn't be converted to a [chrono::DateTime]
|
||||
#[error("Source has invalid access or modification time: {0}")]
|
||||
#[error("{}", get_message_with_args("touch-error-invalid-filetime", HashMap::from([("time".to_string(), .0.to_string())])))]
|
||||
InvalidFiletime(FileTime),
|
||||
|
||||
/// The reference file's attributes could not be found or read
|
||||
#[error("failed to get attributes of {}: {}", .0.quote(), to_uioerror(.1))]
|
||||
#[error("{}", get_message_with_args("touch-error-reference-file-inaccessible", HashMap::from([("path".to_string(), .0.quote().to_string()), ("error".to_string(), to_uioerror(.1).to_string())])))]
|
||||
ReferenceFileInaccessible(PathBuf, std::io::Error),
|
||||
|
||||
/// An error getting a path to stdout on Windows
|
||||
#[error("GetFinalPathNameByHandleW failed with code {0}")]
|
||||
#[error("{}", get_message_with_args("touch-error-windows-stdout-path-failed", HashMap::from([("code".to_string(), .0.clone())])))]
|
||||
WindowsStdoutPathError(String),
|
||||
|
||||
/// An error encountered on a specific file
|
||||
|
|
|
@ -16,6 +16,7 @@ use clap::builder::{PossibleValue, ValueParser};
|
|||
use clap::{Arg, ArgAction, ArgGroup, ArgMatches, Command};
|
||||
use filetime::{FileTime, set_file_times, set_symlink_file_times};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
@ -26,7 +27,7 @@ use uucore::parser::shortcut_value_parser::ShortcutValueParser;
|
|||
use uucore::{format_usage, show};
|
||||
|
||||
use crate::error::TouchError;
|
||||
use uucore::locale::get_message;
|
||||
use uucore::locale::{get_message, get_message_with_args};
|
||||
|
||||
/// Options contains all the possible behaviors and flags for touch.
|
||||
///
|
||||
|
@ -192,9 +193,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
.ok_or_else(|| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"missing file operand\nTry '{} --help' for more information.",
|
||||
uucore::execution_phrase()
|
||||
get_message_with_args(
|
||||
"touch-error-missing-file-operand",
|
||||
HashMap::from([(
|
||||
"help_command".to_string(),
|
||||
uucore::execution_phrase().to_string(),
|
||||
)]),
|
||||
),
|
||||
)
|
||||
})?
|
||||
|
@ -263,19 +267,19 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help("Print help information.")
|
||||
.help(get_message("touch-help-help"))
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ACCESS)
|
||||
.short('a')
|
||||
.help("change only the access time")
|
||||
.help(get_message("touch-help-access"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::sources::TIMESTAMP)
|
||||
.short('t')
|
||||
.help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
|
||||
.help(get_message("touch-help-timestamp"))
|
||||
.value_name("STAMP"),
|
||||
)
|
||||
.arg(
|
||||
|
@ -283,38 +287,35 @@ pub fn uu_app() -> Command {
|
|||
.short('d')
|
||||
.long(options::sources::DATE)
|
||||
.allow_hyphen_values(true)
|
||||
.help("parse argument and use it instead of current time")
|
||||
.help(get_message("touch-help-date"))
|
||||
.value_name("STRING")
|
||||
.conflicts_with(options::sources::TIMESTAMP),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::MODIFICATION)
|
||||
.short('m')
|
||||
.help("change only the modification time")
|
||||
.help(get_message("touch-help-modification"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_CREATE)
|
||||
.short('c')
|
||||
.long(options::NO_CREATE)
|
||||
.help("do not create any files")
|
||||
.help(get_message("touch-help-no-create"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::NO_DEREF)
|
||||
.short('h')
|
||||
.long(options::NO_DEREF)
|
||||
.help(
|
||||
"affect each symbolic link instead of any referenced file \
|
||||
(only for systems that can change the timestamps of a symlink)",
|
||||
)
|
||||
.help(get_message("touch-help-no-deref"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::sources::REFERENCE)
|
||||
.short('r')
|
||||
.long(options::sources::REFERENCE)
|
||||
.help("use this file's times instead of the current time")
|
||||
.help(get_message("touch-help-reference"))
|
||||
.value_name("FILE")
|
||||
.value_parser(ValueParser::os_string())
|
||||
.value_hint(clap::ValueHint::AnyPath)
|
||||
|
@ -323,11 +324,7 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::TIME)
|
||||
.long(options::TIME)
|
||||
.help(
|
||||
"change only the specified time: \"access\", \"atime\", or \
|
||||
\"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
|
||||
equivalent to -m",
|
||||
)
|
||||
.help(get_message("touch-help-time"))
|
||||
.value_name("WORD")
|
||||
.value_parser(ShortcutValueParser::new([
|
||||
PossibleValue::new("atime").alias("access").alias("use"),
|
||||
|
@ -442,7 +439,12 @@ fn touch_file(
|
|||
|
||||
if let Err(e) = metadata_result {
|
||||
if e.kind() != ErrorKind::NotFound {
|
||||
return Err(e.map_err_context(|| format!("setting times of {}", filename.quote())));
|
||||
return Err(e.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-setting-times-of",
|
||||
HashMap::from([("filename".to_string(), filename.quote().to_string())]),
|
||||
)
|
||||
}));
|
||||
}
|
||||
|
||||
if opts.no_create {
|
||||
|
@ -452,9 +454,9 @@ fn touch_file(
|
|||
if opts.no_deref {
|
||||
let e = USimpleError::new(
|
||||
1,
|
||||
format!(
|
||||
"setting times of {}: No such file or directory",
|
||||
filename.quote()
|
||||
get_message_with_args(
|
||||
"touch-error-setting-times-no-such-file",
|
||||
HashMap::from([("filename".to_string(), filename.quote().to_string())]),
|
||||
),
|
||||
);
|
||||
if opts.strict {
|
||||
|
@ -475,12 +477,20 @@ fn touch_file(
|
|||
false
|
||||
};
|
||||
if is_directory {
|
||||
let custom_err = Error::other("No such file or directory");
|
||||
return Err(
|
||||
custom_err.map_err_context(|| format!("cannot touch {}", filename.quote()))
|
||||
);
|
||||
let custom_err = Error::other(get_message("touch-error-no-such-file-or-directory"));
|
||||
return Err(custom_err.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-cannot-touch",
|
||||
HashMap::from([("filename".to_string(), filename.quote().to_string())]),
|
||||
)
|
||||
}));
|
||||
}
|
||||
let e = e.map_err_context(|| format!("cannot touch {}", path.quote()));
|
||||
let e = e.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-cannot-touch",
|
||||
HashMap::from([("filename".to_string(), path.quote().to_string())]),
|
||||
)
|
||||
});
|
||||
if opts.strict {
|
||||
return Err(e);
|
||||
}
|
||||
|
@ -543,12 +553,22 @@ fn update_times(
|
|||
ChangeTimes::AtimeOnly => (
|
||||
atime,
|
||||
stat(path, !opts.no_deref)
|
||||
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?
|
||||
.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-failed-to-get-attributes",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
.1,
|
||||
),
|
||||
ChangeTimes::MtimeOnly => (
|
||||
stat(path, !opts.no_deref)
|
||||
.map_err_context(|| format!("failed to get attributes of {}", path.quote()))?
|
||||
.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-failed-to-get-attributes",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())]),
|
||||
)
|
||||
})?
|
||||
.0,
|
||||
mtime,
|
||||
),
|
||||
|
@ -563,7 +583,12 @@ fn update_times(
|
|||
} else {
|
||||
set_file_times(path, atime, mtime)
|
||||
}
|
||||
.map_err_context(|| format!("setting times of {}", path.quote()))
|
||||
.map_err_context(|| {
|
||||
get_message_with_args(
|
||||
"touch-error-setting-times-of-path",
|
||||
HashMap::from([("path".to_string(), path.quote().to_string())]),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get metadata of the provided path
|
||||
|
@ -645,9 +670,15 @@ fn parse_date(ref_time: DateTime<Local>, s: &str) -> Result<FileTime, TouchError
|
|||
/// - 68 and before is interpreted as 20xx
|
||||
/// - 69 and after is interpreted as 19xx
|
||||
fn prepend_century(s: &str) -> UResult<String> {
|
||||
let first_two_digits = s[..2]
|
||||
.parse::<u32>()
|
||||
.map_err(|_| USimpleError::new(1, format!("invalid date ts format {}", s.quote())))?;
|
||||
let first_two_digits = s[..2].parse::<u32>().map_err(|_| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
get_message_with_args(
|
||||
"touch-error-invalid-date-ts-format",
|
||||
HashMap::from([("date".to_string(), s.quote().to_string())]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
Ok(format!(
|
||||
"{}{s}",
|
||||
if first_two_digits > 68 { 19 } else { 20 }
|
||||
|
@ -678,17 +709,30 @@ fn parse_timestamp(s: &str) -> UResult<FileTime> {
|
|||
_ => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date format {}", s.quote()),
|
||||
get_message_with_args(
|
||||
"touch-error-invalid-date-format",
|
||||
HashMap::from([("date".to_string(), s.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
let local = NaiveDateTime::parse_from_str(&ts, format)
|
||||
.map_err(|_| USimpleError::new(1, format!("invalid date ts format {}", ts.quote())))?;
|
||||
let local = NaiveDateTime::parse_from_str(&ts, format).map_err(|_| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
get_message_with_args(
|
||||
"touch-error-invalid-date-ts-format",
|
||||
HashMap::from([("date".to_string(), ts.quote().to_string())]),
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let LocalResult::Single(mut local) = Local.from_local_datetime(&local) else {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date ts format {}", ts.quote()),
|
||||
get_message_with_args(
|
||||
"touch-error-invalid-date-ts-format",
|
||||
HashMap::from([("date".to_string(), ts.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
};
|
||||
|
||||
|
@ -709,7 +753,10 @@ fn parse_timestamp(s: &str) -> UResult<FileTime> {
|
|||
if local.hour() != local2.hour() {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format!("invalid date format {}", s.quote()),
|
||||
get_message_with_args(
|
||||
"touch-error-invalid-date-format",
|
||||
HashMap::from([("date".to_string(), s.quote().to_string())]),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -763,15 +810,22 @@ fn pathbuf_from_stdout() -> Result<PathBuf, TouchError> {
|
|||
|
||||
let buffer_size = match ret {
|
||||
ERROR_PATH_NOT_FOUND | ERROR_NOT_ENOUGH_MEMORY | ERROR_INVALID_PARAMETER => {
|
||||
return Err(TouchError::WindowsStdoutPathError(format!(
|
||||
"GetFinalPathNameByHandleW failed with code {ret}"
|
||||
return Err(TouchError::WindowsStdoutPathError(get_message_with_args(
|
||||
"touch-error-windows-stdout-path-failed",
|
||||
HashMap::from([("code".to_string(), ret.to_string())]),
|
||||
)));
|
||||
}
|
||||
0 => {
|
||||
return Err(TouchError::WindowsStdoutPathError(format!(
|
||||
"GetFinalPathNameByHandleW failed with code {}",
|
||||
// SAFETY: GetLastError is thread-safe and has no documented memory unsafety.
|
||||
unsafe { GetLastError() },
|
||||
return Err(TouchError::WindowsStdoutPathError(get_message_with_args(
|
||||
"touch-error-windows-stdout-path-failed",
|
||||
HashMap::from([(
|
||||
"code".to_string(),
|
||||
format!(
|
||||
"{}",
|
||||
// SAFETY: GetLastError is thread-safe and has no documented memory unsafety.
|
||||
unsafe { GetLastError() }
|
||||
),
|
||||
)]),
|
||||
)));
|
||||
}
|
||||
e => e as usize,
|
||||
|
@ -793,9 +847,18 @@ mod tests {
|
|||
uu_app,
|
||||
};
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::env;
|
||||
#[cfg(windows)]
|
||||
use uucore::locale;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn test_get_pathbuf_from_stdout_fails_if_stdout_is_not_a_file() {
|
||||
unsafe {
|
||||
env::set_var("LANG", "C");
|
||||
}
|
||||
let _ = locale::setup_localization("touch");
|
||||
// We can trigger an error by not setting stdout to anything (will
|
||||
// fail with code 1)
|
||||
assert!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue