Arabic, English localization with flutter_bloc & cubit implementations — Advanced
At the beginning, let’s talk a little bit why we need the localization and multiple languages.. Well, it’s important if you need your app to grow up, reach more people, to be interactive with different cultures and so on.
So it’s very important to include multiple languages in your app especially if your app is an e-commerce app or something like it.
What we’ll do?
We’ll achieve this little app using flutter localizations and flutter bloc
If you’re familiar or worked with flutter_bloc before, then you’re good to go but if you’re not.. then I highly recommend you to read about the flutter_bloc and take a look at my previous article.
Otherwise, what we will do is:
- Architect our project files, add libraries, and setting up both languages (Arabic, English) from JOSN files and the app localization.
- Implementing the Bloc pattern and its logic.
- Hooking up all together with the UI.
Adding Libraries, Creating languages JSON files, and App Architecture
1- we need to add the flutter_localizations in the pubspec.yaml as well as the flutter_bloc library.
2- Create in the root directory a new folder called lang and inside this folder create two files (ar.json, en.json) as shown below
The ar.json will contains the Arabic translations as a json data (key, value) pair, and the en.json too.. now let’s fill both files with some data and will be explained later on.
Let’s head to the lib folder and do some changes:
3- Create a src folder inside the lib folder, this will contains all the source files.. inside this folder create some other folders (Blocs, Views, Themes, Routes, Localization…etc)
- Blocs: this folder will contains all the (blocs, cubits) folders and files as well as the blocs.dart and providers.dart files.
- Views: this folder will contains the app views (screens) and also called the presentation layer.
- Themes: this folder contains the app theme and all coloring stuff.
- Routes: this folder contains the app routes and things responsible of the app navigation and routing.
- Localization: this folder will contain the app localizations, delegates and localizations setup files.
And as shown here below
The flutter_bloc has its own vs code extension so we can easily create bloc, cubit files called Bloc.. so make sure you have it installed in your vs code.
Now, click at the Blocs folder and select the ‘Cubit: New Cubit’ option so you can create a new Cubit files and give it a name ‘Locale’.. The extension will automatically create the files with the suffix of ‘Cubit’ and ‘State’ so the files will be like this:
- LocaleCubit (a file contains our logic, methods, etc..)
Here, we’re defining two different methods to be called in the UI later.. and each method will emit a new state with a different Locale.
and initially we’re passing a default state with default language to the super class as a Locale(‘en’).
- LocateState (a file contains the states we need to emit)
One state that has one parameter in the constructor then will passed to the super class.
Now, let’s jump into the Localization folder that we already created above and create three different files:
This file contains a different things that needs to be explained:
load(): this method will load the specific file according to the locale that passed to the constructor and read the data inside that file whether the Arabic json file or the English one.
Then, the dynamic data read from the file will be decoded into key-value pair map data type, and since we need the dynamic to be a string we just map it to string so we can get the read data as <String, String> values and stored in the _localizedStrings variable.
translate(String key): this method will return the value of that key.
This is the delegate we created earlier if you noticed in the previous file as a static field, and it’s important when we call different locales and load it data.
This file is actually will be called in the main.dart, and the reason why I do that is because it’s easy to follow and separate implementations of its calls.
We can easily call them directly since they all are static fields.
- supportedLocales: is a list of Locale that our app should supports and we define a Locale for each language (Ar, En)
- localizationsDelegates: is also a list of LocalizationsDelegate that contains a built-in delegates and the delegate we build earlier called AppLocalizationsDelegate and called as a static field inside the AppLocalizations.
The other delegates are built-in and responsible of formatting dates and times or controlling the RTL/LTR according the some locales that needs those configurations.
Now, after creating, writing and other stuff.. here we’re hooking things together in the main.dart.
Here’s where everything comes interesting..
We have a StatelessWidget class called MainApp and the build method will return a MaterialApp, but before that.. we’re wrapping the MaterialApp with MultiBlocProvider or just BlocProvider to provide the blocs or cubits we wrote before.
Then, the child will be a BlocBuilder of the LocaleCubit so the app will listen to that cubit changes and if there are any new changes, the app will be rebuilt entirely with the new locale state value.
In the MaterialApp we’re calling the static fields in the AppLocalizationsSetup class and we can notice how easily now the separation is.
This is the final step, we just need to create a simple Scaffold view (screen) that contains a simple appBar, body (row and text).. so we can see the translations, widgets directions and stuff like that.
The appBar contains an IconButton to switch between the both languages and we can call the translate() method using the of(context) static field inside the AppLocalizations and provide the key that you write or define in the JSON file.
And to check if the current language is En, just call the isEnLocale() to return a boolean value.