138 lines
5.8 KiB
Rust
138 lines
5.8 KiB
Rust
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<'_> {}
|