| use rustc_error_messages::{ |
| fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}, |
| FluentArgs, FluentError, |
| }; |
| use std::borrow::Cow; |
| use std::error::Error; |
| use std::fmt; |
| |
| #[derive(Debug)] |
| pub enum TranslateError<'args> { |
| One { |
| id: &'args Cow<'args, str>, |
| args: &'args FluentArgs<'args>, |
| kind: TranslateErrorKind<'args>, |
| }, |
| Two { |
| primary: Box<TranslateError<'args>>, |
| fallback: Box<TranslateError<'args>>, |
| }, |
| } |
| |
| impl<'args> TranslateError<'args> { |
| pub fn message(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self { |
| Self::One { id, args, kind: TranslateErrorKind::MessageMissing } |
| } |
| pub fn primary(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self { |
| Self::One { id, args, kind: TranslateErrorKind::PrimaryBundleMissing } |
| } |
| pub fn attribute( |
| id: &'args Cow<'args, str>, |
| args: &'args FluentArgs<'args>, |
| attr: &'args str, |
| ) -> Self { |
| Self::One { id, args, kind: TranslateErrorKind::AttributeMissing { attr } } |
| } |
| pub fn value(id: &'args Cow<'args, str>, args: &'args FluentArgs<'args>) -> Self { |
| Self::One { id, args, kind: TranslateErrorKind::ValueMissing } |
| } |
| |
| pub fn fluent( |
| id: &'args Cow<'args, str>, |
| args: &'args FluentArgs<'args>, |
| errs: Vec<FluentError>, |
| ) -> Self { |
| Self::One { id, args, kind: TranslateErrorKind::Fluent { errs } } |
| } |
| |
| pub fn and(self, fallback: TranslateError<'args>) -> TranslateError<'args> { |
| Self::Two { primary: Box::new(self), fallback: Box::new(fallback) } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub enum TranslateErrorKind<'args> { |
| MessageMissing, |
| PrimaryBundleMissing, |
| AttributeMissing { attr: &'args str }, |
| ValueMissing, |
| Fluent { errs: Vec<FluentError> }, |
| } |
| |
| impl fmt::Display for TranslateError<'_> { |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| use TranslateErrorKind::*; |
| |
| match self { |
| Self::One { id, args, kind } => { |
| writeln!(f, "failed while formatting fluent string `{id}`: ")?; |
| match kind { |
| MessageMissing => writeln!(f, "message was missing")?, |
| PrimaryBundleMissing => writeln!(f, "the primary bundle was missing")?, |
| AttributeMissing { attr } => { |
| writeln!(f, "the attribute `{attr}` was missing")?; |
| writeln!(f, "help: add `.{attr} = <message>`")?; |
| } |
| ValueMissing => writeln!(f, "the value was missing")?, |
| Fluent { errs } => { |
| for err in errs { |
| match err { |
| FluentError::ResolverError(ResolverError::Reference( |
| ReferenceKind::Message { id, .. } |
| | ReferenceKind::Variable { id, .. }, |
| )) => { |
| if args.iter().any(|(arg_id, _)| arg_id == id) { |
| writeln!( |
| f, |
| "argument `{id}` exists but was not referenced correctly" |
| )?; |
| writeln!(f, "help: try using `{{${id}}}` instead")?; |
| } else { |
| writeln!( |
| f, |
| "the fluent string has an argument `{id}` that was not found." |
| )?; |
| let vars: Vec<&str> = |
| args.iter().map(|(a, _v)| a).collect(); |
| match &*vars { |
| [] => writeln!(f, "help: no arguments are available")?, |
| [one] => writeln!( |
| f, |
| "help: the argument `{one}` is available" |
| )?, |
| [first, middle @ .., last] => { |
| write!(f, "help: the arguments `{first}`")?; |
| for a in middle { |
| write!(f, ", `{a}`")?; |
| } |
| writeln!(f, " and `{last}` are available")?; |
| } |
| } |
| } |
| } |
| _ => writeln!(f, "{err}")?, |
| } |
| } |
| } |
| } |
| } |
| // If someone cares about primary bundles, they'll probably notice it's missing |
| // regardless or will be using `debug_assertions` |
| // so we skip the arm below this one to avoid confusing the regular user. |
| Self::Two { primary: box Self::One { kind: PrimaryBundleMissing, .. }, fallback } => { |
| fmt::Display::fmt(fallback, f)?; |
| } |
| Self::Two { primary, fallback } => { |
| writeln!( |
| f, |
| "first, fluent formatting using the primary bundle failed:\n {primary}\n \ |
| while attempting to recover by using the fallback bundle instead, another error occurred:\n{fallback}" |
| )?; |
| } |
| } |
| Ok(()) |
| } |
| } |
| |
| impl Error for TranslateError<'_> {} |