diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart index 51d6e534f19a..30bb27f28db7 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n.dart @@ -1167,7 +1167,20 @@ class LocalizationsGenerator { } if (!pluralLogicArgs.containsKey(pluralCases[pluralCase])) { final String pluralPartExpression = generateVariables(pluralMessage); - pluralLogicArgs[pluralCases[pluralCase]!] = ' ${pluralCases[pluralCase]}: $pluralPartExpression,'; + final String? transformedPluralCase = pluralCases[pluralCase]; + // A valid plural case is one of "=0", "=1", "=2", "zero", "one", "two", "few", "many", or "other". + if (transformedPluralCase == null) { + throw L10nParserException( + ''' +The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", "many", or "other. + $pluralCase is not a valid plural case.''', + _inputFileNames[locale]!, + message.resourceId, + translationForMessage, + pluralPart.positionInMessage, + ); + } + pluralLogicArgs[transformedPluralCase] = ' ${pluralCases[pluralCase]}: $pluralPartExpression,'; } else if (!suppressWarnings) { logger.printWarning(''' [${_inputFileNames[locale]}:${message.resourceId}] ICU Syntax Warning: The plural part specified below is overridden by a later plural part. diff --git a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart index 9da376bc977e..604b82144e4a 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -2027,6 +2027,38 @@ import 'output-localization-file_en.dart' deferred as output-localization-file_e ^''')); }); + testWithoutContext('undefined plural cases throws syntax error', () { + const String pluralMessageWithUndefinedParts = ''' +{ + "count": "{count,plural, =0{None} =1{One} =2{Two} =3{Undefined Behavior!} other{Hmm...}}" +}'''; + final Directory l10nDirectory = fs.currentDirectory.childDirectory('lib').childDirectory('l10n') + ..createSync(recursive: true); + l10nDirectory.childFile(defaultTemplateArbFileName) + .writeAsStringSync(pluralMessageWithUndefinedParts); + try { + LocalizationsGenerator( + fileSystem: fs, + inputPathString: defaultL10nPathString, + outputPathString: defaultL10nPathString, + templateArbFileName: defaultTemplateArbFileName, + outputFileString: defaultOutputFileString, + classNameString: defaultClassNameString, + logger: logger, + ) + ..loadResources() + ..writeOutputFiles(); + } on L10nException catch (error) { + expect(error.message, contains('Found syntax errors.')); + expect(logger.hadErrorOutput, isTrue); + expect(logger.errorText, contains(''' +[app_en.arb:count] The plural cases must be one of "=0", "=1", "=2", "zero", "one", "two", "few", "many", or "other. + 3 is not a valid plural case. + {count,plural, =0{None} =1{One} =2{Two} =3{Undefined Behavior!} other{Hmm...}} + ^''')); + } + }); + testWithoutContext('should automatically infer plural placeholders that are not explicitly defined', () { const String pluralMessageWithoutPlaceholdersAttribute = ''' {