Skip to content

Commit

Permalink
Update V1.1.2: Localization.
Browse files Browse the repository at this point in the history
 - Implemented a very unique Localization system.
 - Dart based CLI generator with isolates for extracting messages.
 - Auto merging all message files into one json.
 - Automatic google trnaslation for new messsages.
 - Automatic generated class based keys for accessing messages.
 - Implemented provider state solution.
  • Loading branch information
hackerhgl committed Jun 8, 2020
1 parent eeb5c9f commit a675cc8
Show file tree
Hide file tree
Showing 28 changed files with 1,019 additions and 271 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ if (flutterVersionCode == null) {

def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.1.1'
flutterVersionName = '1.1.2'
}

apply plugin: 'com.android.application'
Expand Down
23 changes: 23 additions & 0 deletions assets/langs/ar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"DownloadScreen/title": "تحميل",
"HomeScreen/title": "أهلا بك",
"HomeScreen/desc": "استكشاف معهد اليونسكو للإحصاء وضعت بشكل رائع مع رفرفة جوجل صممه المصممين المبدعين.",
"HomeScreen/uiList": "استكشاف معهد اليونسكو للإحصاء",
"HomeScreen/about": "حول التطبيقات",
"HomeScreen/aboutDeveloper": "وشك المطور",
"HomeScreen/download": "تحميل",
"HomeScreen/settings": "الإعدادات",
"HomeScreen/modalWebTitle": "تحذير",
"HomeScreen/modalWebDesc": "رفرفة ليس لديه دعم جيد لشبكة الإنترنت للخروج من مربع. هذا هو السبب في أنك سوف تواجه الخلل والتخلف. لا يوجد شيء خاطئ مع بلدي implementaion بيكوس كل شيء يعمل بشكل جيد على تطبيقات الوطنية.\n\nوذلك لخالية من المتاعب على نحو سلس تجربة فإنني أوصي لكم لتحميل التطبيق الأصلي",
"HomeScreen/modalWebButton1": "تحميل",
"HomeScreen/modalWebButton2": "استمر",
"HomeScreen/modalDesktopTitle": "إنذار",
"HomeScreen/modalDesktopDesc": "في \"BackButton\" بعض الشاشات ليست أفيبل بيكوس انها حققت UI البشعة. لذلك كبديل I نفذت اختصار لوحة المفاتيح لاعادة التنقل.\n\nماك: خيار + مسافة للخلف\nلينكس: البديل + مسافة للخلف\nنوافذ: السيطرة + مسافة للخلف",
"HomeScreen/modalDesktopButton": "استمر",
"HomeScreen/version": "الإصدار",
"HomeScreen/settingsModalTitle": "اختار اللغة",
"HomeScreen/settingsModalEnglish": "الإنجليزية",
"HomeScreen/settingsModalChinese": "صينى",
"HomeScreen/settingsModalArabic": "عربى",
"HomeScreen/settingsModalSystemDefault": "النظام الافتراضي"
}
1 change: 1 addition & 0 deletions assets/langs/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"welcome":"Welcome","test":"YUPPP","DownloadScreen/title":"Download","HomeScreen/welcome":"Welcome","HomeScreen/desc":"Explore elegantly crafted UIs with Google's Flutter designed by creative designers.","HomeScreen/title":"Welcome","HomeScreen/uiList":"Explore UIs","HomeScreen/about":"About App","HomeScreen/aboutDeveloper":"About Developer","HomeScreen/download":"Download","HomeScreen/modalWebTitle":"Warning","HomeScreen/modalWebDesc":"Flutter does not have good support for web out of box. That's why you will face bugs and lag. There is nothing wrong with my implementaion becuase every things works well on native apps.\n\nSo for hassle free smooth experience I recommend you to download native app","HomeScreen/modalWebButton1":"Download","HomeScreen/modalWebButton2":"Continue","HomeScreen/ModalDesktopTitle":"Alert","HomeScreen/ModalDesktopDesc":"In some screens 'BackButton' isn't avaible becuase it made UI hideous. So as an alternative I implemented keyboard shortcut to navigate back.\n\nMacOS: Option + Backspace\nLinux: Alt + Backsoace\nWindows: Ctrl + Backspace","HomeScreen/ModalDesktopButton":"Continue","HomeScreen/modalDesktopTitle":"Alert","HomeScreen/modalDesktopDesc":"In some screens 'BackButton' isn't avaible becuase it made UI hideous. So as an alternative I implemented keyboard shortcut to navigate back.\n\nMacOS: Option + Backspace\nLinux: Alt + Backspace\nWindows: Ctrl + Backspace","HomeScreen/modalDesktopButton":"Continue","HomeScreen/version":"VERSION","HomeScreen/settings":"Settings","SettingsScreen/title":"Settings","HomeScreen/settingsModalTitle":"Select Language","HomeScreen/settingsModalEnglish":"english","HomeScreen/settingsModalChinese":"chinese","HomeScreen/settingsModalArabic":"arabic","HomeScreen/settingsModalSystemDefault":"system default"}
1 change: 1 addition & 0 deletions assets/langs/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"DownloadScreen/title":"下载","HomeScreen/title":"欢迎","HomeScreen/desc":"探索与谷歌的扑优雅制作的UI由创意的设计师设计的。","HomeScreen/uiList":"浏览用户界面","HomeScreen/about":"关于应用程序","HomeScreen/aboutDeveloper":"关于开发者","HomeScreen/download":"下载","HomeScreen/settings":"设置","HomeScreen/modalWebTitle":"警告","HomeScreen/modalWebDesc":"扑不具备开箱对网络的良好支持。这就是为什么你会面临漏洞和滞后。有什么错我implementaion监守每一件事上的本地应用效果很好。\n\n因此,对于轻松自由流畅的体验,我建议你下载本机应用程序","HomeScreen/modalWebButton1":"下载","HomeScreen/modalWebButton2":"继续","HomeScreen/modalDesktopTitle":"警报","HomeScreen/modalDesktopDesc":"在某些屏幕“后退按钮”不avaible,原因是其取得UI狰狞。因此,作为一种替代我实现了键盘快捷键,即可返回。\n\nMacOS的:选项+ Backspace键\nLinux的键:Alt + Backspace键\nWindows系统:按Ctrl + Backspace键","HomeScreen/modalDesktopButton":"继续","HomeScreen/version":"版","HomeScreen/settingsModalTitle":"选择语言","HomeScreen/settingsModalEnglish":"英语","HomeScreen/settingsModalChinese":"中文","HomeScreen/settingsModalArabic":"阿拉伯","HomeScreen/settingsModalSystemDefault":"系统默认"}
66 changes: 66 additions & 0 deletions lib/AppLocalizations.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';

