Skip to content

Commit

Permalink
Merge pull request #32 from wednesday-solutions/feature_localization
Browse files Browse the repository at this point in the history
Feature localization
  • Loading branch information
shounak-mulay authored Jul 11, 2022
2 parents 09ba983 + 019aaa0 commit 951a45e
Show file tree
Hide file tree
Showing 27 changed files with 149 additions and 77 deletions.
10 changes: 10 additions & 0 deletions assets/translations/hi-IN.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"homePageTitle": "मुख्य पृष्ठ",
"searchPageTitle": "खोज",
"forecast": "पूर्वानुमान",
"favCitiesAppearHere": "आपके पसंदीदा शहरों का मौसम यहां दिखाई देगा। पसंदीदा में जोड़ने के लिए शहर खोजें।",
"startTypingToSearch": "खोजने के लिए टाइप करना प्रारंभ करें",
"searchResultsAppearHere": "खोज परिणाम यहां दिखाई देते हैं...",
"noResultsFound": "कोई परिणाम नहीं मिला...",
"dynamicTheme": "डायनामिक थीम"
}
2 changes: 1 addition & 1 deletion lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void startApp() async {
await _initialiseApp();

runApp(EasyLocalization(
supportedLocales: const [Locale("en", "US")],
supportedLocales: const [Locale("en", "US"), Locale("hi", "IN")],
path: "assets/translations",
fallbackLocale: const Locale("en", "US"),
assetLoader: const CodegenLoader(),
Expand Down
16 changes: 16 additions & 0 deletions lib/foundation/extensions/context_ext.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:easy_localization/easy_localization.dart' as el;
import 'package:flutter/cupertino.dart';

extension ContextExt on BuildContext {
///
/// Extension on context to make sure any string that uses [tr] gets updated when translation changes.
/// Not using the context won't translate the string if its [tr] is being used in non changing components eg. viewModel
///
String tr(String key) {
try {
return el.tr(key);
} catch (e) {
return key;
}
}
}
10 changes: 0 additions & 10 deletions lib/foundation/extensions/string_ext.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,3 @@
import 'package:easy_localization/easy_localization.dart' as el;

extension StringExt on String {
bool get isBlank => trim().isEmpty;

String get tr {
try {
return el.tr(this);
} catch (e) {
return this;
}
}
}
8 changes: 8 additions & 0 deletions lib/presentation/base/page/base_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_template/foundation/extensions/theme_ext.dart';
Expand Down Expand Up @@ -55,7 +56,14 @@ class BasePage<SCREEN extends Screen, SCREEN_STATE extends ScreenState,
return subscription.cancel;
}, [viewModel.effectStream]);

///
/// Adding [reRenderKey] makes sure that any time the language is changed,
/// the current pages gets completely re-rendered.
///
final reRenderKey = ValueKey(context.locale.languageCode);

return ViewModelProvider(
key: reRenderKey,
provider: viewModelProvider,
child: _BasePageContent<VIEW_MODEL, SCREEN_STATE>(
onAppBarBackPressed: onAppBarBackPressed,
Expand Down
3 changes: 2 additions & 1 deletion lib/presentation/base/widgets/appbar/app_bar_title.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_template/foundation/extensions/context_ext.dart';
import 'package:flutter_template/presentation/base/view_model_provider/base_view_model.dart';
import 'package:flutter_template/presentation/base/view_model_provider/view_model_provider_ext.dart';
import 'package:flutter_template/presentation/entity/screen/screen.dart';
Expand All @@ -19,7 +20,7 @@ class AppBarTitle<VIEW_MODEL extends BaseViewModel<Screen, SCREEN_STATE>,
.select((state) => state.toolbar.title),
);
return Text(
title,
context.tr(title),
overflow: TextOverflow.ellipsis,
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_template/foundation/extensions/string_ext.dart';
import 'package:flutter_template/foundation/extensions/context_ext.dart';
import 'package:flutter_template/presentation/intl/translations/translation_keys.dart';

class DynamicThemeSwitchContent extends StatelessWidget {
Expand All @@ -16,7 +16,7 @@ class DynamicThemeSwitchContent extends StatelessWidget {
Widget build(BuildContext context) {
return Row(
children: [
Text(LocaleKeys.dynamicTheme.tr),
Text(context.tr(LocaleKeys.dynamicTheme)),
Switch(
value: isDynamic,
onChanged: onIsDynamicToggled,
Expand Down
12 changes: 12 additions & 0 deletions lib/presentation/destinations/weather/home/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_template/presentation/base/page/base_page.dart';
Expand All @@ -23,6 +24,17 @@ class HomePage extends ConsumerWidget {
viewModelProvider: homeViewModelProvider,
screen: homeScreen,
appBarActions: () => [
IconButton(
onPressed: () {
String locale = context.locale.toString();
if (locale == "hi_IN") {
context.setLocale(const Locale("en", "US"));
} else {
context.setLocale(const Locale("hi", "IN"));
}
},
icon: const Icon(Icons.language),
),
IconButton(
onPressed: () {
final viewModel = ref.watch(homeViewModelProvider.notifier);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:flutter_template/foundation/extensions/string_ext.dart';
import 'package:flutter_template/interactor/weather/favorite/favorite_weather_interactor.dart';
import 'package:flutter_template/navigation/weather/home/home_navigator.dart';
import 'package:flutter_template/presentation/destinations/weather/home/home_screen_intent.dart';
Expand All @@ -19,7 +18,7 @@ class HomeViewModelImpl extends HomeViewModel {

static get _initialState => HomeScreenState(
toolbar: UIToolbar(
title: LocaleKeys.homePageTitle.tr,
title: LocaleKeys.homePageTitle,
hasBackButton: false,
),
showLoading: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_template/foundation/extensions/string_ext.dart';
import 'package:flutter_template/foundation/extensions/context_ext.dart';
import 'package:flutter_template/presentation/base/intent/intent_handler_callback.dart';
import 'package:flutter_template/presentation/base/widgets/list/ui_list.dart';
import 'package:flutter_template/presentation/base/widgets/responsive/responsive_builder.dart';
Expand All @@ -26,7 +26,7 @@ class HomePageBodyContent extends StatelessWidget {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
LocaleKeys.favCitiesAppearHere.tr,
context.tr(LocaleKeys.favCitiesAppearHere),
textAlign: TextAlign.center,
),
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class SearchViewModelImpl extends SearchViewModel {

static SearchScreenState get _initialState => SearchScreenState(
toolbar: UIToolbar(
title: LocaleKeys.searchPageTitle.tr,
title: LocaleKeys.searchPageTitle,
hasBackButton: true,
),
showLoading: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_template/foundation/extensions/string_ext.dart';
import 'package:flutter_template/foundation/extensions/context_ext.dart';
import 'package:flutter_template/presentation/destinations/weather/search/search_screen_intent.dart';
import 'package:flutter_template/presentation/destinations/weather/search/search_view_model.dart';
import 'package:flutter_template/presentation/destinations/weather/search/widgets/search_page_body/search_page_body_content.dart';
Expand All @@ -27,7 +27,7 @@ class SearchPageBody extends HookConsumerWidget {

return SearchPageBodyContent(
textController: textController,
searchHint: LocaleKeys.startTypingToSearch.tr,
searchHint: context.tr(LocaleKeys.startTypingToSearch),
child: const SearchPageResults(),
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_template/foundation/extensions/string_ext.dart';
import 'package:flutter_template/foundation/extensions/context_ext.dart';
import 'package:flutter_template/presentation/destinations/weather/search/search_view_model.dart';
import 'package:flutter_template/presentation/destinations/weather/search/widgets/search_page_results/search_page_results_content.dart';
import 'package:flutter_template/presentation/intl/translations/translation_keys.dart';
Expand All @@ -25,8 +25,8 @@ class SearchPageResults extends ConsumerWidget {
searchList: searchList,
searchTerm: viewModel.searchTerm,
intentHandlerCallback: viewModel.onIntent,
searchResultsPlaceholder: LocaleKeys.searchResultsAppearHere.tr,
noResultsPlaceholder: LocaleKeys.noResultsFound.tr,
searchResultsPlaceholder: context.tr(LocaleKeys.searchResultsAppearHere),
noResultsPlaceholder: context.tr(LocaleKeys.noResultsFound),
);
}
}
12 changes: 11 additions & 1 deletion lib/presentation/intl/translations/translation_loader.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,15 @@ class CodegenLoader extends AssetLoader{
"noResultsFound": "No results found...",
"dynamicTheme": "Dynamic Theme"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"en_US": en_US};
static const Map<String,dynamic> hi_IN = {
"homePageTitle": "मुख्य पृष्ठ",
"searchPageTitle": "खोज",
"forecast": "पूर्वानुमान",
"favCitiesAppearHere": "आपके पसंदीदा शहरों का मौसम यहां दिखाई देगा। पसंदीदा में जोड़ने के लिए शहर खोजें।",
"startTypingToSearch": "खोजने के लिए टाइप करना प्रारंभ करें",
"searchResultsAppearHere": "खोज परिणाम यहां दिखाई देते हैं...",
"noResultsFound": "कोई परिणाम नहीं मिला...",
"dynamicTheme": "डायनामिक थीम"
};
static const Map<String, Map<String,dynamic>> mapLocales = {"en_US": en_US, "hi_IN": hi_IN};
}
39 changes: 29 additions & 10 deletions test/presentation/base/widget_tester_ext.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ extension WidgetTesterExt on WidgetTester {
fallbackLocale: const Locale("en", "US"),
assetLoader: const CodegenLoader(),
child: Builder(builder: (context) {
context.setLocale(const Locale("en", "US"));
return MaterialApp(
theme: material3LightTheme,
debugShowCheckedModeBanner: false,
darkTheme: material3DarkTheme,
themeMode: ThemeMode.dark,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
home: ProviderScope(
overrides: [
viewModelProvider.overrideWithProvider(fakeViewModelProvider),
Expand All @@ -56,20 +58,37 @@ extension WidgetTesterExt on WidgetTester {
devicePixelRatio: 3,
),
}) async {
TestWidgetsFlutterBinding.ensureInitialized();
SharedPreferences.setMockInitialValues({});
await EasyLocalization.ensureInitialized();
await pumpWidget(
MediaQuery(
data: mediaQueryData,
child: MaterialApp(
useInheritedMediaQuery: true,
home: ProviderScope(
overrides: [
viewModelProvider.overrideWithProvider(fakeViewModelProvider),
],
child: widget,
),
EasyLocalization(
supportedLocales: const [Locale("en", "US"), Locale("hi", "IN")],
path: "assets/translations",
fallbackLocale: const Locale("en", "US"),
assetLoader: const CodegenLoader(),
child: Builder(
builder: (context) {
context.setLocale(const Locale("en", "US"));
return MediaQuery(
data: mediaQueryData,
child: MaterialApp(
locale: context.locale,
useInheritedMediaQuery: true,
home: ProviderScope(
overrides: [
viewModelProvider
.overrideWithProvider(fakeViewModelProvider),
],
child: widget,
),
),
);
},
),
),
);
await pumpAndSettle();
}

Future loadWidget({
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 951a45e

Please sign in to comment.