diagnostics: translation infrastructure
An implementation of the infrastructure required to have translatable diagnostic messages.
- Introduces a `DiagnosticMessage` type which can represent both the current non-translatable messages and identifiers for [Fluent](https://projectfluent.org/).
- Modifies current diagnostic API so that existing calls still work but `DiagnosticMessage`s can be provided too.
- Adds support for always loading a "fallback bundle" containing the English diagnostic messages, which are used when a `DiagnosticMessage::FluentIdentifier` is used in a diagnostic being emitted.
- Adds support for loading a "primary bundle" which contains the user's preferred language translation, and is used preferentially when it contains a diagnostic message being emitted. Primary bundles are loaded either from the path provided to `-Ztranslate-alternate-ftl` (for testing), or from the sysroot at `$sysroot/locale/$locale/*.ftl` given a locale with `-Ztranslate-lang` (which is parsed as a language identifier).
- Adds "diagnostic args" which enable normally-interpolated variables to be made available as variables for Fluent messages to use.
- Updates `#[derive(SessionDiagnostic)]` so that it can only be used for translatable diagnostics and update the handful of diagnostics which used the derive to be translatable.
For example, the following diagnostic...
```rust
#[derive(SessionDiagnostic)]
#[error = "E0195"]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"]
#[label = "lifetimes do not match {item_kind} in trait"]
pub span: Span,
#[label = "lifetimes in impl do not match this {item_kind} in trait"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
```
...becomes...
```rust
#[derive(SessionDiagnostic)]
#[error(code = "E0195", slug = "typeck-lifetimes-or-bounds-mismatch-on-trait")]
pub struct LifetimesOrBoundsMismatchOnTrait {
#[primary_span]
#[label]
pub span: Span,
#[label = "generics-label"]
pub generics_span: Option<Span>,
pub item_kind: &'static str,
pub ident: Ident,
}
```
```fluent
typeck-lifetimes-or-bounds-mismatch-on-trait =
lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
.label = lifetimes do not match {$item_kind} in trait
.generics-label = lifetimes in impl do not match this {$item_kind} in trait
```
r? `@estebank`
cc `@oli-obk` `@Manishearth`