Home > OS >  How to change the application language with BlockBuilder?
How to change the application language with BlockBuilder?

Time:05-14

The application needs to implement language switching at runtime. Wrote a bloc with event and state and called BlocBuilder in main.dart. But I don't know how to implement the switch. How can I do that? In total, the application has two languages. My bloc:

class LanguageBloc extends Bloc<LanguageEvent, LanguageState> {
  LanguageBloc() : super(InitialLang()) {
    on<ChangeLang>(
      (event, emit) {
        emit(NewLang());
      },
    );
  }
  
  @immutable
abstract class LanguageEvent {}

class ChangeLang extends LanguageEvent {}

@immutable
abstract class LanguageState {}

class InitialLang extends LanguageState {}
class NewLang extends LanguageState {}

My main.dart

Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => BottomNavyBloc(),
        ),
        BlocProvider(
          create: (context) => LanguageBloc(),
        ),
      ],
      child: BlocBuilder<LanguageBloc, LanguageState>(
        builder: (context, state) {
          return MaterialApp(
            title: 'Flutter Demo',
            localizationsDelegates: const [
              S.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
            ],
            supportedLocales: S.delegate.supportedLocales,
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            debugShowCheckedModeBanner: false,
            home: const HomeScreen(),
          );
        },
      ),
    );
  }

My lang btn:

ElevatedButton(onPressed: (){}, child: Text('Switch lang'))

CodePudding user response:

What you can do is to send a variable Locale with the language of your choice, and in your MaterialApp in the locale attribute, you attach it.

Without complications you can use Cubit instead of Bloc, because it is not necessary to have events, then you could do the following:

class LanguageCubit extends Cubit<Locale?> { // change state here, you dont use LanguageState
  LanguageCubit() : super(null);

  void initialLang () { // your initial lang
    emit(
      Locale("en", ""),
    );
  }

  void newLang(
    bool isEnglish, // in your checkbox you are gonna send the boolean value here
  ) {
    emit(
      isEnglish ? Locale("en") : Locale("fr"),
    );
  }
}

Now in your main, as you have it, it would only look like this:

Widget build(BuildContext context) {
    return MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => BottomNavyBloc(),
        ),
        BlocProvider(
          create: (context) => LanguageBloc(),
        ),
      ],
      child: BlocBuilder<LanguageBloc, Locale?>( // change the state for Locale? cause could be null
        builder: (context, lang) { // different name to lang
          return MaterialApp(
            title: 'Flutter Demo',
            localizationsDelegates: const [
              S.delegate,
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              GlobalCupertinoLocalizations.delegate,
            ],
            supportedLocales: S.delegate.supportedLocales,
            theme: ThemeData(
              primarySwatch: Colors.blue,
            ),
            locale: lang, // here you set the lang
            debugShowCheckedModeBanner: false,
            home: const HomeScreen(),
          );
        },
      ),
    );
  }

----- EDIT WITH BUTTON -----

I thought you would need a Switch Button that handles the booleans but no, you only need one button that will be the one to change it so I did it this way:

class _HomePageState extends State<HomePage> {
  bool _currentLanguageBool = false; // variable to know if is english or french

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
     create: (context) => LanguageCubit(), // with this we can use the Cubit in all the page, normally you have to have it in main and in the MaterialApp
     child: Scaffold(
      body: Center(
        child: ElevatedButton(
           onPressed: () {
              BlocProvider.of<LanguageCubit>(context)
                  .newLang(_currentLanguageBool);

              setState(() {
                _currentLanguageBool = !_currentLanguageBool;
              }); // with this you change the variable
            },
           child: Text('Switch lang'),
        ),
      ),
     ),
    );
  }
}

We will make our widget a StatefulWidget so we can just change the boolean variable and know if it is in English or French. If you don't want to use Stateful let me know, because we can use it with the same Cubit, but it would change the code and a little bit the logic of the LanguageCubit.

  • Related