mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
l10n: Use FluentArgs instead of HashMap directly
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
use crate::error::UError;
|
||||
use fluent::{FluentArgs, FluentBundle, FluentResource};
|
||||
use fluent_syntax::parser::ParserError;
|
||||
use std::collections::HashMap;
|
||||
use std::fs;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
@@ -238,32 +237,18 @@ pub fn get_message(id: &str) -> String {
|
||||
///
|
||||
/// ```
|
||||
/// use uucore::locale::get_message_with_args;
|
||||
/// use std::collections::HashMap;
|
||||
/// use fluent::FluentArgs;
|
||||
///
|
||||
/// // For a Fluent message like: "Hello, { $name }! You have { $count } notifications."
|
||||
/// let mut args = HashMap::new();
|
||||
/// args.insert("name".to_string(), "Alice".to_string());
|
||||
/// args.insert("count".to_string(), "3".to_string());
|
||||
/// let mut args = FluentArgs::new();
|
||||
/// args.set("name".to_string(), "Alice".to_string());
|
||||
/// args.set("count".to_string(), 3);
|
||||
///
|
||||
/// let message = get_message_with_args("notification", args);
|
||||
/// println!("{message}");
|
||||
/// ```
|
||||
pub fn get_message_with_args(id: &str, ftl_args: HashMap<String, String>) -> String {
|
||||
let mut args = FluentArgs::new();
|
||||
|
||||
for (key, value) in ftl_args {
|
||||
// Try to parse as number first for proper pluralization support
|
||||
if let Ok(num_val) = value.parse::<i64>() {
|
||||
args.set(key, num_val);
|
||||
} else if let Ok(float_val) = value.parse::<f64>() {
|
||||
args.set(key, float_val);
|
||||
} else {
|
||||
// Keep as string if not a number
|
||||
args.set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
get_message_internal(id, Some(args))
|
||||
pub fn get_message_with_args(id: &str, ftl_args: FluentArgs) -> String {
|
||||
get_message_internal(id, Some(ftl_args))
|
||||
}
|
||||
|
||||
/// Function to detect system locale from environment variables
|
||||
@@ -416,6 +401,7 @@ fn get_locales_dir(p: &str) -> Result<PathBuf, LocalizationError> {
|
||||
///
|
||||
/// ```
|
||||
/// use uucore::translate;
|
||||
/// use fluent::FluentArgs;
|
||||
///
|
||||
/// // Simple message without arguments
|
||||
/// let greeting = translate!("greeting");
|
||||
@@ -443,9 +429,17 @@ macro_rules! translate {
|
||||
// Case 2: Message ID with key-value arguments
|
||||
($id:expr, $($key:expr => $value:expr),+ $(,)?) => {
|
||||
{
|
||||
let mut args = std::collections::HashMap::new();
|
||||
let mut args = fluent::FluentArgs::new();
|
||||
$(
|
||||
args.insert($key.to_string(), $value.to_string());
|
||||
let value_str = $value.to_string();
|
||||
if let Ok(num_val) = value_str.parse::<i64>() {
|
||||
args.set($key, num_val);
|
||||
} else if let Ok(float_val) = value_str.parse::<f64>() {
|
||||
args.set($key, float_val);
|
||||
} else {
|
||||
// Keep as string if not a number
|
||||
args.set($key, value_str);
|
||||
}
|
||||
)+
|
||||
$crate::locale::get_message_with_args($id, args)
|
||||
}
|
||||
@@ -458,7 +452,6 @@ pub use translate;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
@@ -778,8 +771,8 @@ invalid-syntax = This is { $missing
|
||||
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
|
||||
let mut args = HashMap::new();
|
||||
args.insert("name".to_string(), "Bob".to_string());
|
||||
let mut args = FluentArgs::new();
|
||||
args.set("name".to_string(), "Bob".to_string());
|
||||
|
||||
let message = get_message_with_args("welcome", args);
|
||||
assert_eq!(message, "Welcome, Bob!");
|
||||
@@ -797,14 +790,14 @@ invalid-syntax = This is { $missing
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
|
||||
// Test singular
|
||||
let mut args1 = HashMap::new();
|
||||
args1.insert("count".to_string(), "1".to_string());
|
||||
let mut args1 = FluentArgs::new();
|
||||
args1.set("count", 1);
|
||||
let message1 = get_message_with_args("count-items", args1);
|
||||
assert_eq!(message1, "You have 1 item");
|
||||
|
||||
// Test plural
|
||||
let mut args2 = HashMap::new();
|
||||
args2.insert("count".to_string(), "5".to_string());
|
||||
let mut args2 = FluentArgs::new();
|
||||
args2.set("count", 5);
|
||||
let message2 = get_message_with_args("count-items", args2);
|
||||
assert_eq!(message2, "You have 5 items");
|
||||
})
|
||||
@@ -1008,14 +1001,14 @@ invalid-syntax = This is { $missing
|
||||
assert_eq!(message, "こんにちは、世界!");
|
||||
|
||||
// Test Japanese with arguments
|
||||
let mut args = HashMap::new();
|
||||
args.insert("name".to_string(), "田中".to_string());
|
||||
let mut args = FluentArgs::new();
|
||||
args.set("name".to_string(), "田中".to_string());
|
||||
let welcome = get_message_with_args("welcome", args);
|
||||
assert_eq!(welcome, "ようこそ、田中さん!");
|
||||
|
||||
// Test Japanese count (no pluralization)
|
||||
let mut count_args = HashMap::new();
|
||||
count_args.insert("count".to_string(), "5".to_string());
|
||||
let mut count_args = FluentArgs::new();
|
||||
count_args.set("count".to_string(), "5".to_string());
|
||||
let count_message = get_message_with_args("count-items", count_args);
|
||||
assert_eq!(count_message, "5個のアイテムがあります");
|
||||
})
|
||||
@@ -1037,39 +1030,39 @@ invalid-syntax = This is { $missing
|
||||
assert_eq!(message, "أهلاً بالعالم!");
|
||||
|
||||
// Test Arabic with arguments
|
||||
let mut args = HashMap::new();
|
||||
args.insert("name".to_string(), "أحمد".to_string());
|
||||
let mut args = FluentArgs::new();
|
||||
args.set("name", "أحمد".to_string());
|
||||
let welcome = get_message_with_args("welcome", args);
|
||||
|
||||
assert_eq!(welcome, "أهلاً وسهلاً، أحمد!");
|
||||
|
||||
// Test Arabic pluralization (zero case)
|
||||
let mut args_zero = HashMap::new();
|
||||
args_zero.insert("count".to_string(), "0".to_string());
|
||||
let mut args_zero = FluentArgs::new();
|
||||
args_zero.set("count", 0);
|
||||
let message_zero = get_message_with_args("count-items", args_zero);
|
||||
assert_eq!(message_zero, "لديك لا عناصر");
|
||||
|
||||
// Test Arabic pluralization (one case)
|
||||
let mut args_one = HashMap::new();
|
||||
args_one.insert("count".to_string(), "1".to_string());
|
||||
let mut args_one = FluentArgs::new();
|
||||
args_one.set("count", 1);
|
||||
let message_one = get_message_with_args("count-items", args_one);
|
||||
assert_eq!(message_one, "لديك عنصر واحد");
|
||||
|
||||
// Test Arabic pluralization (two case)
|
||||
let mut args_two = HashMap::new();
|
||||
args_two.insert("count".to_string(), "2".to_string());
|
||||
let mut args_two = FluentArgs::new();
|
||||
args_two.set("count", 2);
|
||||
let message_two = get_message_with_args("count-items", args_two);
|
||||
assert_eq!(message_two, "لديك عنصران");
|
||||
|
||||
// Test Arabic pluralization (few case - 3-10)
|
||||
let mut args_few = HashMap::new();
|
||||
args_few.insert("count".to_string(), "5".to_string());
|
||||
let mut args_few = FluentArgs::new();
|
||||
args_few.set("count", 5);
|
||||
let message_few = get_message_with_args("count-items", args_few);
|
||||
assert_eq!(message_few, "لديك 5 عناصر");
|
||||
|
||||
// Test Arabic pluralization (other case - 11+)
|
||||
let mut args_many = HashMap::new();
|
||||
args_many.insert("count".to_string(), "15".to_string());
|
||||
let mut args_many = FluentArgs::new();
|
||||
args_many.set("count", 15);
|
||||
let message_many = get_message_with_args("count-items", args_many);
|
||||
assert_eq!(message_many, "لديك 15 عنصر");
|
||||
})
|
||||
@@ -1077,6 +1070,48 @@ invalid-syntax = This is { $missing
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_arabic_localization_with_macro() {
|
||||
std::thread::spawn(|| {
|
||||
use self::translate;
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ar-SA").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test Arabic greeting (RTL text)
|
||||
let message = translate!("greeting");
|
||||
assert_eq!(message, "أهلاً بالعالم!");
|
||||
|
||||
// Test Arabic with arguments
|
||||
let welcome = translate!("welcome", "name" => "أحمد");
|
||||
assert_eq!(welcome, "أهلاً وسهلاً، أحمد!");
|
||||
|
||||
// Test Arabic pluralization (zero case)
|
||||
let message_zero = translate!("count-items", "count" => 0);
|
||||
assert_eq!(message_zero, "لديك لا عناصر");
|
||||
|
||||
// Test Arabic pluralization (one case)
|
||||
let message_one = translate!("count-items", "count" => 1);
|
||||
assert_eq!(message_one, "لديك عنصر واحد");
|
||||
|
||||
// Test Arabic pluralization (two case)
|
||||
let message_two = translate!("count-items", "count" => 2);
|
||||
assert_eq!(message_two, "لديك عنصران");
|
||||
|
||||
// Test Arabic pluralization (few case - 3-10)
|
||||
let message_few = translate!("count-items", "count" => 5);
|
||||
assert_eq!(message_few, "لديك 5 عناصر");
|
||||
|
||||
// Test Arabic pluralization (other case - 11+)
|
||||
let message_many = translate!("count-items", "count" => 15);
|
||||
assert_eq!(message_many, "لديك 15 عنصر");
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mixed_script_fallback() {
|
||||
std::thread::spawn(|| {
|
||||
@@ -1107,8 +1142,8 @@ invalid-syntax = This is { $missing
|
||||
|
||||
// Test that Latin script names are NOT isolated in RTL context
|
||||
// since we disabled Unicode directional isolation
|
||||
let mut args = HashMap::new();
|
||||
args.insert("name".to_string(), "John Smith".to_string());
|
||||
let mut args = FluentArgs::new();
|
||||
args.set("name".to_string(), "John Smith".to_string());
|
||||
let message = get_message_with_args("welcome", args);
|
||||
|
||||
// The Latin name should NOT be wrapped in directional isolate characters
|
||||
|
||||
Reference in New Issue
Block a user