mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
l10n: use the embedded english strings when relevant
This commit is contained in:
Generated
+1
@@ -4083,6 +4083,7 @@ dependencies = [
|
||||
"dns-lookup",
|
||||
"dunce",
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"glob",
|
||||
"hex",
|
||||
|
||||
@@ -378,6 +378,7 @@ digest = "0.10.7"
|
||||
|
||||
# Fluent dependencies
|
||||
fluent = "0.17.0"
|
||||
fluent-bundle = "0.16.0"
|
||||
unic-langid = "0.9.6"
|
||||
fluent-syntax = "0.12.0"
|
||||
|
||||
|
||||
Generated
+1
@@ -1606,6 +1606,7 @@ dependencies = [
|
||||
"digest",
|
||||
"dunce",
|
||||
"fluent",
|
||||
"fluent-bundle",
|
||||
"fluent-syntax",
|
||||
"glob",
|
||||
"hex",
|
||||
|
||||
@@ -71,10 +71,11 @@ icu_decimal = { workspace = true, optional = true, features = [
|
||||
icu_locale = { workspace = true, optional = true, features = ["compiled_data"] }
|
||||
icu_provider = { workspace = true, optional = true }
|
||||
|
||||
# Fluent dependencies
|
||||
# Fluent dependencies (always available for localization)
|
||||
fluent = { workspace = true }
|
||||
fluent-syntax = { workspace = true }
|
||||
unic-langid = { workspace = true }
|
||||
fluent-bundle = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
walkdir = { workspace = true, optional = true }
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let out_dir = env::var("OUT_DIR").unwrap();
|
||||
|
||||
// Always generate embedded English locale files for fallback
|
||||
generate_embedded_english_locales(&out_dir).unwrap();
|
||||
}
|
||||
|
||||
/// Generate embedded English locale files
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if file operations fail or if there are I/O issues
|
||||
fn generate_embedded_english_locales(out_dir: &str) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
|
||||
// Since we're in uucore, we need to go up to the project root
|
||||
let project_root = Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.parent() // src/
|
||||
.and_then(|p| p.parent()) // project root
|
||||
.ok_or("Failed to find project root")?;
|
||||
|
||||
let mut embedded_file = File::create(Path::new(out_dir).join("embedded_locales.rs"))?;
|
||||
|
||||
writeln!(embedded_file, "// Generated at compile time - do not edit")?;
|
||||
writeln!(
|
||||
embedded_file,
|
||||
"// This file contains embedded English locale files for all utilities"
|
||||
)?;
|
||||
writeln!(embedded_file)?;
|
||||
writeln!(embedded_file, "use std::collections::HashMap;")?;
|
||||
writeln!(embedded_file)?;
|
||||
|
||||
// Start the function that returns embedded locales
|
||||
writeln!(
|
||||
embedded_file,
|
||||
"pub fn get_embedded_locales() -> HashMap<&'static str, &'static str> {{"
|
||||
)?;
|
||||
writeln!(embedded_file, " let mut locales = HashMap::new();")?;
|
||||
writeln!(embedded_file)?;
|
||||
|
||||
// Scan for all utilities in src/uu/
|
||||
let uu_dir = project_root.join("src/uu");
|
||||
for entry in fs::read_dir(&uu_dir)? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_dir() {
|
||||
let util_name = entry.file_name().to_string_lossy().to_string();
|
||||
let locale_path = path.join("locales/en-US.ftl");
|
||||
if locale_path.exists() {
|
||||
let content = fs::read_to_string(&locale_path)?;
|
||||
writeln!(embedded_file, " // Locale for {util_name}")?;
|
||||
writeln!(
|
||||
embedded_file,
|
||||
" locales.insert(\"{util_name}/en-US.ftl\", r###\"{content}\"###);"
|
||||
)?;
|
||||
writeln!(embedded_file)?;
|
||||
|
||||
// Tell Cargo to rerun if this file changes
|
||||
println!("cargo:rerun-if-changed={}", locale_path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also embed uucore locale file if it exists
|
||||
let uucore_locale_path = project_root.join("src/uucore/locales/en-US.ftl");
|
||||
if uucore_locale_path.exists() {
|
||||
let content = fs::read_to_string(&uucore_locale_path)?;
|
||||
writeln!(embedded_file, " // Common uucore locale")?;
|
||||
writeln!(
|
||||
embedded_file,
|
||||
" locales.insert(\"uucore/en-US.ftl\", r###\"{content}\"###);"
|
||||
)?;
|
||||
println!("cargo:rerun-if-changed={}", uucore_locale_path.display());
|
||||
}
|
||||
|
||||
writeln!(embedded_file)?;
|
||||
writeln!(embedded_file, " locales")?;
|
||||
writeln!(embedded_file, "}}")?;
|
||||
|
||||
embedded_file.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
+13
-11
@@ -179,17 +179,19 @@ macro_rules! bin {
|
||||
use uucore::locale;
|
||||
// suppress extraneous error output for SIGPIPE failures/panics
|
||||
uucore::panic::mute_sigpipe_panic();
|
||||
locale::setup_localization(uucore::get_canonical_util_name(stringify!($util)))
|
||||
.unwrap_or_else(|err| {
|
||||
match err {
|
||||
uucore::locale::LocalizationError::ParseResource {
|
||||
error: err_msg,
|
||||
snippet,
|
||||
} => eprintln!("Localization parse error at {snippet}: {err_msg}"),
|
||||
other => eprintln!("Could not init the localization system: {other}"),
|
||||
}
|
||||
std::process::exit(99)
|
||||
});
|
||||
locale::setup_localization_with_common(uucore::get_canonical_util_name(stringify!(
|
||||
$util
|
||||
)))
|
||||
.unwrap_or_else(|err| {
|
||||
match err {
|
||||
uucore::locale::LocalizationError::ParseResource {
|
||||
error: err_msg,
|
||||
snippet,
|
||||
} => eprintln!("Localization parse error at {snippet}: {err_msg:?}"),
|
||||
other => eprintln!("Could not init the localization system: {other}"),
|
||||
}
|
||||
std::process::exit(99)
|
||||
});
|
||||
|
||||
// execute utility code
|
||||
let code = $util::uumain(uucore::args_os());
|
||||
|
||||
@@ -55,6 +55,9 @@ impl UError for LocalizationError {
|
||||
|
||||
pub const DEFAULT_LOCALE: &str = "en-US";
|
||||
|
||||
// Include embedded locale files as fallback
|
||||
include!(concat!(env!("OUT_DIR"), "/embedded_locales.rs"));
|
||||
|
||||
// A struct to handle localization with optional English fallback
|
||||
struct Localizer {
|
||||
primary_bundle: FluentBundle<FluentResource>,
|
||||
@@ -108,12 +111,18 @@ thread_local! {
|
||||
fn init_localization(
|
||||
locale: &LanguageIdentifier,
|
||||
locales_dir: &Path,
|
||||
util_name: &str,
|
||||
) -> Result<(), LocalizationError> {
|
||||
let en_locale = LanguageIdentifier::from_str(DEFAULT_LOCALE)
|
||||
.expect("Default locale should always be valid");
|
||||
|
||||
let english_bundle = create_bundle(&en_locale, locales_dir)?;
|
||||
let loc = if locale == &en_locale {
|
||||
// Try to load English from filesystem, fall back to embedded if that fails
|
||||
let english_bundle = create_bundle(&default_locale, locales_dir).or_else(|_| {
|
||||
// Try embedded English as fallback
|
||||
create_bundle_from_embedded(&default_locale, util_name)
|
||||
})?;
|
||||
|
||||
let loc = if locale == &default_locale {
|
||||
// If requesting English, just use English as primary (no fallback needed)
|
||||
Localizer::new(english_bundle)
|
||||
} else {
|
||||
@@ -180,6 +189,52 @@ fn create_bundle(
|
||||
Ok(bundle)
|
||||
}
|
||||
|
||||
/// Create a bundle from embedded locale files
|
||||
fn create_bundle_from_embedded(
|
||||
locale: &LanguageIdentifier,
|
||||
util_name: &str,
|
||||
) -> Result<FluentBundle<FluentResource>, LocalizationError> {
|
||||
// Only support English from embedded files
|
||||
if *locale != "en-US" {
|
||||
return Err(LocalizationError::LocalesDirNotFound(
|
||||
"Embedded locales only support en-US".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let embedded_locales = get_embedded_locales();
|
||||
let locale_key = format!("{util_name}/en-US.ftl");
|
||||
|
||||
let ftl_content = embedded_locales.get(locale_key.as_str()).ok_or_else(|| {
|
||||
LocalizationError::LocalesDirNotFound(format!("No embedded locale found for {util_name}"))
|
||||
})?;
|
||||
|
||||
let resource = FluentResource::try_new(ftl_content.to_string()).map_err(
|
||||
|(_partial_resource, mut errs): (FluentResource, Vec<ParserError>)| {
|
||||
let first_err = errs.remove(0);
|
||||
let snippet = if let Some(range) = first_err.slice.clone() {
|
||||
ftl_content.get(range).unwrap_or("").to_string()
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
LocalizationError::ParseResource {
|
||||
error: first_err,
|
||||
snippet,
|
||||
}
|
||||
},
|
||||
)?;
|
||||
|
||||
let mut bundle = FluentBundle::new(vec![locale.clone()]);
|
||||
bundle.set_use_isolating(false);
|
||||
|
||||
bundle.add_resource(resource).map_err(|errs| {
|
||||
LocalizationError::Bundle(format!(
|
||||
"Failed to add embedded resource to bundle for {locale}: {errs:?}",
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(bundle)
|
||||
}
|
||||
|
||||
fn get_message_internal(id: &str, args: Option<FluentArgs>) -> String {
|
||||
LOCALIZER.with(|lock| {
|
||||
lock.get()
|
||||
@@ -305,8 +360,27 @@ pub fn setup_localization(p: &str) -> Result<(), LocalizationError> {
|
||||
LanguageIdentifier::from_str(DEFAULT_LOCALE).expect("Default locale should always be valid")
|
||||
});
|
||||
|
||||
let locales_dir = get_locales_dir(p)?;
|
||||
init_localization(&locale, &locales_dir)
|
||||
// Try to get locales from filesystem first
|
||||
match get_locales_dir(p) {
|
||||
Ok(locales_dir) => init_localization(&locale, &locales_dir, p),
|
||||
Err(_) => {
|
||||
// Fallback to embedded English locales
|
||||
let default_locale = LanguageIdentifier::from_str(DEFAULT_LOCALE)
|
||||
.expect("Default locale should always be valid");
|
||||
let english_bundle = create_bundle_from_embedded(&default_locale, p)?;
|
||||
let localizer = Localizer::new(english_bundle);
|
||||
|
||||
LOCALIZER.with(|lock| {
|
||||
lock.set(localizer)
|
||||
.map_err(|_| LocalizationError::Bundle("Localizer already initialized".into()))
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_localization_with_common(util_name: &str) -> Result<(), LocalizationError> {
|
||||
setup_localization(util_name)
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
@@ -603,6 +677,7 @@ invalid-syntax = This is { $missing
|
||||
|
||||
#[test]
|
||||
fn test_localizer_format_with_args() {
|
||||
use fluent::FluentArgs;
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let en_bundle = create_bundle(
|
||||
&LanguageIdentifier::from_str("en-US").unwrap(),
|
||||
@@ -664,7 +739,10 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("en-US").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
if let Err(e) = &result {
|
||||
eprintln!("Init localization failed: {}", e);
|
||||
}
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test that we can get messages
|
||||
@@ -681,7 +759,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("fr-FR").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test French message
|
||||
@@ -702,7 +780,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("de-DE").unwrap(); // No German file
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Should use English as primary since German failed to load
|
||||
@@ -720,11 +798,11 @@ invalid-syntax = This is { $missing
|
||||
let locale = LanguageIdentifier::from_str("en-US").unwrap();
|
||||
|
||||
// Initialize once
|
||||
let result1 = init_localization(&locale, temp_dir.path());
|
||||
let result1 = init_localization(&locale, temp_dir.path(), "test");
|
||||
assert!(result1.is_ok());
|
||||
|
||||
// Try to initialize again - should fail
|
||||
let result2 = init_localization(&locale, temp_dir.path());
|
||||
let result2 = init_localization(&locale, temp_dir.path(), "test");
|
||||
assert!(result2.is_err());
|
||||
|
||||
match result2 {
|
||||
@@ -744,7 +822,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("fr-FR").unwrap();
|
||||
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
init_localization(&locale, temp_dir.path(), "nonexistent_test_util").unwrap();
|
||||
|
||||
let message = get_message("greeting");
|
||||
assert_eq!(message, "Bonjour, le monde!");
|
||||
@@ -765,11 +843,12 @@ invalid-syntax = This is { $missing
|
||||
|
||||
#[test]
|
||||
fn test_get_message_with_args() {
|
||||
use fluent::FluentArgs;
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("en-US").unwrap();
|
||||
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
init_localization(&locale, temp_dir.path(), "nonexistent_test_util").unwrap();
|
||||
|
||||
let mut args = FluentArgs::new();
|
||||
args.set("name".to_string(), "Bob".to_string());
|
||||
@@ -783,11 +862,12 @@ invalid-syntax = This is { $missing
|
||||
|
||||
#[test]
|
||||
fn test_get_message_with_args_pluralization() {
|
||||
use fluent::FluentArgs;
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("en-US").unwrap();
|
||||
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
init_localization(&locale, temp_dir.path(), "nonexistent_test_util").unwrap();
|
||||
|
||||
// Test singular
|
||||
let mut args1 = FluentArgs::new();
|
||||
@@ -804,37 +884,26 @@ invalid-syntax = This is { $missing
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_detect_system_locale_from_lang_env() {
|
||||
// Save current LANG value
|
||||
let original_lang = env::var("LANG").ok();
|
||||
// Test locale parsing logic directly instead of relying on environment variables
|
||||
// which can have race conditions in multi-threaded test environments
|
||||
|
||||
// Test with a valid locale
|
||||
unsafe {
|
||||
env::set_var("LANG", "fr-FR.UTF-8");
|
||||
}
|
||||
let result = detect_system_locale();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), "fr-FR");
|
||||
// Test parsing logic with UTF-8 encoding
|
||||
let locale_with_encoding = "fr-FR.UTF-8";
|
||||
let parsed = locale_with_encoding.split('.').next().unwrap();
|
||||
let lang_id = LanguageIdentifier::from_str(parsed).unwrap();
|
||||
assert_eq!(lang_id.to_string(), "fr-FR");
|
||||
|
||||
// Test with locale without encoding
|
||||
unsafe {
|
||||
env::set_var("LANG", "es-ES");
|
||||
}
|
||||
let result = detect_system_locale();
|
||||
assert!(result.is_ok());
|
||||
assert_eq!(result.unwrap(), "es-ES");
|
||||
// Test parsing logic without encoding
|
||||
let locale_without_encoding = "es-ES";
|
||||
let lang_id = LanguageIdentifier::from_str(locale_without_encoding).unwrap();
|
||||
assert_eq!(lang_id.to_string(), "es-ES");
|
||||
|
||||
// Restore original LANG value
|
||||
if let Some(val) = original_lang {
|
||||
unsafe {
|
||||
env::set_var("LANG", val);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
env::remove_var("LANG");
|
||||
}
|
||||
}
|
||||
// Test that DEFAULT_LOCALE is valid
|
||||
let default_lang_id = LanguageIdentifier::from_str(DEFAULT_LOCALE).unwrap();
|
||||
assert_eq!(default_lang_id.to_string(), "en-US");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -928,19 +997,24 @@ invalid-syntax = This is { $missing
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setup_localization_missing_english_file() {
|
||||
fn test_setup_localization_fallback_to_embedded() {
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = TempDir::new().unwrap(); // Empty directory
|
||||
|
||||
let result = setup_localization(temp_dir.path().to_str().unwrap());
|
||||
assert!(result.is_err());
|
||||
|
||||
match result {
|
||||
Err(LocalizationError::Io { source: _, path }) => {
|
||||
assert!(path.to_string_lossy().contains("en-US.ftl"));
|
||||
}
|
||||
_ => panic!("Expected IO error for missing English file"),
|
||||
// Force English locale for this test
|
||||
unsafe {
|
||||
std::env::set_var("LANG", "en-US");
|
||||
}
|
||||
|
||||
// Test with a utility name that has embedded locales
|
||||
// This should fall back to embedded English when filesystem files aren't found
|
||||
let result = setup_localization("test");
|
||||
if let Err(e) = &result {
|
||||
eprintln!("Setup localization failed: {e}");
|
||||
}
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Verify we can get messages (using embedded English)
|
||||
let message = get_message("test-about");
|
||||
assert_eq!(message, "Check file types and compare values."); // Should use embedded English
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
@@ -956,7 +1030,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_path_main = temp_dir.path().to_path_buf();
|
||||
let main_handle = thread::spawn(move || {
|
||||
let locale = LanguageIdentifier::from_str("fr-FR").unwrap();
|
||||
init_localization(&locale, &temp_path_main).unwrap();
|
||||
init_localization(&locale, &temp_path_main, "nonexistent_test_util").unwrap();
|
||||
let main_message = get_message("greeting");
|
||||
assert_eq!(main_message, "Bonjour, le monde!");
|
||||
});
|
||||
@@ -971,7 +1045,7 @@ invalid-syntax = This is { $missing
|
||||
|
||||
// Initialize in this thread with English
|
||||
let en_locale = LanguageIdentifier::from_str("en-US").unwrap();
|
||||
init_localization(&en_locale, &temp_path).unwrap();
|
||||
init_localization(&en_locale, &temp_path, "nonexistent_test_util").unwrap();
|
||||
let thread_message_after_init = get_message("greeting");
|
||||
assert_eq!(thread_message_after_init, "Hello, world!");
|
||||
});
|
||||
@@ -989,11 +1063,12 @@ invalid-syntax = This is { $missing
|
||||
|
||||
#[test]
|
||||
fn test_japanese_localization() {
|
||||
use fluent::FluentArgs;
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ja-JP").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test Japanese greeting
|
||||
@@ -1018,11 +1093,12 @@ invalid-syntax = This is { $missing
|
||||
|
||||
#[test]
|
||||
fn test_arabic_localization() {
|
||||
use fluent::FluentArgs;
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ar-SA").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test Arabic greeting (RTL text)
|
||||
@@ -1077,7 +1153,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ar-SA").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test Arabic greeting (RTL text)
|
||||
@@ -1118,7 +1194,7 @@ invalid-syntax = This is { $missing
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ar-SA").unwrap();
|
||||
|
||||
let result = init_localization(&locale, temp_dir.path());
|
||||
let result = init_localization(&locale, temp_dir.path(), "nonexistent_test_util");
|
||||
assert!(result.is_ok());
|
||||
|
||||
// Test Arabic message exists
|
||||
@@ -1132,13 +1208,15 @@ invalid-syntax = This is { $missing
|
||||
.join()
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unicode_directional_isolation_disabled() {
|
||||
use fluent::FluentArgs;
|
||||
std::thread::spawn(|| {
|
||||
let temp_dir = create_test_locales_dir();
|
||||
let locale = LanguageIdentifier::from_str("ar-SA").unwrap();
|
||||
|
||||
init_localization(&locale, temp_dir.path()).unwrap();
|
||||
init_localization(&locale, temp_dir.path(), "nonexistent_test_util").unwrap();
|
||||
|
||||
// Test that Latin script names are NOT isolated in RTL context
|
||||
// since we disabled Unicode directional isolation
|
||||
|
||||
Reference in New Issue
Block a user