i18n compatibilty

release/mobdr-v0.0.1
Frédérik Benoist 2023-02-26 21:15:23 +01:00
parent 66edbf3f38
commit 28cd6e73f4
18 changed files with 378 additions and 14 deletions

3
assets/lang/ar.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "مرحبًا ، سيتغير هذا النص وفقًا للغة"
}

5
assets/lang/en.json Normal file
View File

@ -0,0 +1,5 @@
{
"text_description": "Hello, this text will change according to the language",
"i18n_hello" : "Hello",
"i18n_take_pictures" : "Take pictures"
}

4
assets/lang/fr.json Normal file
View File

@ -0,0 +1,4 @@
{
"i18n_hello": "Bonjour",
"i18n_take_pictures" : "Prendre des photos"
}

3
assets/lang/hi.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "नमस्कार, यह पाठ भाषा के अनुसार बदल जाएगा"
}

3
assets/lang/id.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "Halo, teks ini akan berubah menurut bahasanya"
}

3
assets/lang/th.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "สวัสดีข้อความนี้จะเปลี่ยนไปตามภาษา"
}

3
assets/lang/tk.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "Merhaba, bu yazı dile göre değişecek"
}

3
assets/lang/zh.json Normal file
View File

@ -0,0 +1,3 @@
{
"text_description": "您好,该文字会根据语言而变化"
}

View File

