Skip to content

Commit 7eef202

Browse files
feat(ref: no-ref): add translations
1 parent 27cfa05 commit 7eef202

17 files changed

+264
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:get/get.dart';
2+
3+
import '../../screens/home/title/title.translation.dart' as home_title;
4+
import '../../screens/home/todo/add-task/add-task.translation.dart'
5+
as home_add_task;
6+
import '../../screens/home/todo/filter-panel/filter-panel.translation.dart'
7+
as home_filter_panel;
8+
9+
class AppTranslation extends GetxService {
10+
AppTranslation();
11+
12+
Map<String, Map<String, String>> translationsKeys =
13+
<String, Map<String, String>>{
14+
'en': en,
15+
'uk': uk,
16+
'ru': ru,
17+
};
18+
19+
void _combineTranslations(Map<String, String> enTranslations,
20+
Map<String, String> ukTranslations, Map<String, String> ruTranslations) {
21+
translationsKeys['en']!.addAll(enTranslations);
22+
translationsKeys['uk']!.addAll(ukTranslations);
23+
translationsKeys['ru']!.addAll(ruTranslations);
24+
}
25+
26+
Map<String, Map<String, String>> combineAllTranslations() {
27+
_combineTranslations(
28+
home_title.en,
29+
home_title.uk,
30+
home_title.ru,
31+
);
32+
33+
_combineTranslations(
34+
home_add_task.en,
35+
home_add_task.uk,
36+
home_add_task.ru,
37+
);
38+
39+
_combineTranslations(
40+
home_filter_panel.en,
41+
home_filter_panel.uk,
42+
home_filter_panel.ru,
43+
);
44+
45+
return translationsKeys;
46+
}
47+
}
48+
49+
final Map<String, String> en = <String, String>{};
50+
final Map<String, String> uk = <String, String>{};
51+
final Map<String, String> ru = <String, String>{};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'package:get/get.dart';
2+
3+
abstract class Translation {}
4+
5+
extension Translations on Translation {
6+
String get st => '$this';
7+
String get tr => st.tr;
8+
}
9+
10+
extension MapEnumExtensions on Map<Translation, String> {
11+
Map<String, String> get st => Map<String, String>.fromEntries(entries.map(
12+
(MapEntry<Translation, String> entry) =>
13+
MapEntry<String, String>(entry.key.st, entry.value)));
14+
}

lib/main.dart

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import 'package:flutter/material.dart';
22
import 'package:get/get.dart';
3+
import 'common/app-translation/app-translation.dart';
34
import 'screens/home/home.binding.dart';
45
import 'screens/home/home.screen.dart';
56

