diff --git a/fluent-bundle/src/resolver/pattern.rs b/fluent-bundle/src/resolver/pattern.rs index 7768d151..4e01d4ca 100644 --- a/fluent-bundle/src/resolver/pattern.rs +++ b/fluent-bundle/src/resolver/pattern.rs @@ -49,15 +49,16 @@ impl<'p> WriteValue for ast::Pattern<&'p str> { let needs_isolation = scope.bundle.use_isolating && len > 1 - && !matches!(expression, ast::Expression::Inline( - ast::InlineExpression::MessageReference { .. }, - ) - | ast::Expression::Inline( - ast::InlineExpression::TermReference { .. }, - ) - | ast::Expression::Inline( - ast::InlineExpression::StringLiteral { .. }, - )); + && !matches!( + expression, + ast::Expression::Inline(ast::InlineExpression::MessageReference { .. },) + | ast::Expression::Inline( + ast::InlineExpression::TermReference { .. }, + ) + | ast::Expression::Inline( + ast::InlineExpression::StringLiteral { .. }, + ) + ); if needs_isolation { w.write_char('\u{2068}')?; } diff --git a/fluent-bundle/tests/custom_types.rs b/fluent-bundle/tests/custom_types.rs index 4a740c22..be534700 100644 --- a/fluent-bundle/tests/custom_types.rs +++ b/fluent-bundle/tests/custom_types.rs @@ -11,7 +11,7 @@ fn fluent_custom_type() { #[derive(Debug, PartialEq)] struct DateTime { epoch: usize, - }; + } impl DateTime { pub fn new(epoch: usize) -> Self { @@ -108,7 +108,7 @@ fn fluent_date_time_builtin() { struct DateTime { epoch: usize, options: DateTimeOptions, - }; + } impl DateTime { pub fn new(epoch: usize, options: DateTimeOptions) -> Self { diff --git a/fluent-fallback/src/errors.rs b/fluent-fallback/src/errors.rs index a65555f1..a7eedb5d 100644 --- a/fluent-fallback/src/errors.rs +++ b/fluent-fallback/src/errors.rs @@ -1,12 +1,17 @@ use fluent_bundle::FluentError; use std::error::Error; +use unic_langid::LanguageIdentifier; #[derive(Debug, PartialEq)] pub enum LocalizationError { Bundle { - id: Option, error: FluentError, }, + Resolver { + id: String, + locale: LanguageIdentifier, + errors: Vec, + }, MissingMessage { id: String, }, @@ -16,29 +21,26 @@ pub enum LocalizationError { SyncRequestInAsyncMode, } -impl From<(I, FluentError)> for LocalizationError { - fn from(pieces: (I, FluentError)) -> Self { - Self::Bundle { - id: Some(pieces.0.to_string()), - error: pieces.1, - } - } -} - impl From for LocalizationError { fn from(error: FluentError) -> Self { - Self::Bundle { id: None, error } + Self::Bundle { error } } } impl std::fmt::Display for LocalizationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::Bundle { - id: Some(id), - error, - } => write!(f, "Bundle {} error: {}", id, error), - Self::Bundle { id: None, error } => write!(f, "Bundle error: {}", error), + Self::Bundle { error } => write!(f, "Bundle error: {}", error), + Self::Resolver { id, locale, errors } => { + let errors: Vec = errors.iter().map(|err| err.to_string()).collect(); + write!( + f, + "[resolver] errors in {}/{}: {}", + id, + locale.to_string(), + errors.join(", ") + ) + } Self::MissingMessage { id } => write!(f, "Missing message: {}", id), Self::MissingValue { id } => write!(f, "Missing value in message: {}", id), Self::SyncRequestInAsyncMode => { diff --git a/fluent-fallback/src/localization.rs b/fluent-fallback/src/localization.rs index d07d6d8c..0c446b3c 100644 --- a/fluent-fallback/src/localization.rs +++ b/fluent-fallback/src/localization.rs @@ -274,7 +274,6 @@ where keys: &'l [L10nKey<'l>], errors: &mut Vec, ) -> Vec>> { - let mut format_errors = vec![]; let mut result: Vec> = Vec::with_capacity(keys.len()); for _ in 0..keys.len() { @@ -295,10 +294,19 @@ where .zip(&mut result) .filter(|(_, cell)| cell.is_none()) { + let mut format_errors = vec![]; let msg = Self::format_message_from_bundle(bundle, key, &mut format_errors); if msg.is_none() { has_missing = true; + } else { + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: key.id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } } *cell = msg; @@ -308,7 +316,6 @@ where break; } } - errors.extend(format_errors.into_iter().map(Into::into)); if !is_complete { for (key, _) in keys @@ -330,7 +337,6 @@ where keys: &'l [L10nKey<'l>], errors: &mut Vec, ) -> Vec>> { - let mut format_errors = vec![]; let mut result: Vec>> = Vec::with_capacity(keys.len()); for _ in 0..keys.len() { @@ -354,11 +360,19 @@ where { if let Some(msg) = bundle.get_message(&key.id) { if let Some(value) = msg.value() { + let mut format_errors = vec![]; *cell = Some(bundle.format_pattern( value, key.args.as_ref(), &mut format_errors, )); + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: key.id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } } else { errors.push(LocalizationError::MissingValue { id: key.id.to_string(), @@ -374,8 +388,6 @@ where } } - errors.extend(format_errors.into_iter().map(Into::into)); - if !is_complete { for (key, _) in keys .iter() @@ -407,7 +419,13 @@ where if let Some(value) = msg.value() { let mut format_errors = vec![]; let result = bundle.format_pattern(value, args, &mut format_errors); - errors.extend(format_errors.into_iter().map(Into::into)); + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } return Some(result); } else { errors.push(LocalizationError::MissingValue { id: id.to_string() }); @@ -430,8 +448,6 @@ where keys: &'l [L10nKey<'l>], errors: &mut Vec, ) -> Vec>> { - let mut format_errors = vec![]; - let mut result: Vec> = Vec::with_capacity(keys.len()); for _ in 0..keys.len() { @@ -454,10 +470,20 @@ where .zip(&mut result) .filter(|(_, cell)| cell.is_none()) { + let mut format_errors = vec![]; + let msg = Self::format_message_from_bundle(bundle, key, &mut format_errors); if msg.is_none() { has_missing = true; + } else { + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: key.id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } } *cell = msg; @@ -467,7 +493,6 @@ where break; } } - errors.extend(format_errors.into_iter().map(Into::into)); if !is_complete { for (key, _) in keys @@ -489,8 +514,6 @@ where keys: &'l [L10nKey<'l>], errors: &mut Vec, ) -> Vec>> { - let mut format_errors = vec![]; - let mut result: Vec>> = Vec::with_capacity(keys.len()); for _ in 0..keys.len() { @@ -515,11 +538,19 @@ where { if let Some(msg) = bundle.get_message(&key.id) { if let Some(value) = msg.value() { + let mut format_errors = vec![]; *cell = Some(bundle.format_pattern( value, key.args.as_ref(), &mut format_errors, )); + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: key.id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } } else { errors.push(LocalizationError::MissingValue { id: key.id.to_string(), @@ -535,7 +566,6 @@ where break; } } - errors.extend(format_errors.into_iter().map(Into::into)); if !is_complete { for (key, _) in keys @@ -570,7 +600,13 @@ where if let Some(value) = msg.value() { let mut format_errors = vec![]; let result = bundle.format_pattern(value, args, &mut format_errors); - errors.extend(format_errors.into_iter().map(Into::into)); + if !format_errors.is_empty() { + errors.push(LocalizationError::Resolver { + id: id.to_string(), + locale: bundle.locales.get(0).cloned().unwrap(), + errors: format_errors, + }); + } return Some(result); } else { errors.push(LocalizationError::MissingValue { id: id.to_string() });