Skip to content

Unable to test localized widget in flutter when using .json files. #45166

@ViniciusSossela

Description

@ViniciusSossela

#22193 (comment)
@chunhtai actually it doesn't work.

In our case, we are using .json files to do translations. So we have like these:

  • assets/lang/en.json
  • assets/lang/pt.json
  • assets/lang/es.json

.....

The way we load and use these json files are through LocalizationsDelegate extension like this:

class AppLocalizations {
  final Locale locale;

  AppLocalizations(this.locale);

  static AppLocalizations of(BuildContext context) =>
      Localizations.of<AppLocalizations>(context, AppLocalizations);

  static const LocalizationsDelegate<AppLocalizations> delegate =
      _AppLocalizationsDelegate();

  Map<String, String> _localizedStrings;

  Future<bool> load() async {
    try {
      String jsonString = await rootBundle.loadString('assets/lang/${locale.languageCode}.json'); **here is the problem**
      Map<String, dynamic> jsonMap = json.decode(jsonString);

      _localizedStrings = jsonMap.map((key, value) => MapEntry(key, value));
      return true;
    } catch (e) {
      return false;
    }
  }

  String translate(String key) => _localizedStrings[key];
}

class _AppLocalizationsDelegate
    extends LocalizationsDelegate<AppLocalizations> {
  const _AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) {
    return ['en', 'pt', 'es'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) async {
    AppLocalizations localizations = AppLocalizations(locale);
    await localizations.load();
    return localizations;
  }

  @override
  bool shouldReload(LocalizationsDelegate<AppLocalizations> old) => false;
}
class MyTranslatedWidget extends StatefulWidget {
  @override
  _MyTranslatedWidgetState createState() => _MyTranslatedWidgetState();
}

class _MyTranslatedWidget extends State<MyTranslatedWidget> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text(
        AppLocalizations.of(context).translate('hello_key'),
      ),
    );
  }
}

and then in our widget test, we have something like this:

 testWidgets(
    'my test description',
    (WidgetTester tester) async {
      await tester.runAsync(() async {

        await tester.pumpWidget(MaterialApp(
          locale: Locale('en'),
          localizationsDelegates: [
            GlobalMaterialLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
            AppLocalizations.delegate   **here is the problem**
          ],
          home: MyTranslatedWidget(),
        ));

        final titleFinder = find.text('hello');
        expect(titleFinder, findsOneWidget);
      });
    },
  );

After running this test we got the following problem:

══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown while running async test code:
  Expected: exactly one matching node in the widget tree
  Actual: ?:<zero widgets with text "hello" (ignoring offstage widgets)>
   Which: means none were found but one was expected

This happens because,AppLocalizations.delegate that is called on localizationsDelegates from MaterialApp is not able to load the .json file that have all the text translations.

Something happens here: String jsonString = await rootBundle.loadString('assets/lang/${locale.languageCode}.json');

it seems like the rootBundle can't find or load the json assets...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions