Improve arb FormatException error message (#56373)

diff --git a/dev/tools/localization/gen_l10n_types.dart b/dev/tools/localization/gen_l10n_types.dart
index a8853dd..2007e4b 100644
--- a/dev/tools/localization/gen_l10n_types.dart
+++ b/dev/tools/localization/gen_l10n_types.dart
@@ -363,8 +363,16 @@
   factory AppResourceBundle(File file) {
     assert(file != null);
     // Assuming that the caller has verified that the file exists and is readable.
+    Map<String, dynamic> resources;
+    try {
+      resources = json.decode(file.readAsStringSync()) as Map<String, dynamic>;
+    } on FormatException catch (e) {
+      throw L10nException(
+        'The arb file ${file.path} has the following formatting issue: \n'
+        '${e.toString()}',
+      );
+    }
 
-    final Map<String, dynamic> resources = json.decode(file.readAsStringSync()) as Map<String, dynamic>;
     String localeString = resources['@@locale'] as String;
     if (localeString == null) {
       final RegExp filenameRE = RegExp(r'^[^_]*_(\w+)\.arb$');
diff --git a/dev/tools/test/localization/gen_l10n_test.dart b/dev/tools/test/localization/gen_l10n_test.dart
index 8748a22..ad6943f 100644
--- a/dev/tools/test/localization/gen_l10n_test.dart
+++ b/dev/tools/test/localization/gen_l10n_test.dart
@@ -1284,40 +1284,46 @@
       });
     });
 
-    test('should throw when failing to parse the arb file', () {
-      const String arbFileWithTrailingComma = '''
+    test(
+      'should throw with descriptive error message when failing to parse the '
+      'arb file',
+      () {
+        const String arbFileWithTrailingComma = '''
 {
   "title": "Stocks",
   "@title": {
     "description": "Title for the Stocks application"
   },
 }''';
-      final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
-        ..createSync(recursive: true);
-      l10nDirectory.childFile(defaultTemplateArbFileName)
-        .writeAsStringSync(arbFileWithTrailingComma);
+        final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n')
+          ..createSync(recursive: true);
+        l10nDirectory.childFile(defaultTemplateArbFileName)
+          .writeAsStringSync(arbFileWithTrailingComma);
 
-      final LocalizationsGenerator generator = LocalizationsGenerator(fs);
-      try {
-        generator.initialize(
-          inputPathString: defaultL10nPathString,
-          outputPathString: defaultL10nPathString,
-          templateArbFileName: defaultTemplateArbFileName,
-          outputFileString: defaultOutputFileString,
-          classNameString: defaultClassNameString,
+        final LocalizationsGenerator generator = LocalizationsGenerator(fs);
+        try {
+          generator.initialize(
+            inputPathString: defaultL10nPathString,
+            outputPathString: defaultL10nPathString,
+            templateArbFileName: defaultTemplateArbFileName,
+            outputFileString: defaultOutputFileString,
+            classNameString: defaultClassNameString,
+          );
+          generator.loadResources();
+          generator.writeOutputFiles();
+        } on L10nException catch (e) {
+          expect(e.message, contains('app_en.arb'));
+          expect(e.message, contains('FormatException'));
+          expect(e.message, contains('Unexpected character'));
+          return;
+        }
+
+        fail(
+          'should fail with an L10nException due to a trailing comma in the '
+          'arb file.'
         );
-        generator.loadResources();
-        generator.writeOutputFiles();
-      } on FormatException catch (e) {
-        expect(e.message, contains('Unexpected character'));
-        return;
-      }
-
-      fail(
-        'should fail with a FormatException due to a trailing comma in the '
-        'arb file.'
-      );
-    });
+      },
+    );
 
     test('should throw when resource is missing resource attribute', () {
       const String arbFileWithMissingResourceAttribute = '''