diff --git a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart index c23ce34360d..70817f2c3aa 100644 --- a/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart +++ b/packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart @@ -638,40 +638,44 @@ class AppResourceBundle { // Look for the first instance of an ISO 639-1 language code, matching exactly. final String fileName = file.fileSystem.path.basenameWithoutExtension(file.path); - for (var index = 0; index < fileName.length; index += 1) { - // If an underscore was found, check if locale string follows. - if (fileName[index] == '_') { - // If Locale.tryParse fails, it returns null. - final Locale? parserResult = Locale.tryParse(fileName.substring(index + 1)); - // If the parserResult is not an actual locale identifier, end the loop. - if (parserResult != null && _iso639Languages.contains(parserResult.languageCode)) { - // The parsed result uses dashes ('-'), but we want underscores ('_'). - final String parserLocaleString = parserResult.toString().replaceAll('-', '_'); + // Try to parse a locale from the filename. + String? fileNameLocale; - if (localeString == null) { - // If @@locale was not defined, use the filename locale suffix. - localeString = parserLocaleString; - } else { - // If the localeString was defined in @@locale and in the filename, verify to - // see if the parsed locale matches, throw an error if it does not. This - // prevents developers from confusing issues when both @@locale and - // "_{locale}" is specified in the filename. - if (localeString != parserLocaleString) { - throw L10nException( - 'The locale specified in @@locale and the arb filename do not match. \n' - 'Please make sure that they match, since this prevents any confusion \n' - 'with which locale to use. Otherwise, specify the locale in either the \n' - 'filename or the @@locale key only.\n' - 'Current @@locale value: $localeString\n' - 'Current filename extension: $parserLocaleString', - ); - } + // First, try parsing the whole filename as a locale. + Locale? parserResult = Locale.tryParse(fileName); + if (parserResult != null && _iso639Languages.contains(parserResult.languageCode)) { + fileNameLocale = parserResult.toString().replaceAll('-', '_'); + } else { + // If that fails, look for underscores and try parsing after each one. + for (var index = 0; index < fileName.length; index += 1) { + if (fileName[index] == '_') { + parserResult = Locale.tryParse(fileName.substring(index + 1)); + if (parserResult != null && _iso639Languages.contains(parserResult.languageCode)) { + // The parsed result uses dashes ('-'), but we want underscores ('_'). + fileNameLocale = parserResult.toString().replaceAll('-', '_'); + break; } - break; } } } + if (localeString != null) { + // If @@locale is provided, check if there's a conflicting locale in the filename. + if (fileNameLocale != null && localeString != fileNameLocale) { + throw L10nException( + 'The locale specified in @@locale and the arb filename do not match. \n' + 'Please make sure that they match, since this prevents any confusion \n' + 'with which locale to use. Otherwise, specify the locale in either the \n' + 'filename or the @@locale key only.\n' + 'Current @@locale value: $localeString\n' + 'Current filename extension: $fileNameLocale', + ); + } + } else { + // If @@locale is not provided, use the locale parsed from the filename. + localeString = fileNameLocale; + } + if (localeString == null) { throw L10nException( "The following .arb file's locale could not be determined: \n" 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 ed6fee7c1b0..d93964eecbd 100644 --- a/packages/flutter_tools/test/general.shard/generate_localizations_test.dart +++ b/packages/flutter_tools/test/general.shard/generate_localizations_test.dart @@ -1210,6 +1210,39 @@ class AppLocalizationsEn extends AppLocalizations { }, ); + testWithoutContext('handles pt_BR locale correctly', () { + const ptArbFileString = ''' +{ + "@@locale": "pt", + "test": "test_PT" +}'''; + + const ptBrArbFileString = ''' +{ + "@@locale": "pt_BR", + "test": "test_PT_BR" +}'''; + + fs.currentDirectory.childDirectory('lib').childDirectory('l10n') + ..createSync(recursive: true) + ..childFile('pt.arb').writeAsStringSync(ptArbFileString) + ..childFile('pt_BR.arb').writeAsStringSync(ptBrArbFileString); + + final generator = LocalizationsGenerator( + fileSystem: fs, + inputPathString: defaultL10nPath, + outputPathString: defaultL10nPath, + templateArbFileName: 'pt.arb', + outputFileString: defaultOutputFileString, + classNameString: defaultClassNameString, + projectPathString: fs.currentDirectory.path, + logger: logger, + )..loadResources(); + + expect(generator.supportedLocales.contains(LocaleInfo.fromString('pt')), true); + expect(generator.supportedLocales.contains(LocaleInfo.fromString('pt_BR')), true); + }); + testWithoutContext("throws when arb file's locale could not be determined", () { fs.currentDirectory.childDirectory('lib').childDirectory('l10n') ..createSync(recursive: true)