Skip to content

Commit

Permalink
🐛 Treat empty ARB content as empty map when decoding (#131242)
Browse files Browse the repository at this point in the history
Fixes #128932.
  • Loading branch information
AlexV525 authored Aug 1, 2023
1 parent d250fa6 commit f2db93d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 16 deletions.
43 changes: 27 additions & 16 deletions packages/flutter_tools/lib/src/localizations/gen_l10n_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,18 @@ class Message {
}
}

// Represents the contents of one ARB file.
/// Represents the contents of one ARB file.
class AppResourceBundle {
/// Assuming that the caller has verified that the file exists and is readable.
factory AppResourceBundle(File file) {
// Assuming that the caller has verified that the file exists and is readable.
Map<String, Object?> resources;
final Map<String, Object?> resources;
try {
resources = json.decode(file.readAsStringSync()) as Map<String, Object?>;
final String content = file.readAsStringSync().trim();
if (content.isEmpty) {
resources = <String, Object?>{};
} else {
resources = json.decode(content) as Map<String, Object?>;
}
} on FormatException catch (e) {
throw L10nException(
'The arb file ${file.path} has the following formatting issue: \n'
Expand Down Expand Up @@ -657,20 +662,26 @@ class AppResourceBundleCollection {
final RegExp filenameRE = RegExp(r'(\w+)\.arb$');
final Map<LocaleInfo, AppResourceBundle> localeToBundle = <LocaleInfo, AppResourceBundle>{};
final Map<String, List<LocaleInfo>> languageToLocales = <String, List<LocaleInfo>>{};
final List<File> files = directory.listSync().whereType<File>().toList()..sort(sortFilesByPath);
// We require the list of files to be sorted so that
// "languageToLocales[bundle.locale.languageCode]" is not null
// by the time we handle locales with country codes.
final List<File> files = directory
.listSync()
.whereType<File>()
.where((File e) => filenameRE.hasMatch(e.path))
.toList()
..sort(sortFilesByPath);
for (final File file in files) {
if (filenameRE.hasMatch(file.path)) {
final AppResourceBundle bundle = AppResourceBundle(file);
if (localeToBundle[bundle.locale] != null) {
throw L10nException(
"Multiple arb files with the same '${bundle.locale}' locale detected. \n"
'Ensure that there is exactly one arb file for each locale.'
);
}
localeToBundle[bundle.locale] = bundle;
languageToLocales[bundle.locale.languageCode] ??= <LocaleInfo>[];
languageToLocales[bundle.locale.languageCode]!.add(bundle.locale);
final AppResourceBundle bundle = AppResourceBundle(file);
if (localeToBundle[bundle.locale] != null) {
throw L10nException(
"Multiple arb files with the same '${bundle.locale}' locale detected. \n"
'Ensure that there is exactly one arb file for each locale.'
);
}
localeToBundle[bundle.locale] = bundle;
languageToLocales[bundle.locale.languageCode] ??= <LocaleInfo>[];
languageToLocales[bundle.locale.languageCode]!.add(bundle.locale);
}

languageToLocales.forEach((String language, List<LocaleInfo> listOfCorrespondingLocales) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/localizations.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/generate_localizations.dart';
import 'package:flutter_tools/src/localizations/gen_l10n_types.dart';

import '../../integration.shard/test_data/basic_project.dart';
import '../../src/common.dart';
Expand Down Expand Up @@ -501,4 +502,33 @@ format: true
throwsToolExit(message: 'Unexpected positional argument "false".')
);
});

group(AppResourceBundle, () {
testWithoutContext("can be parsed without FormatException when it's content is empty", () {
final File arbFile = fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb'))
..createSync(recursive: true);
expect(AppResourceBundle(arbFile), isA<AppResourceBundle>());
});

testUsingContext("would not fail the gen-l10n command when it's content is empty", () async {
fileSystem.file(fileSystem.path.join('lib', 'l10n', 'app_en.arb')).createSync(recursive: true);
final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync(BasicProjectWithFlutterGen().pubspec);
final GenerateLocalizationsCommand command = GenerateLocalizationsCommand(
fileSystem: fileSystem,
logger: logger,
artifacts: artifacts,
processManager: processManager,
);
await createTestCommandRunner(command).run(<String>['gen-l10n']);

final Directory outputDirectory = fileSystem.directory(fileSystem.path.join('.dart_tool', 'flutter_gen', 'gen_l10n'));
expect(outputDirectory.existsSync(), true);
expect(outputDirectory.childFile('app_localizations_en.dart').existsSync(), true);
expect(outputDirectory.childFile('app_localizations.dart').existsSync(), true);
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
});
}

0 comments on commit f2db93d

Please sign in to comment.