6-
void main() {
7+
Future<void> main() async {
8+
await HomeBinding().dependencies();
9+
710
runApp(const MyApp());
811
}
912

@@ -14,5 +17,8 @@ class MyApp extends StatelessWidget {
1417
Widget build(BuildContext context) => GetMaterialApp(
1518
initialBinding: HomeBinding(),
1619
home: const HomeScreen(),
20+
translationsKeys: Get.find<AppTranslation>().combineAllTranslations(),
21+
locale: const Locale('en'),
22+
fallbackLocale: const Locale('en'),
1723
);
1824
}

lib/screens/home/home.binding.dart

+4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import 'package:get/get.dart';
2+
import '../../common/app-translation/app-translation.dart';
3+
import 'language-switcher/language-switcher.controller.dart';
24
import 'todo/add-task/add-task.controller.dart';
35
import 'todo/filter-panel/filter-panel.controller.dart';
46
import 'todo/task-list-item/task-list-item.controller.dart';
@@ -8,7 +10,9 @@ class HomeBinding extends Bindings {
810
@override
911
Future<void> dependencies() async {
1012
Get
13+
..lazyPut(AppTranslation.new)
1114
..lazyPut(TodoService.new)
15+
..lazyPut(LocaleController.new)
1216
..lazyPut(() => AddTaskController(Get.find()))
1317
..lazyPut(() => FilterPanelController(Get.find()))
1418
..lazyPut(() => TaskListItemController(Get.find(), Get.find()));

lib/screens/home/home.screen.dart

+7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import 'language-switcher/language-switcher.dart';
23
import 'todo/todo.widget.dart';
34
import '../home/title/title.widget.dart';
45

@@ -10,6 +11,12 @@ class HomeScreen extends StatelessWidget {
1011
body: ListView(
1112
children: const <Widget>[
1213
Center(child: TitleWidget()),
14+
Padding(
15+
padding: EdgeInsets.only(bottom: 20),
16+
child: Center(
17+
child: LanguageSwitcher(),
18+
),
19+
),
1320
TodoWidget(),
1421
],
1522
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'package:get/get.dart';
2+
import 'language-switcher.enum.dart';
3+
4+
class LocaleController extends GetxController {
5+
final Rx<Language> currentLanguage = Language.en.obs;
6+
7+
List<Language> get languages => Language.values;
8+
9+
void updateLocale(Language language) {
10+
currentLanguage.value = language;
11+
Get.updateLocale(language.locale);
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// import 'package:flutter/material.dart';
2+
// import 'package:get/get.dart';
3+
// import 'language-switcher.controller.dart';
4+
//
5+
// class LanguageSwitcher extends GetView<LocaleController> {
6+
// const LanguageSwitcher({super.key});
7+
//
8+
// @override
9+
// Widget build(BuildContext context) => Obx(() => DropdownButton<Locale>(
10+
// value: controller.locales.firstWhere(
11+
// (Locale locale) =>
12+
// locale.languageCode ==
13+
// controller.currentLocale.value.languageCode,
14+
// orElse: () => controller.locales.first,
15+
// ),
16+
// onChanged: (Locale? locale) {
17+
// if (locale != null) {
18+
// controller.updateLocale(locale);
19+
// }
20+
// },
21+
// items: controller.locales
22+
// .map<DropdownMenuItem<Locale>>(
23+
// (Locale locale) => DropdownMenuItem<Locale>(
24+
// value: locale,
25+
// child: Text(controller.localeNames[locale.languageCode] ??
26+
// locale.languageCode),
27+
// ))
28+
// .toList(),
29+
// ));
30+
// }
31+
import 'package:flutter/material.dart';
32+
import 'package:get/get.dart';
33+
import 'language-switcher.controller.dart';
34+
import 'language-switcher.enum.dart';
35+
36+
class LanguageSwitcher extends GetView<LocaleController> {
37+
const LanguageSwitcher({super.key});
38+
39+
@override
40+
Widget build(BuildContext context) => Obx(() => DropdownButton<Language>(
41+
value: controller.currentLanguage.value,
42+
onChanged: (Language? language) {
43+
if (language != null) {
44+
controller.updateLocale(language);
45+
}
46+
},
47+
items: controller.languages
48+
.map<DropdownMenuItem<Language>>(
49+
(Language language) => DropdownMenuItem<Language>(
50+
value: language,
51+
child: Text(language.title),
52+
))
53+
.toList(),
54+
));
55+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import 'dart:ui';
2+
3+
enum Language {
4+
en(Locale('en'), 'English'),
5+
ru(Locale('ru'), 'Русский'),
6+
uk(Locale('uk'), 'Українська');
7+
8+
const Language(this.locale, this.title);
9+
10+
final Locale locale;
11+
final String title;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import '../../../common/app-translation/translation.extensions.dart';
2+
3+
enum TitleTranslationNames implements Translation {
4+
title,
5+
}
6+
7+
final Map<String, String> en = <TitleTranslationNames, String>{
8+
TitleTranslationNames.title: 'todos',
9+
}.st;
10+
11+
final Map<String, String> ru = <TitleTranslationNames, String>{
12+
TitleTranslationNames.title: 'Список задач',
13+
}.st;
14+
15+
final Map<String, String> uk = <TitleTranslationNames, String>{
16+
TitleTranslationNames.title: 'Список завдань',
17+
}.st;

lib/screens/home/title/title.widget.dart

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import 'package:flutter/material.dart';
22

3+
import 'title.translation.dart';
4+
import '../../../common/app-translation/translation.extensions.dart';
5+
36
class TitleWidget extends StatelessWidget {
47
const TitleWidget({super.key});
58

69
@override
7-
Widget build(BuildContext context) => const Padding(
8-
padding: EdgeInsets.only(top: 50, bottom: 20),
10+
Widget build(BuildContext context) => Padding(
11+
padding: const EdgeInsets.only(top: 50, bottom: 20),
912
child: Text(
10-
'todos',
11-
style: TextStyle(
13+
TitleTranslationNames.title.tr,
14+
style: const TextStyle(
1215
fontSize: 80,
1316
fontWeight: FontWeight.w300,
1417
color: Colors.red,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import '../../../../common/app-translation/translation.extensions.dart';
2+
3+
enum AddTaskTranslationNames implements Translation {
4+
title,
5+
}
6+
7+
final Map<String, String> en = <AddTaskTranslationNames, String>{
8+
AddTaskTranslationNames.title: 'What needs to be done?',
9+
}.st;
10+
11+
final Map<String, String> ru = <AddTaskTranslationNames, String>{
12+
AddTaskTranslationNames.title: 'Что нужно сделать?',
13+
}.st;
14+
15+
final Map<String, String> uk = <AddTaskTranslationNames, String>{
16+
AddTaskTranslationNames.title: 'Що потрібно зробити?',
17+
}.st;

lib/screens/home/todo/add-task/add-task.widget.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'package:flutter/material.dart';
22
import 'package:get/get.dart';
3+
import '../../../../common/app-translation/translation.extensions.dart';
34
import '../../../../common/input/input.widget.dart';
45
import 'add-task.controller.dart';
6+
import 'add-task.translation.dart';
57

68
class AddTaskWidget extends GetView<AddTaskController> {
79
const AddTaskWidget({super.key});
@@ -16,7 +18,7 @@ class AddTaskWidget extends GetView<AddTaskController> {
1618
child: InputWidget(
1719
textController: controller.textController,
1820
focusNode: controller.focusNode,
19-
hintText: 'What needs to be done?',
21+
hintText: AddTaskTranslationNames.title.tr,
2022
onSubmitted: controller.addTask,
2123
),
2224
);
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1+
import '../../../../common/app-translation/translation.extensions.dart';
2+
import 'filter-panel.translation.dart';
3+
14
enum FilterType {
2-
all('All'),
3-
active('Active'),
4-
completed('Completed');
5+
all(FilterPanelTranslationNames.all),
6+
active(FilterPanelTranslationNames.active),
7+
completed(FilterPanelTranslationNames.completed);
8+
9+
const FilterType(this.translationKey);
510

6-
const FilterType(this.type);
11+
final FilterPanelTranslationNames translationKey;
712

8-
final String type;
13+
String get type => translationKey.tr;
914
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import '../../../../common/app-translation/translation.extensions.dart';
2+
3+
enum FilterPanelTranslationNames implements Translation {
4+
clearItems,
5+
itemsLeft,
6+
all,
7+
active,
8+
completed
9+
}
10+
11+
final Map<String, String> en = <FilterPanelTranslationNames, String>{
12+
FilterPanelTranslationNames.clearItems: 'Clear completed',
13+
FilterPanelTranslationNames.all: 'All',
14+
FilterPanelTranslationNames.active: 'Active',
15+
FilterPanelTranslationNames.completed: 'Completed',
16+
FilterPanelTranslationNames.itemsLeft: '@count items left',
17+
}.st;
18+
19+
final Map<String, String> ru = <FilterPanelTranslationNames, String>{
20+
FilterPanelTranslationNames.clearItems: 'Очистить выполненные',
21+
FilterPanelTranslationNames.all: 'Все',
22+
FilterPanelTranslationNames.active: 'Активные',
23+
FilterPanelTranslationNames.completed: 'Выполненные',
24+
FilterPanelTranslationNames.itemsLeft:
25+
'@count элемент остался|@count элемента осталось|@count элементов осталось',
26+
}.st;
27+
28+
final Map<String, String> uk = <FilterPanelTranslationNames, String>{
29+
FilterPanelTranslationNames.clearItems: 'Очистити виконані',
30+
FilterPanelTranslationNames.all: 'Усі',
31+
FilterPanelTranslationNames.active: 'Активні',
32+
FilterPanelTranslationNames.completed: 'Виконані',
33+
FilterPanelTranslationNames.itemsLeft:
34+
'@count елемент залишився|@count елементи залишились|@count елементів залишилось',
35+
}.st;

lib/screens/home/todo/filter-panel/filter-panel.widget.dart

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import 'package:flutter/material.dart';
22
import 'package:get/get.dart';
3+
import '../../../../common/app-translation/translation.extensions.dart';
34
import '../../../../common/button/button.widget.dart';
45
import 'filter-panel-buttons/filter-panel-buttons.dart';
56
import 'filter-panel.controller.dart';
7+
import 'filter-panel.translation.dart';
68

79
class FilterPanelWidget extends GetView<FilterPanelController> {
810
const FilterPanelWidget({super.key});
@@ -29,7 +31,7 @@ class FilterPanelWidget extends GetView<FilterPanelController> {
2931
if (!isMobile) const FilterPanelButtons(),
3032
ButtonWidget(
3133
onTap: controller.clearCompleted,
32-
title: 'Clear completed',
34+
title: FilterPanelTranslationNames.clearItems.tr,
3335
),
3436
],
3537
),

pubspec.lock

+8
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ packages:
256256
url: "https://pub.dev"
257257
source: hosted
258258
version: "4.2.0"
259+
intl:
260+
dependency: "direct main"
261+
description:
262+
name: intl
263+
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
264+
url: "https://pub.dev"
265+
source: hosted
266+
version: "0.19.0"
259267
jsdaddy_custom_lints:
260268
dependency: "direct dev"
261269
description:

pubspec.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ dependencies:
1212
sdk: flutter
1313
get: ^4.6.6
1414
cupertino_icons: ^1.0.8
15+
intl: ^0.19.0
1516

1617
dev_dependencies:
1718
flutter_test:

0 commit comments

Comments
 (0)