class AppLocalizations {
AppLocalizations(this.locale);
final Locale locale;

// Helper method to keep the code in the widgets concise
// Localizations are accessed using an InheritedWidget "of" syntax
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();

static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}

Map<String, String> _localizedStrings;

Future<bool> load() async {
// Load the language JSON file from the "lang" folder
String jsonString = await rootBundle.loadString(
'assets/langs/${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];
}
}

// LocalizationsDelegate is a factory for a set of localized resources
// In this case, the localized strings will be gotten in an AppLocalizations object
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
// This delegate instance will never change (it doesn't even have fields!)
// It can provide a constant constructor.
const _AppLocalizationsDelegate();

@override
bool isSupported(Locale locale) {
// Include all of your supported language codes here
return ['en', 'zh', 'ar'].contains(locale.languageCode);
}

@override
Future<AppLocalizations> load(Locale locale) async {
// AppLocalizations class is where the JSON loading actually runs
AppLocalizations localizations = new AppLocalizations(locale);
await localizations.load();
return localizations;
}

@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
136 changes: 80 additions & 56 deletions lib/Navigator.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_uis/AppLocalizations.dart';
import 'package:provider/provider.dart';
// import 'package:firebase/firebase.dart' as firebase;

import './configs/Theme.dart' as theme;
Expand All @@ -24,6 +27,7 @@ import './MiniApps/SkyView/Screens/DetailScreen/SKDetailScreen.dart';
import 'package:flutter_uis/MiniApps/AsicsShoesConcept/Screens/HomeScreen/ASCHomeScreen.dart';

import 'MiniApps/EggTimerConcept/Screens/HomeScreen/EggTimerConcept.dart';
import 'Providers/AppProvider.dart';

bool isAlt = false;

