@@ -273,40 +273,58 @@ pub trait Emitter {
273273 DiagnosticMessage :: FluentIdentifier ( identifier, attr) => ( identifier, attr) ,
274274 } ;
275275
276- let bundle = match self . fluent_bundle ( ) {
277- Some ( bundle) if bundle. has_message ( & identifier) => bundle,
278- _ => self . fallback_fluent_bundle ( ) ,
279- } ;
276+ let translate_with_bundle = |bundle : & ' a FluentBundle | -> Option < ( Cow < ' _ , str > , Vec < _ > ) > {
277+ let message = bundle. get_message ( & identifier) ?;
278+ let value = match attr {
279+ Some ( attr) => message. get_attribute ( attr) ?. value ( ) ,
280+ None => message. value ( ) ?,
281+ } ;
282+ debug ! ( ?message, ?value) ;
280283
281- let message = bundle. get_message ( & identifier) . expect ( "missing diagnostic in fluent bundle" ) ;
282- let value = match attr {
283- Some ( attr) => {
284- if let Some ( attr) = message. get_attribute ( attr) {
285- attr. value ( )
286- } else {
287- panic ! ( "missing attribute `{attr}` in fluent message `{identifier}`" )
288- }
289- }
290- None => {
291- if let Some ( value) = message. value ( ) {
292- value
293- } else {
294- panic ! ( "missing value in fluent message `{identifier}`" )
295- }
296- }
284+ let mut errs = vec ! [ ] ;
285+ let translated = bundle. format_pattern ( value, Some ( & args) , & mut errs) ;
286+ debug ! ( ?translated, ?errs) ;
287+ Some ( ( translated, errs) )
297288 } ;
298289
299- let mut err = vec ! [ ] ;
300- let translated = bundle. format_pattern ( value, Some ( & args) , & mut err) ;
301- trace ! ( ?translated, ?err) ;
302- debug_assert ! (
303- err. is_empty( ) ,
304- "identifier: {:?}, args: {:?}, errors: {:?}" ,
305- identifier,
306- args,
307- err
308- ) ;
309- translated
290+ self . fluent_bundle ( )
291+ . and_then ( |bundle| translate_with_bundle ( bundle) )
292+ // If `translate_with_bundle` returns `None` with the primary bundle, this is likely
293+ // just that the primary bundle doesn't contain the message being translated, so
294+ // proceed to the fallback bundle.
295+ //
296+ // However, when errors are produced from translation, then that means the translation
297+ // is broken (e.g. `{$foo}` exists in a translation but `foo` isn't provided).
298+ //
299+ // In debug builds, assert so that compiler devs can spot the broken translation and
300+ // fix it..
301+ . inspect ( |( _, errs) | {
302+ debug_assert ! (
303+ errs. is_empty( ) ,
304+ "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}" ,
305+ identifier,
306+ attr,
307+ args,
308+ errs
309+ ) ;
310+ } )
311+ // ..otherwise, for end users, an error about this wouldn't be useful or actionable, so
312+ // just hide it and try with the fallback bundle.
313+ . filter ( |( _, errs) | errs. is_empty ( ) )
314+ . or_else ( || translate_with_bundle ( self . fallback_fluent_bundle ( ) ) )
315+ . map ( |( translated, errs) | {
316+ // Always bail out for errors with the fallback bundle.
317+ assert ! (
318+ errs. is_empty( ) ,
319+ "identifier: {:?}, attr: {:?}, args: {:?}, errors: {:?}" ,
320+ identifier,
321+ attr,
322+ args,
323+ errs
324+ ) ;
325+ translated
326+ } )
327+ . expect ( "failed to find message in primary or fallback fluent bundles" )
310328 }
311329
312330 /// Formats the substitutions of the primary_span
0 commit comments