@ -11,6 +11,9 @@ PODS:
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite (0.0.2): - sqflite (0.0.2):
- Flutter - Flutter
- FMDB (>= 2.7.5) - FMDB (>= 2.7.5)
@ -21,6 +24,7 @@ DEPENDENCIES:
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`) - sqflite (from `.symlinks/plugins/sqflite/ios`)
SPEC REPOS: SPEC REPOS:
@ -37,6 +41,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios" :path: ".symlinks/plugins/path_provider_foundation/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
sqflite: sqflite:
:path: ".symlinks/plugins/sqflite/ios" :path: ".symlinks/plugins/sqflite/ios"
@ -46,6 +52,7 @@ SPEC CHECKSUMS:
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 Toast: 91b396c56ee72a5790816f40d3a94dd357abc196

View File

@ -0,0 +1,73 @@
/*
This is the app localizations for multi language
This function is used to change the language
We used shared preferences to change a whole language of the apps
*/
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AppLocalizations {
final Locale locale;
AppLocalizations(this.locale);
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
late Map<String, String> _localizedStrings;
Future<bool> load() async {
// Load the language JSON file from the "lang" folder
String jsonString =
await rootBundle.loadString('assets/lang/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);
_localizedStrings = jsonMap.map((key, value) {
return MapEntry(key, value.toString());
});
return true;
}
// This method will be called from every widget which needs a localized text
String? translate(String key) {
return _localizedStrings[key];
}
}
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
const AppLocalizationsDelegate();
@override
bool isSupported(Locale locale) {
// Include all of your supported language codes here
return ['fr', 'en', 'id', 'ar', 'zh', 'hi', 'th', 'tk']
.contains(locale.languageCode);
}
@override
Future<AppLocalizations> load(Locale locale) async {
final SharedPreferences _pref = await SharedPreferences.getInstance();
String? lCode = _pref.getString('lCode');
String? cCode = _pref.getString('cCode');
if (lCode == null || cCode == null) {
await _pref.setString('lCode', locale.languageCode);
await _pref.setString('cCode', locale.countryCode!);
} else {
locale = Locale(lCode, cCode);
}
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}
@override
bool shouldReload(AppLocalizationsDelegate old) => true;
}

View File

@ -0,0 +1,44 @@
import 'package:mobdr/cubit/language/language_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
class InitialLanguage extends StatefulWidget {
final Widget child;
const InitialLanguage({required this.child});
@override
_InitialLanguageState createState() => _InitialLanguageState();
}
class _InitialLanguageState extends State<InitialLanguage> {
late LanguageCubit _languageCubit;
@override
void initState() {
_languageCubit = BlocProvider.of<LanguageCubit>(context);
_getLocale().then((val) {
_languageCubit.changeLanguage(val);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
Future<Locale> _getLocale() async {
final SharedPreferences _pref = await SharedPreferences.getInstance();
String? lCode = _pref.getString('lCode');
String? cCode = _pref.getString('cCode');
if (lCode == null || cCode == null) {
await _pref.setString('lCode', 'fr');
await _pref.setString('cCode', 'FR');
return Locale('fr', 'FR');
} else {
return Locale(lCode, cCode);
}
}
}

View File

@ -0,0 +1,12 @@
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
part 'language_state.dart';
class LanguageCubit extends Cubit<LanguageState>{
LanguageCubit() : super(LanguageInitial());
void changeLanguage(locale){
emit(ChangeLanguageSuccess(locale));
}
}

View File

@ -0,0 +1,11 @@
part of 'language_cubit.dart';
@immutable
abstract class LanguageState {}
class LanguageInitial extends LanguageState{}
class ChangeLanguageSuccess extends LanguageState{
final locale;
ChangeLanguageSuccess(this.locale);
}

View File

@ -4,10 +4,17 @@ import 'dart:ui';
import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/constant.dart';
import 'package:mobdr/cubit/language/language_cubit.dart';
import 'package:mobdr/cubit/language/app_localizations.dart';
import 'package:mobdr/cubit/language/initial_language.dart';
import 'package:mobdr/ui/splash_screen.dart'; import 'package:mobdr/ui/splash_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
void main() { void main() {
// this function makes application always run in portrait mode // this function makes application always run in portrait mode
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
@ -31,6 +38,18 @@ class MyApp extends StatelessWidget {
// This widget is the root of your application. // This widget is the root of your application.
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// Initialize all bloc provider used on this entire application here
return MultiBlocProvider(
providers: [
// this bloc used for feature - change language
BlocProvider<LanguageCubit>(
create: (BuildContext context) => LanguageCubit(),
),
],
// if you want to change default language, go to lib/ui/feature/multi_language/initial_language.dart and change en US to your default language
child: InitialLanguage(
child: BlocBuilder<LanguageCubit, LanguageState>(
builder: (context, state) {
return MaterialApp( return MaterialApp(
scrollBehavior: MyCustomScrollBehavior(), scrollBehavior: MyCustomScrollBehavior(),
title: APP_NAME, title: APP_NAME,
@ -38,11 +57,42 @@ class MyApp extends StatelessWidget {
theme: ThemeData( theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity, visualDensity: VisualDensity.adaptivePlatformDensity,
pageTransitionsTheme: PageTransitionsTheme(builders: { pageTransitionsTheme: PageTransitionsTheme(builders: {
/*
Below is the example to change MaterialPageRoute default transition in iOS and Android :
FadeUpwardsPageTransitionsBuilder() <= Default MaterialPageRoute Transition
OpenUpwardsPageTransitionsBuilder()
ZoomPageTransitionsBuilder()
CupertinoPageTransitionsBuilder()
*/
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(), TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
TargetPlatform.android: ZoomPageTransitionsBuilder(), TargetPlatform.android: ZoomPageTransitionsBuilder(),
}), }),
), ),
// below is used for language feature
supportedLocales: [
Locale('fr', 'FR'),
Locale('en', 'US'),
Locale('id', 'ID'),
Locale('ar', 'DZ'),
Locale('zh', 'HK'),
Locale('hi', 'IN'),
Locale('th', 'TH'),
Locale('tk', 'TK'),
],
// These delegates make sure that the localization data for the proper language is loaded
localizationsDelegates: [
AppLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate
],
// Returns a locale which will be used by the app
locale: (state is ChangeLanguageSuccess)
? state.locale
: Locale('fr', 'FR'),
home: SplashScreenPage(), home: SplashScreenPage(),
); );
}),
),
);
} }
} }

View File

@ -4,6 +4,9 @@ we used AutomaticKeepAliveClientMixin to keep the state when moving from 1 navba
*/ */
import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/constant.dart';
import 'package:mobdr/cubit/language/language_cubit.dart';
import 'package:mobdr/cubit/language/app_localizations.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/config/global_style.dart';
import 'package:mobdr/model/wishlist_model.dart'; import 'package:mobdr/model/wishlist_model.dart';
import 'package:mobdr/ui/general/chat_us.dart'; import 'package:mobdr/ui/general/chat_us.dart';
@ -12,7 +15,7 @@ import 'package:mobdr/ui/general/product_detail/product_detail.dart';
import 'package:mobdr/ui/reusable/reusable_widget.dart'; import 'package:mobdr/ui/reusable/reusable_widget.dart';
import 'package:mobdr/ui/reusable/cache_image_network.dart'; import 'package:mobdr/ui/reusable/cache_image_network.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:shared_preferences/shared_preferences.dart';
class TabHomePage extends StatefulWidget { class TabHomePage extends StatefulWidget {
@override @override
@ -31,8 +34,18 @@ class _TabHomePageState extends State<TabHomePage>
@override @override
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
String defaultLang = 'en';
late LanguageCubit _languageCubit;
@override @override
void initState() { void initState() {
_languageCubit = BlocProvider.of<LanguageCubit>(context);
_getLocale().then((val) {
setState(() {
defaultLang = val!;
});
});
super.initState(); super.initState();
} }
@ -41,6 +54,20 @@ class _TabHomePageState extends State<TabHomePage>
super.dispose(); super.dispose();
} }
Future<String?> _getLocale() async {
final SharedPreferences _pref = await SharedPreferences.getInstance();
String? lCode = _pref.getString('lCode');
return lCode;
}
void changeLocale(Locale locale) async {
final SharedPreferences _pref = await SharedPreferences.getInstance();
await _pref.setString('lCode', locale.languageCode);
await _pref.setString('cCode', locale.countryCode!);
_languageCubit.changeLanguage(locale);
defaultLang = locale.languageCode;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// if we used AutomaticKeepAliveClientMixin, we must call super.build(context); // if we used AutomaticKeepAliveClientMixin, we must call super.build(context);
@ -51,7 +78,8 @@ class _TabHomePageState extends State<TabHomePage>
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
elevation: GlobalStyle.appBarElevation, elevation: GlobalStyle.appBarElevation,
title: Text( title: Text(
'Bonjour, Frédérik', AppLocalizations.of(context)!.translate('i18n_hello')! +
', Frédérik',
style: GlobalStyle.appBarTitle, style: GlobalStyle.appBarTitle,
), ),
backgroundColor: GlobalStyle.appBarBackgroundColor, backgroundColor: GlobalStyle.appBarBackgroundColor,
@ -242,7 +270,8 @@ class _TabHomePageState extends State<TabHomePage>
BorderSide(color: SOFT_BLUE, width: 1.0), BorderSide(color: SOFT_BLUE, width: 1.0),
)), )),
child: Text( child: Text(
'Prendre des photos', AppLocalizations.of(context)!
.translate('i18n_take_pictures')!,
style: TextStyle( style: TextStyle(
color: SOFT_BLUE, color: SOFT_BLUE,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@ -7,10 +7,12 @@ import Foundation
import package_info_plus import package_info_plus
import path_provider_foundation import path_provider_foundation
import shared_preferences_foundation
import sqflite import sqflite
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
} }

View File

@ -9,6 +9,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.10.0" version: "2.10.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: "658a5ae59edcf1e58aac98b000a71c762ad8f46f1394c34a52050cafb3e11a80"
url: "https://pub.dev"
source: hosted
version: "8.1.1"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -126,6 +134,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" version: "0.0.0"
flutter_bloc:
dependency: "direct main"
description:
name: flutter_bloc
sha256: "434951eea948dbe87f737b674281465f610b8259c16c097b8163ce138749a775"
url: "https://pub.dev"
source: hosted
version: "8.1.2"
flutter_blurhash: flutter_blurhash:
dependency: transitive dependency: transitive
description: description:
@ -150,6 +166,11 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0-alpha.6" version: "3.0.0-alpha.6"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -232,6 +253,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.8.0" version: "1.8.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
numerus: numerus:
dependency: transitive dependency: transitive
description: description:
@ -352,6 +381,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.4" version: "4.2.4"
provider:
dependency: transitive
description:
name: provider
sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
url: "https://pub.dev"
source: hosted
version: "6.0.5"
rxdart: rxdart:
dependency: transitive dependency: transitive
description: description:
@ -360,6 +397,62 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.27.7" version: "0.27.7"
shared_preferences:
dependency: "direct main"
description:
name: shared_preferences
sha256: "5949029e70abe87f75cfe59d17bf5c397619c4b74a099b10116baeb34786fad9"
url: "https://pub.dev"
source: hosted
version: "2.0.17"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: a51a4f9375097f94df1c6e0a49c0374440d31ab026b59d58a7e7660675879db4
url: "https://pub.dev"
source: hosted
version: "2.0.16"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "6b84fdf06b32bb336f972d373cd38b63734f3461ba56ac2ba01b56d052796259"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shared_preferences_linux:
dependency: transitive
description:
name: shared_preferences_linux
sha256: d7fb71e6e20cd3dfffcc823a28da3539b392e53ed5fc5c2b90b55fdaa8a7e8fa
url: "https://pub.dev"
source: hosted
version: "2.1.4"
shared_preferences_platform_interface:
dependency: transitive
description:
name: shared_preferences_platform_interface
sha256: "824bfd02713e37603b2bdade0842e47d56e7db32b1dcdd1cae533fb88e2913fc"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
shared_preferences_web:
dependency: transitive
description:
name: shared_preferences_web
sha256: "6737b757e49ba93de2a233df229d0b6a87728cea1684da828cbc718b65dcf9d7"
url: "https://pub.dev"
source: hosted
version: "2.0.5"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
sha256: bd014168e8484837c39ef21065b78f305810ceabc1d4f90be6e3b392ce81b46d
url: "https://pub.dev"
source: hosted
version: "2.1.4"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter

View File

@ -31,16 +31,23 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_localizations:
sdk: flutter
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: 1.0.5 cupertino_icons: 1.0.5
fluttertoast: 8.1.3 fluttertoast: 8.1.3
package_info_plus: 3.0.3 package_info_plus: 3.0.3
flutter_bloc: 8.1.2
flutter_html: 3.0.0-alpha.6 flutter_html: 3.0.0-alpha.6
#https://pub.dev/packages/intl
intl: 0.17.0 intl: 0.17.0
carousel_slider: 4.2.1 carousel_slider: 4.2.1
cached_network_image: 3.2.3 cached_network_image: 3.2.3
shared_preferences: 2.0.17
universal_io: 2.2.0 universal_io: 2.2.0
dev_dependencies: dev_dependencies:
@ -108,3 +115,12 @@ flutter:
- assets/images/logo.png - assets/images/logo.png
- assets/images/logo_dark.png - assets/images/logo_dark.png
- assets/images/onboarding/search_product.gif - assets/images/onboarding/search_product.gif
- assets/lang/fr.json
- assets/lang/en.json
- assets/lang/id.json
- assets/lang/ar.json
- assets/lang/zh.json
- assets/lang/hi.json
- assets/lang/th.json
- assets/lang/tk.json