diff --git a/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..15338f2 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,3 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart diff --git a/lib/food_entry/enter_food_widget.dart b/lib/food_entry/enter_food_widget.dart index b0cfd2b..70b01b6 100644 --- a/lib/food_entry/enter_food_widget.dart +++ b/lib/food_entry/enter_food_widget.dart @@ -4,6 +4,7 @@ import 'package:calorimeter/storage/storage.dart'; import 'package:flutter/material.dart'; import 'package:calorimeter/food_entry/food_entry_bloc.dart'; import 'package:calorimeter/utils/row_with_spacers_widget.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class EnterFoodWidget extends StatefulWidget { final Function(BuildContext context, FoodEntryState entry) onAdd; @@ -42,8 +43,8 @@ class _EnterFoodWidgetState extends State { return TextFormField( controller: controller, focusNode: focusNode, - decoration: const InputDecoration( - label: Text("Name"), + decoration: InputDecoration( + label: Text(AppLocalizations.of(context)!.name), ), ); }, @@ -70,9 +71,11 @@ class _EnterFoodWidgetState extends State { }), TextField( textAlign: TextAlign.end, - decoration: const InputDecoration( - label: - Align(alignment: Alignment.centerRight, child: Text("Menge")), + decoration: InputDecoration( + label: Align( + alignment: Alignment.centerRight, + child: Text(AppLocalizations.of(context)!.amount), + ), ), keyboardType: TextInputType.number, controller: massController, @@ -80,9 +83,10 @@ class _EnterFoodWidgetState extends State { ), TextField( textAlign: TextAlign.end, - decoration: const InputDecoration( + decoration: InputDecoration( label: Align( - alignment: Alignment.centerRight, child: Text("kcal pro"))), + alignment: Alignment.centerRight, + child: Text(AppLocalizations.of(context)!.kcalper))), keyboardType: TextInputType.number, controller: kcalPerMassController, onSubmitted: (value) => onSubmitAction(), @@ -107,7 +111,8 @@ class _EnterFoodWidgetState extends State { try { massAsNumber = int.parse(massController.text.replaceAll(",", ".")); } catch (e) { - var snackbar = const SnackBar(content: Text("Menge muss eine Zahl sein")); + var snackbar = SnackBar( + content: Text(AppLocalizations.of(context)!.errAmountNotANumber)); ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar(snackbar); return; @@ -117,8 +122,8 @@ class _EnterFoodWidgetState extends State { kcalPerMassAsNumber = int.parse(kcalPerMassController.text.replaceAll(",", ".")); } catch (e) { - var snackbar = - const SnackBar(content: Text("'kcal pro 100g' muss eine Zahl sein")); + var snackbar = SnackBar( + content: Text(AppLocalizations.of(context)!.errKcalNotANumber)); ScaffoldMessenger.of(context).removeCurrentSnackBar(); ScaffoldMessenger.of(context).showSnackBar(snackbar); return; diff --git a/lib/food_entry/food_entry_widget.dart b/lib/food_entry/food_entry_widget.dart index 59530b9..bcb8551 100644 --- a/lib/food_entry/food_entry_widget.dart +++ b/lib/food_entry/food_entry_widget.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:calorimeter/food_entry/food_entry_bloc.dart'; import 'package:calorimeter/utils/row_with_spacers_widget.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class FoodEntryWidget extends StatefulWidget { final FoodEntryState entry; @@ -165,8 +166,8 @@ class _FoodEntryChangeDialogState extends State { child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: nameController, - decoration: const InputDecoration( - label: Text("Name"), + decoration: InputDecoration( + label: Text(AppLocalizations.of(context)!.name), ), ), ), @@ -177,8 +178,8 @@ class _FoodEntryChangeDialogState extends State { child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: massController, - decoration: const InputDecoration( - label: Text("Menge"), + decoration: InputDecoration( + label: Text(AppLocalizations.of(context)!.amount), ), ), ), @@ -189,8 +190,8 @@ class _FoodEntryChangeDialogState extends State { child: TextField( onSubmitted: (val) => _onSubmitAction(), controller: kcalPer100Controller, - decoration: const InputDecoration( - label: Text("kcal pro Menge"), + decoration: InputDecoration( + label: Text(AppLocalizations.of(context)!.kcalper), ), ), ) diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb new file mode 100644 index 0000000..fb7e989 --- /dev/null +++ b/lib/l10n/app_de.arb @@ -0,0 +1,13 @@ +{ + "ok": "OK", + "name": "Name", + "amount": "Menge in 100 g/ml", + "kcalper": "kcal pro Menge", + "kcalToday": "kcal heute", + "menu": "Menü", + "settings": "Einstellungen", + "yourSettings": "Deine persönlichen Einstellungen", + "dayLimit": "Kalorienlimit pro Tag", + "errAmountNotANumber": "Menge muss eine Zahl sein", + "errKcalNotANumber": "kcal muss eine Zahl sein" +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb new file mode 100644 index 0000000..c92ea54 --- /dev/null +++ b/lib/l10n/app_en.arb @@ -0,0 +1,13 @@ +{ + "ok": "OK", + "name": "Name", + "amount": "Amount in 100 grams/ml", + "kcalper": "kcal per amount", + "kcalToday": "kcal today", + "menu": "Menu", + "settings": "Settings", + "yourSettings": "Your personal settings", + "dayLimit": "Calorie limit per day", + "errAmountNotANumber": "Amount must be a number", + "errKcalNotANumber": "kcal must be a number" +} diff --git a/lib/main.dart b/lib/main.dart index 53033c4..c9c9bc4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,8 +8,8 @@ import 'package:calorimeter/utils/settings_bloc.dart'; import 'package:calorimeter/utils/theme_bloc.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:go_router/go_router.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; List entriesForToday = []; DateTime timeNow = DateTime.now(); @@ -17,8 +17,6 @@ DateTime timeNow = DateTime.now(); void main() async { WidgetsFlutterBinding.ensureInitialized(); - WidgetsFlutterBinding.ensureInitialized(); - var storage = await FoodStorage.create(); await storage.buildFoodLookupDatabase(); @@ -79,6 +77,7 @@ class MainApp extends StatelessWidget { } return MaterialApp.router( + //locale: Locale('de'), routerConfig: GoRouter( routes: [ GoRoute( @@ -91,14 +90,8 @@ class MainApp extends StatelessWidget { ), ], ), - localizationsDelegates: const [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: const [ - Locale('de'), - ], + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, theme: ThemeData( dividerTheme: const DividerThemeData(space: 2), colorScheme: ColorScheme.fromSeed( diff --git a/lib/perdate/perdate_pageview_controller.dart b/lib/perdate/perdate_pageview_controller.dart index b1445b4..376dc1b 100644 --- a/lib/perdate/perdate_pageview_controller.dart +++ b/lib/perdate/perdate_pageview_controller.dart @@ -58,8 +58,10 @@ class PerDatePageViewController extends StatelessWidget { child: Scaffold( appBar: AppBar( title: Builder(builder: (context) { - return Text(DateFormat.yMMMMd('de').format( - context.watch().displayedDate)); + return Text(DateFormat.yMMMMd( + Localizations.localeOf(context).toString()) + .format( + context.watch().displayedDate)); }), actions: const [ThemeSwitcherButton()], ), diff --git a/lib/utils/app_drawer.dart b/lib/utils/app_drawer.dart index 1a420ec..7cf7300 100644 --- a/lib/utils/app_drawer.dart +++ b/lib/utils/app_drawer.dart @@ -2,6 +2,7 @@ /* Copyright (C) 2024 Marco Groß */ import 'package:calorimeter/utils/settings.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class AppDrawer extends StatelessWidget { const AppDrawer({ @@ -19,16 +20,17 @@ class AppDrawer extends StatelessWidget { color: Colors.redAccent, ), child: ListTile( - leading: IconButton( - icon: const Icon(Icons.close), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - title: const Text('Menü')), + leading: IconButton( + icon: const Icon(Icons.close), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + title: Text(AppLocalizations.of(context)!.menu), + ), ), ListTile( - title: const Text('Einstellungen'), + title: Text(AppLocalizations.of(context)!.settings), trailing: const Icon(Icons.settings), onTap: () { Navigator.of(context).pop(); diff --git a/lib/utils/calendar_floating_button.dart b/lib/utils/calendar_floating_button.dart index bb4a7ee..698bf01 100644 --- a/lib/utils/calendar_floating_button.dart +++ b/lib/utils/calendar_floating_button.dart @@ -15,7 +15,6 @@ class CalendarFAB extends StatelessWidget { return FloatingActionButton( onPressed: () async { var datePicked = await showDatePicker( - locale: const Locale('de'), context: context, initialDate: startFromDate, currentDate: DateTimeHelper.now(), diff --git a/lib/utils/settings.dart b/lib/utils/settings.dart index 6077cf8..3c37a96 100644 --- a/lib/utils/settings.dart +++ b/lib/utils/settings.dart @@ -5,6 +5,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calorimeter/utils/app_drawer.dart'; import 'package:calorimeter/utils/settings_bloc.dart'; import 'package:settings_ui/settings_ui.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class SettingsWidget extends StatefulWidget { const SettingsWidget({super.key}); @@ -23,33 +24,24 @@ class _SettingsWidgetState extends State { builder: (context, state) { return SettingsList(sections: [ SettingsSection( - title: const Text('Deine persönlichen Einstellungen'), + title: Text(AppLocalizations.of(context)!.yourSettings), tiles: [ SettingsTile.navigation( leading: const Icon(Icons.food_bank), - title: const Text('Kalorienlimit pro Tag'), + title: Text(AppLocalizations.of(context)!.dayLimit), value: Text(state.kcalLimit.toString()), onPressed: (context) async { await showDialog( builder: (ctx) { return AlertDialog( - title: const Text("Kalorienlimit pro Tag"), - content: TextField(controller: kcalPerDayCtrl), + title: Text(AppLocalizations.of(context)!.dayLimit), + content: TextField( + controller: kcalPerDayCtrl, + onSubmitted: (val) => submitDailyKcal()), actions: [ TextButton( - onPressed: () { - double setting; - try { - setting = - double.parse(kcalPerDayCtrl.text); - } catch (e) { - setting = 2000.0; - } - context.read().add( - DailyKcalLimitUpdated(kcal: setting)); - Navigator.of(context).pop(); - }, - child: const Text('Ok')) + onPressed: () => submitDailyKcal(), + child: Text(AppLocalizations.of(context)!.ok)) ], ); }, @@ -60,7 +52,18 @@ class _SettingsWidgetState extends State { ]); }), drawer: const AppDrawer(), - appBar: AppBar(title: const Text('Einstellungen')), + appBar: AppBar(title: Text(AppLocalizations.of(context)!.settings)), ); } + + void submitDailyKcal() { + double setting; + try { + setting = double.parse(kcalPerDayCtrl.text); + } catch (e) { + setting = 2000.0; + } + context.read().add(DailyKcalLimitUpdated(kcal: setting)); + Navigator.of(context).pop(); + } } diff --git a/lib/utils/sum_widget.dart b/lib/utils/sum_widget.dart index 349ca77..5cd32bc 100644 --- a/lib/utils/sum_widget.dart +++ b/lib/utils/sum_widget.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:calorimeter/food_entry/food_entry_bloc.dart'; import 'package:calorimeter/utils/settings_bloc.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class SumWidget extends StatelessWidget { final DateTime date; @@ -48,7 +49,7 @@ class SumWidget extends StatelessWidget { return Align( alignment: Alignment.centerLeft, child: Text( - 'kcal heute: ${sum.ceil().toString()}/${settingsState.kcalLimit.ceil()}', + '${AppLocalizations.of(context)!.kcalToday}: ${sum.ceil().toString()}/${settingsState.kcalLimit.ceil()}', style: Theme.of(context) .textTheme .bodyLarge! diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt new file mode 100644 index 0000000..891b3ca --- /dev/null +++ b/metadata/en-US/full_description.txt @@ -0,0 +1,2 @@ +With Calorimeter you can track your daily calorie intake. +As simple as it gets. diff --git a/metadata/en-US/short_description.txt b/metadata/en-US/short_description.txt new file mode 100644 index 0000000..101463d --- /dev/null +++ b/metadata/en-US/short_description.txt @@ -0,0 +1 @@ +Track your calories! diff --git a/metadata/en-US/title.txt b/metadata/en-US/title.txt new file mode 100644 index 0000000..8be7ad7 --- /dev/null +++ b/metadata/en-US/title.txt @@ -0,0 +1 @@ +Calorimeter diff --git a/pubspec.yaml b/pubspec.yaml index 3238cfd..368be06 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dev_dependencies: flutter: uses-material-design: true + generate: true flutter_launcher_icons: android: "launcher_icon"