Expand All @@ -45,73 +49,93 @@ class AppNavigator extends StatelessWidget {
if (Platform.isWindows && keyName == ctrl) {
isAlt = (runtime == 'RawKeyDownEvent');
}

// print(
// "runtime:${event.runtimeType} | keyName:${event.logicalKey.debugName} | alt:${event.isAltPressed}");
if (runtime == 'RawKeyUpEvent' &&
(keyName == 'Backspace' || keyName == 'Digit 1') &&
(event.isAltPressed || isAlt) &&
this.navigator.currentState.canPop()) {
this.navigator.currentState.pop();
}
},
child: MaterialApp(
debugShowCheckedModeBanner: false,
navigatorKey: this.navigator,
theme: ThemeData(
fontFamily: "Muli",
primaryColor: theme.primary,
accentColor: theme.primary,
textTheme: TextTheme(
bodyText2: TextStyle(
color: Colors.black.withOpacity(0.6),
),
),
),
navigatorObservers: observers,
home: HomeScreen(),
onGenerateRoute: (settings) {
final index = ["skDetail", "hfdDetail"].indexOf(settings.name);
if (index > -1) {
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) {
if (index == 1) {
return HFDDetailScreen();
child: ChangeNotifierProvider<AppProvider>(
create: (_) => AppProvider(),
child: Consumer<AppProvider>(
// stream: null,
builder: (context, value, _) {
return MaterialApp(
debugShowCheckedModeBanner: false,
locale: value.activeLocale,
supportedLocales: AppProvider.locales,
localizationsDelegates: [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
localeResolutionCallback: (locale, supportedLocales) {
for (var supportedLocale in supportedLocales) {
if (locale != null &&
supportedLocale.languageCode == locale.languageCode &&
supportedLocale.countryCode == locale.countryCode) {
return supportedLocale;
}
}
return SKDetailScreen(settings.arguments);
return supportedLocales.first;
},
transitionsBuilder: (_, anim, __, child) {
return FadeTransition(opacity: anim, child: child);
navigatorKey: this.navigator,
theme: ThemeData(
fontFamily: "Muli",
primaryColor: theme.primary,
accentColor: theme.primary,
textTheme: TextTheme(
bodyText2: TextStyle(),
),
),
navigatorObservers: observers,
home: HomeScreen(),
onGenerateRoute: (settings) {
final index = ["skDetail", "hfdDetail"].indexOf(settings.name);
if (index > -1) {
return PageRouteBuilder(
settings: settings,
pageBuilder: (_, __, ___) {
if (index == 1) {
return HFDDetailScreen();
}
return SKDetailScreen(settings.arguments);
},
transitionsBuilder: (_, anim, __, child) {
return FadeTransition(opacity: anim, child: child);
},
);
}
return MaterialPageRoute(builder: (context) => HomeScreen());
},
routes: <String, WidgetBuilder>{
"home": (ctx) => new HomeScreen(),
"about": (ctx) => new AboutAppScreen(),
"aboutDeveloper": (ctx) => new AboutDeveloperScreen(),
"download": (ctx) => new DownloadScreen(),
"uiList": (ctx) => new UiListScreen(),
"uiDetail": (ctx) => new UiDetailScreen(),
"designerProfile": (ctx) => new DesignerProfileScreen(),

// Healthy Food Delivery
"hfdHome": (ctx) => new HFDHomeScreen(),
// "hfdDetail": (ctx) => new HFDDetailScreen(),

// Hot Air Balloon
"habHome": (ctx) => new HABHomeScreen(),

// Sky View
"skHome": (ctx) => new SKHomeScreen(),
// "skDetail": (ctx) => new SKDetailScreen(),

"ascHome": (ctx) => new ASCHomeScreen(),

"etcHome": (ctx) => new ETCHomeScreen(),
},
);
}
return MaterialPageRoute(builder: (context) => HomeScreen());
},
routes: <String, WidgetBuilder>{
"home": (ctx) => new HomeScreen(),
"about": (ctx) => new AboutAppScreen(),
"aboutDeveloper": (ctx) => new AboutDeveloperScreen(),
"download": (ctx) => new DownloadScreen(),
"uiList": (ctx) => new UiListScreen(),
"uiDetail": (ctx) => new UiDetailScreen(),
"designerProfile": (ctx) => new DesignerProfileScreen(),

// Healthy Food Delivery
"hfdHome": (ctx) => new HFDHomeScreen(),
// "hfdDetail": (ctx) => new HFDDetailScreen(),

// Hot Air Balloon
"habHome": (ctx) => new HABHomeScreen(),

// Sky View
"skHome": (ctx) => new SKHomeScreen(),
// "skDetail": (ctx) => new SKDetailScreen(),

"ascHome": (ctx) => new ASCHomeScreen(),

"etcHome": (ctx) => new ETCHomeScreen(),
},
},
),
),
);
}
Expand Down
18 changes: 18 additions & 0 deletions lib/Providers/AppProvider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'package:flutter/material.dart';

class AppProvider extends ChangeNotifier {
Locale _activeLocale;

static List<Locale> locales = [
Locale('en', 'US'),
Locale('zh', 'CN'),
Locale('ar', 'SA'),
];

Locale get activeLocale => this._activeLocale;

set activeLocale(Locale newLocale) {
this._activeLocale = newLocale;
notifyListeners();
}
}
19 changes: 19 additions & 0 deletions lib/configs/App.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_uis/AppLocalizations.dart';

import 'package:flutter_uis/configs/AppDimensions.dart';
import 'package:flutter_uis/configs/TextStyles.dart';

class App {
static BuildContext ctx;

static init(BuildContext context) {
AppDimensions.init(context);
TextStyles.init();
App.ctx = context;
}

static translate(String key) {
return AppLocalizations.of(App.ctx).translate(key);
}
}
20 changes: 20 additions & 0 deletions lib/configs/TextStyles.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';

import 'AppDimensions.dart';

abstract class TextStyles {
static TextStyle heading1;
static TextStyle heading2;

static init() {
// INIT HEADINGS
heading1 = TextStyle(
fontSize: 20 + AppDimensions.ratio * 10,
fontWeight: FontWeight.w700,
);
heading2 = TextStyle(
fontSize: 16 + AppDimensions.ratio * 8,
fontWeight: FontWeight.w600,
);
}
}
18 changes: 17 additions & 1 deletion lib/screens/AboutDeveloper/AboutDeveloper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,22 @@ class AboutDeveloperScreen extends StatelessWidget {
),
),
),
Container(
decoration: BoxDecoration(),
padding: EdgeInsets.only(
left: AppDimensions.padding,
top: AppDimensions.padding,
bottom: AppDimensions.padding * 2,
),
child: Text(
"NOTE: These contact links are not any kind of flutter helpline. I shared my contacts only for buisness related inquiries.\n\nAny help related query will not be entertain. For any help/answer follow docs or post your query on stackoverflow & community group.",
style: TextStyle(
fontSize: 16,
color: Colors.white.withOpacity(0.5),
fontWeight: FontWeight.w600,
),
),
),
Padding(
padding: EdgeInsets.only(
right: AppDimensions.padding,
Expand Down Expand Up @@ -234,7 +250,7 @@ class AboutDeveloperScreen extends StatelessWidget {
top: AppDimensions.padding,
),
child: Text(
"If you like the project and want to appreciate my effort. Then please click any of these links and perform any action you may like.",
"If you like the project and want to appreciate my effort. Then click any of these links below and perform the action.",
style: TextStyle(
fontSize: 8 + AppDimensions.ratio * 4,
// fontWeight: FontWeight.w300,
Expand Down
5 changes: 0 additions & 5 deletions lib/screens/AboutDeveloper/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ final contacts = [
"username": "hackerhgl",
"icon": MaterialCommunityIcons.facebook,
},
{
"platform": "instagram",
"username": "hackerhgl",
"icon": MaterialCommunityIcons.instagram,
},
{
"platform": "linkedin",
"username": "hackerhgl",
Expand Down
7 changes: 7 additions & 0 deletions lib/screens/Download/messages/keys.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// This is an auto generated file. Do not make any change on this.

const scope = 'DownloadScreen';

abstract class DownloadScreenMessages {
static String title = '$scope/title';
}
11 changes: 11 additions & 0 deletions lib/screens/Download/messages/strings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import 'dart:isolate';

const String scope = 'DownloadScreen';

const Map strings = {
'$scope/title': 'Download',
};

main(List<String> args, SendPort port) {
port.send({"strings": strings, "scope": scope});
}
Loading

0 comments on commit a675cc8

Please sign in to comment.