diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/pick_up_recipe/.gitignore b/pick_up_recipe/.gitignore index b6323af..cffea90 100644 --- a/pick_up_recipe/.gitignore +++ b/pick_up_recipe/.gitignore @@ -45,4 +45,12 @@ app.*.map.json /android/app/release # FVM Version Cache -.fvm/ \ No newline at end of file +.fvm/ + +# Auto-generated files by build_runner +*.g.dart +*.freezed.dart +*.chopper.dart +*.injectable.dart +*.mocks.dart +*.gr.dart \ No newline at end of file diff --git a/pick_up_recipe/l10n.yaml b/pick_up_recipe/l10n.yaml new file mode 100644 index 0000000..c114495 --- /dev/null +++ b/pick_up_recipe/l10n.yaml @@ -0,0 +1,4 @@ +arb-dir: lib/l10n +template-arb-file: app_en.arb +output-localization-file: app_localizations.dart +nullable-getter: false \ No newline at end of file diff --git a/pick_up_recipe/lib/l10n/app_en.arb b/pick_up_recipe/lib/l10n/app_en.arb new file mode 100644 index 0000000..2fd4813 --- /dev/null +++ b/pick_up_recipe/lib/l10n/app_en.arb @@ -0,0 +1,75 @@ +{ + "@_LOGIN_FORM": {}, + "loginFormTitle": "Sign in to account", + "loginFormEmail": "Email", + "loginFormInvalidEmail": "Enter existing email", + "loginFormPassword": "Password", + "loginFormInvalidPassword": "Password must contain minimum 6 symbols", + "loginFormSignIn": "Sign in", + + "@_MAIL_CONFIRMATION_FORM": {}, + "mailConfirmationFormTitle": "Confirm your e-mail address", + "mailConfirmationFormCode": "Confirmation code", + "mailConfirmationFormInvalidCode": "Code must contain 6 symbols", + "mailConfirmationFormConfirm": "Confirm email", + + "@_REGISTRATION_FORM": {}, + "registrationFormTitle": "Create new account", + "registrationFormEmail": "Email", + "registrationFormInvalidEmail": "Enter existing email address", + "registrationFormPassword": "Password", + "registrationFormInvalidPassword": "Password must contain minimum of 6 symbols", + "registrationFormConfirmPassword": "Confirm password", + "registrationFormPasswordsUnmatch": "Passwords do not match", + "registrationFormRegister": "Register", + + "@_NEW_PACK_SCREEN": {}, + "newPackScreenTitle": "Add a new pack", + "newPackScreenSubtitle": "You can make a photo of your pack to recognise it", + "newPackScreenCamera": "Camera", + "newPackScreenGallery": "Gallery", + "newPackImageError": "Error fetching information from pack image", + "newPackName": "Name", + "newPackCountry": "Country", + "newPackScore": "SCA score", + "newPackDescriptors": "Descriptors", + "newPackDescriptor": "Descriptor", + "newPackVariety": "Variety", + "newPackMethods": "Processing methods", + "newPackMethod": "Method", + "newPackDate": "Roast date", + "newPackSend": "Send", + + "@_RECIPES": {}, + "recipesCoffee": "Coffee", + "recipesBrewed": "Brewed", + "recipesVolume": "ml", + + "@_AUTH_PAGE": {}, + "authPageTitle": "PickUpRecipe", + "authPageButtonRegistration": "Have an account? Sign in", + "authPageButtonVerifyEmail": "Have an account? Sign in", + "authPageButtonLogin": "Not registered? Sign up", + + "@_BREW_PAGE": {}, + "brewPageBrewed": "Brewed on", + "brewPageRecipeFor": "Recipe for pack", + "brewPageStart": "Start brewing!", + "brewPageStop": "Stop brewing", + "brewPageDegrees": "°C", + "brewPageMass": "g", + "brewPageVolume": "ml", + "brewPageGrind": "click", + + "@_RECIPE_PAGE": {}, + "recipePageChoose": "Choose brewing method", + "recipePageGenerate": "Generate", + "recipePageFor": "recipe for", + "recipePageChooseGenerate": "Choose brewing method to generate", + + "@_MAIN_PAGE": {}, + "mainPageLatest": "Latest Recipes", + "mainPageActive": "Active packs", + "mainPageHome": "Main", + "mainPageAdd": "Add pack" +} \ No newline at end of file diff --git a/pick_up_recipe/lib/l10n/app_ru.arb b/pick_up_recipe/lib/l10n/app_ru.arb new file mode 100644 index 0000000..4b7cc56 --- /dev/null +++ b/pick_up_recipe/lib/l10n/app_ru.arb @@ -0,0 +1,75 @@ +{ + "@_LOGIN_FORM": {}, + "loginFormTitle": "Вход в аккаунт", + "loginFormEmail": "Email", + "loginFormInvalidEmail": "Введите существующий email", + "loginFormPassword": "Пароль", + "loginFormInvalidPassword": "Пароль должен содержать хотя бы 6 символов", + "loginFormSignIn": "Войти", + + "@_MAIL_CONFIRMATION_FORM": {}, + "mailConfirmationFormTitle": "Подтверждение e-mail адреса", + "mailConfirmationFormCode": "Код подтверждения", + "mailConfirmationFormInvalidCode": "Код должен состоять из 6 символов", + "mailConfirmationFormConfirm": "Подтвердить email", + + "@_REGISTRATION_FORM": {}, + "registrationFormTitle": "Создать новый аккаунт", + "registrationFormEmail": "Email", + "registrationFormInvalidEmail": "Введите существующий emai", + "registrationFormPassword": "Пароль", + "registrationFormInvalidPassword": "Пароль должен содержать хотя бы 6 символов", + "registrationFormConfirmPassword": "Повторите пароль", + "registrationFormPasswordsUnmatch": "Пароли не совпадают", + "registrationFormRegister": "Зарегистрироваться", + + "@_NEW_PACK_SCREEN": {}, + "newPackScreenTitle": "Добавить новую пачку", + "newPackScreenSubtitle": "Вы можете добавить фото, чтобы распознать текст", + "newPackScreenCamera": "Камера", + "newPackScreenGallery": "Галерея", + "newPackImageError": "Не удалось получить информацию с изображения", + "newPackName": "Название", + "newPackCountry": "Страна", + "newPackScore": "Оценка SCA", + "newPackDescriptors": "Дескрипторы", + "newPackDescriptor": "Дескриптор", + "newPackVariety": "Сорт", + "newPackMethods": "Методы обработки", + "newPackMethod": "Метод", + "newPackDate": "Дата обжарки", + "newPackSend": "Отправить", + + "@_RECIPES": {}, + "recipesCoffee": "Кофе", + "recipesBrewed": "Заварен", + "recipesVolume": "мл", + + "@_AUTH_PAGE": {}, + "authPageTitle": "PickUpRecipe", + "authPageButtonRegistration": "Уже есть аккаунт? Войти", + "authPageButtonVerifyEmail": "Уже есть аккаунт? Войти", + "authPageButtonLogin": "Нет аккаунта? Зарегестрироваться", + + "@_BREW_PAGE": {}, + "brewPageBrewed": "Был заварен", + "brewPageRecipeFor": "Рецепт для зерна", + "brewPageStart": "Начать заваривать!", + "brewPageStop": "Закончить заваривать", + "brewPageDegrees": "°C", + "brewPageMass": "г", + "brewPageVolume": "мл", + "brewPageGrind": "помол", + + "@_RECIPE_PAGE": {}, + "recipePageChoose": "Выберите метод заваривания", + "recipePageGenerate": "Сгенерировать", + "recipePageFor": "рецепт для", + "recipePageChooseGenerate": "Выберите метод заваривания для генерации", + + "@_MAIN_PAGE": {}, + "mainPageLatest": "Недавние рецепты", + "mainPageActive": "Текущее зерно", + "mainPageHome": "Главная", + "mainPageAdd": "Добавить пачку" +} \ No newline at end of file diff --git a/pick_up_recipe/lib/l10n/s.dart b/pick_up_recipe/lib/l10n/s.dart new file mode 100644 index 0000000..f0a1e4e --- /dev/null +++ b/pick_up_recipe/lib/l10n/s.dart @@ -0,0 +1,19 @@ +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:flutter/widgets.dart'; + +class S { + static const locale = Locale('ru'); + + static const supportedLocales = [Locale('en'), Locale('ru')]; + + static const localizationDelegates = [ + GlobalWidgetsLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + AppLocalizations.delegate, + ]; + + static AppLocalizations of(BuildContext context) => + AppLocalizations.of(context); +} diff --git a/pick_up_recipe/lib/main.dart b/pick_up_recipe/lib/main.dart index 2472872..04e76e4 100644 --- a/pick_up_recipe/lib/main.dart +++ b/pick_up_recipe/lib/main.dart @@ -9,6 +9,7 @@ import 'package:pick_up_recipe/routing/app_router.dart'; import 'package:pick_up_recipe/src/features/authentication/provider/authentication_state_notifier.dart'; import 'package:pick_up_recipe/src/themes/dark_theme.dart'; import 'package:pick_up_recipe/src/themes/light_theme.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); @@ -58,6 +59,9 @@ class _MyAppState extends ConsumerState { routerConfig: AppRouter(ref).config(), theme: lightTheme, darkTheme: darkTheme, + localizationsDelegates: S.localizationDelegates, + supportedLocales: S.supportedLocales, + locale: S.locale, ); } } @@ -95,14 +99,14 @@ class _RootScreenState extends State { enableFeedback: false, selectedItemColor: Theme.of(context).colorScheme.primary, iconSize: 28, - items: const [ + items: [ BottomNavigationBarItem( - label: 'Main', - icon: Icon(Icons.coffee), + label: S.of(context).mainPageHome, + icon: const Icon(Icons.coffee), ), BottomNavigationBarItem( - label: 'Add pack', - icon: Icon(Icons.add), + label: S.of(context).mainPageAdd, + icon: const Icon(Icons.add), ), ], ), diff --git a/pick_up_recipe/lib/src/features/authentication/presentation/login_form_widget.dart b/pick_up_recipe/lib/src/features/authentication/presentation/login_form_widget.dart index 13e0a39..aec0b03 100644 --- a/pick_up_recipe/lib/src/features/authentication/presentation/login_form_widget.dart +++ b/pick_up_recipe/lib/src/features/authentication/presentation/login_form_widget.dart @@ -5,6 +5,7 @@ import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:pick_up_recipe/routing/app_router.dart'; import 'package:pick_up_recipe/src/features/authentication/provider/authentication_state_notifier.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class LoginFormWidget extends ConsumerStatefulWidget { const LoginFormWidget({super.key}); @@ -57,11 +58,11 @@ class _LoginFormWidgetState extends ConsumerState { Widget build(BuildContext context) { return Column( children: [ - const Align( + Align( alignment: Alignment.topLeft, child: Text( - 'Sign in to account', - style: TextStyle(fontSize: 18), + S.of(context).loginFormTitle, + style: const TextStyle(fontSize: 18), ), ), const SizedBox( @@ -75,7 +76,7 @@ class _LoginFormWidgetState extends ConsumerState { TextFormField( controller: _emailController, decoration: InputDecoration( - labelText: 'Email', + labelText: S.of(context).loginFormEmail, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -85,7 +86,7 @@ class _LoginFormWidgetState extends ConsumerState { ), validator: (value) { if (value!.isEmpty || !value.contains('@')) { - return 'Enter existing email'; + return S.of(context).loginFormInvalidEmail; } return null; }, @@ -95,7 +96,7 @@ class _LoginFormWidgetState extends ConsumerState { controller: _passwordController, obscureText: true, decoration: InputDecoration( - labelText: 'Password', + labelText: S.of(context).loginFormPassword, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -105,7 +106,7 @@ class _LoginFormWidgetState extends ConsumerState { ), validator: (value) { if (value!.isEmpty || value.length < 6) { - return 'Password must contain minimum 6 symbols'; + return S.of(context).loginFormInvalidPassword; } return null; }, @@ -125,7 +126,7 @@ class _LoginFormWidgetState extends ConsumerState { color: Theme.of(context).colorScheme.surface, ) : Text( - 'Sign in', + S.of(context).loginFormSignIn, style: TextStyle( fontSize: 20, color: Theme.of(context).colorScheme.surface, diff --git a/pick_up_recipe/lib/src/features/authentication/presentation/mail_confirmation_form_widget.dart b/pick_up_recipe/lib/src/features/authentication/presentation/mail_confirmation_form_widget.dart index 84d7d9a..1094b66 100644 --- a/pick_up_recipe/lib/src/features/authentication/presentation/mail_confirmation_form_widget.dart +++ b/pick_up_recipe/lib/src/features/authentication/presentation/mail_confirmation_form_widget.dart @@ -5,6 +5,7 @@ import 'package:pick_up_recipe/src/features/authentication/provider/authenticati import 'package:pick_up_recipe/src/features/authentication/provider/authentication_state_notifier.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; import 'package:pick_up_recipe/src/pages/authentication_page.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class MailConfirmationFormWidget extends ConsumerStatefulWidget { const MailConfirmationFormWidget({ @@ -54,11 +55,11 @@ class _MailConfirmationFormWidgetState Widget build(BuildContext context) { return Column( children: [ - const Align( + Align( alignment: Alignment.topLeft, child: Text( - 'Confirm your e-mail address', - style: TextStyle(fontSize: 18), + S.of(context).mailConfirmationFormTitle, + style: const TextStyle(fontSize: 18), ), ), const SizedBox( @@ -72,7 +73,7 @@ class _MailConfirmationFormWidgetState TextFormField( controller: _codeController, decoration: InputDecoration( - labelText: 'Confirmation code', + labelText: S.of(context).mailConfirmationFormCode, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -82,7 +83,7 @@ class _MailConfirmationFormWidgetState ), validator: (value) { if (value!.isEmpty || value.length != 6) { - return 'Code must contain 6 symbols'; + return S.of(context).mailConfirmationFormInvalidCode; } return null; }, @@ -102,7 +103,7 @@ class _MailConfirmationFormWidgetState color: Theme.of(context).colorScheme.surface, ) : Text( - 'Confirm email', + S.of(context).mailConfirmationFormConfirm, style: TextStyle( fontSize: 20, color: Theme.of(context).colorScheme.surface, diff --git a/pick_up_recipe/lib/src/features/authentication/presentation/registration_form_widget.dart b/pick_up_recipe/lib/src/features/authentication/presentation/registration_form_widget.dart index ab6d121..e598a0d 100644 --- a/pick_up_recipe/lib/src/features/authentication/presentation/registration_form_widget.dart +++ b/pick_up_recipe/lib/src/features/authentication/presentation/registration_form_widget.dart @@ -6,6 +6,7 @@ import 'package:pick_up_recipe/src/features/authentication/provider/authenticati import 'package:pick_up_recipe/src/features/authentication/provider/authentication_state_notifier.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; import 'package:pick_up_recipe/src/pages/authentication_page.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class RegistrationFormWidget extends ConsumerStatefulWidget { const RegistrationFormWidget({super.key}); @@ -58,11 +59,11 @@ class _RegistrationFormWidgetState Widget build(BuildContext context) { return Column( children: [ - const Align( + Align( alignment: Alignment.topLeft, child: Text( - 'Create new account', - style: TextStyle(fontSize: 18), + S.of(context).registrationFormTitle, + style: const TextStyle(fontSize: 18), ), ), const SizedBox(height: 20), @@ -74,7 +75,7 @@ class _RegistrationFormWidgetState TextFormField( controller: _emailController, decoration: InputDecoration( - labelText: 'Email', + labelText: S.of(context).registrationFormEmail, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -84,7 +85,7 @@ class _RegistrationFormWidgetState ), validator: (value) { if (value!.isEmpty || !value.contains('@')) { - return 'Enter existing email address'; + return S.of(context).registrationFormInvalidEmail; } return null; }, @@ -94,7 +95,7 @@ class _RegistrationFormWidgetState controller: _passwordController, obscureText: true, decoration: InputDecoration( - labelText: 'Password', + labelText: S.of(context).registrationFormPassword, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -104,7 +105,7 @@ class _RegistrationFormWidgetState ), validator: (value) { if (value!.isEmpty || value.length < 6) { - return 'Password must contain minimum of 6 symbols'; + return S.of(context).registrationFormInvalidPassword; } return null; }, @@ -114,7 +115,7 @@ class _RegistrationFormWidgetState controller: _confirmPasswordController, obscureText: true, decoration: InputDecoration( - labelText: 'Confirm Password', + labelText: S.of(context).registrationFormConfirmPassword, border: const OutlineInputBorder(), enabledBorder: OutlineInputBorder( borderSide: BorderSide( @@ -124,7 +125,7 @@ class _RegistrationFormWidgetState ), validator: (value) { if (value != _passwordController.text) { - return 'Passwords do not match'; + return S.of(context).registrationFormPasswordsUnmatch; } return null; }, @@ -144,7 +145,7 @@ class _RegistrationFormWidgetState color: Theme.of(context).colorScheme.surface, ) : Text( - 'Sign up', + S.of(context).registrationFormRegister, style: TextStyle( fontSize: 20, color: Theme.of(context).colorScheme.surface, diff --git a/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/info_inserting_camera_widget.dart b/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/info_inserting_camera_widget.dart index 9402f7c..eae16c0 100644 --- a/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/info_inserting_camera_widget.dart +++ b/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/info_inserting_camera_widget.dart @@ -9,6 +9,7 @@ import 'package:pick_up_recipe/src/features/packs/data_sources/remote/pack_servi import 'package:pick_up_recipe/core/logger.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class InsertingPackInfoCameraWidget extends ConsumerStatefulWidget { const InsertingPackInfoCameraWidget({super.key}); @@ -78,17 +79,17 @@ class _InsertingPackInfoCameraWidgetState Widget build(BuildContext context) { return Column( children: [ - const Text( - 'Add a new pack', - style: TextStyle(fontSize: 30), + Text( + S.of(context).newPackScreenTitle, + style: const TextStyle(fontSize: 30), textAlign: TextAlign.center, ), const SizedBox( height: 10, ), - const Text( - 'You can make a photo of your pack to recognise it', - style: TextStyle(fontSize: 20), + Text( + S.of(context).newPackScreenSubtitle, + style: const TextStyle(fontSize: 20), textAlign: TextAlign.center, ), const SizedBox( @@ -105,14 +106,14 @@ class _InsertingPackInfoCameraWidgetState onTap: () { getImage(true); }, - centerWidget: const Row( + centerWidget: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('Camera'), - SizedBox( + Text(S.of(context).newPackScreenCamera), + const SizedBox( width: 5, ), - Icon(Icons.camera_alt), + const Icon(Icons.camera_alt), ], ), buttonStyle: AppButtonStyle.secondary, @@ -129,14 +130,14 @@ class _InsertingPackInfoCameraWidgetState onTap: () { getImage(false); }, - centerWidget: const Row( + centerWidget: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text('Gallery'), - SizedBox( + Text(S.of(context).newPackScreenGallery), + const SizedBox( width: 5, ), - Icon(Icons.pageview), + const Icon(Icons.pageview), ], ), buttonStyle: AppButtonStyle.secondary, diff --git a/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/inserting_pack_info_widget.dart b/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/inserting_pack_info_widget.dart index ee8232a..e70c291 100644 --- a/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/inserting_pack_info_widget.dart +++ b/pick_up_recipe/lib/src/features/inserting_pack_info/presentation/inserting_pack_info_widget.dart @@ -9,6 +9,7 @@ import 'package:pick_up_recipe/src/features/inserting_pack_info/presentation/inf import 'package:pick_up_recipe/src/features/inserting_pack_info/presentation/info_inserting_number_widget.dart'; import 'package:pick_up_recipe/src/features/packs/application/state/active_packs_state.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class InsertingPackInfoWidget extends ConsumerStatefulWidget { const InsertingPackInfoWidget({super.key}); @@ -230,16 +231,16 @@ class _InsertingPackInfoWidgetState children: [ if (imageError != null) Text( - 'Error fetching information from pack image', + S.of(context).newPackImageError, style: TextStyle( fontSize: 16, color: Theme.of(context).colorScheme.error), ), _InputWidget( - title: 'Name', + title: S.of(context).newPackName, child: TextInputWithHints( hintsArray: possibleName, - labelText: 'Name', + labelText: S.of(context).newPackName, controller: _nameInputController, onChanged: _onTextChanged, ), @@ -248,10 +249,10 @@ class _InsertingPackInfoWidgetState height: 10, ), _InputWidget( - title: 'Country', + title: S.of(context).newPackCountry, child: TextInputWithHints( hintsArray: possibleCountries, - labelText: 'Country', + labelText: S.of(context).newPackCountry, controller: _countryInputController, onChanged: _onTextChanged, ), @@ -260,10 +261,10 @@ class _InsertingPackInfoWidgetState height: 10, ), _InputWidget( - title: 'SCA score', + title: S.of(context).newPackScore, child: NumberInput( controller: _scaScoreController, - hintText: "SCA score", + hintText: S.of(context).newPackScore, minimalPercentageNumber: 70, ), ), @@ -280,13 +281,13 @@ class _InsertingPackInfoWidgetState duration: const Duration(milliseconds: 300), child: Column( children: [ - const Align( + Align( alignment: Alignment.centerLeft, child: Padding( - padding: EdgeInsets.only(left: 12, top: 10), + padding: const EdgeInsets.only(left: 12, top: 10), child: Text( - 'Descriptors', - style: TextStyle(fontSize: 20), + S.of(context).newPackDescriptors, + style: const TextStyle(fontSize: 20), ), ), ), @@ -300,7 +301,8 @@ class _InsertingPackInfoWidgetState horizontal: 10, vertical: 10), child: TextInputWithHints( hintsArray: possibleDescriptors, - labelText: 'Descriptor ${index + 1}', + labelText: + '${S.of(context).newPackDescriptor} ${index + 1}', controller: _descriptorControllers[index], onChanged: _onTextChanged, ), @@ -314,10 +316,10 @@ class _InsertingPackInfoWidgetState height: 10, ), _InputWidget( - title: 'Variety', + title: S.of(context).newPackVariety, child: TextInputWithHints( hintsArray: possibleVariety, - labelText: 'Variety', + labelText: S.of(context).newPackVariety, controller: _varietyController, onChanged: _onTextChanged, ), @@ -335,13 +337,13 @@ class _InsertingPackInfoWidgetState duration: const Duration(milliseconds: 300), child: Column( children: [ - const Align( + Align( alignment: Alignment.centerLeft, child: Padding( - padding: EdgeInsets.only(left: 12, top: 10), + padding: const EdgeInsets.only(left: 12, top: 10), child: Text( - 'Processing methods', - style: TextStyle(fontSize: 20), + S.of(context).newPackMethods, + style: const TextStyle(fontSize: 20), ), ), ), @@ -355,7 +357,8 @@ class _InsertingPackInfoWidgetState horizontal: 10, vertical: 10), child: TextInputWithHints( hintsArray: possibleProcessingMethods, - labelText: 'Method ${index + 1}', + labelText: + '${S.of(context).newPackMethod} ${index + 1}', controller: _processingMethodControllers[index], onChanged: _onTextChanged, ), @@ -369,7 +372,7 @@ class _InsertingPackInfoWidgetState height: 10, ), DateInputField( - hintText: 'Roast date', + hintText: S.of(context).newPackDate, controller: _dateInputController, ), const SizedBox( @@ -383,7 +386,7 @@ class _InsertingPackInfoWidgetState centerWidget: isSubmitting ? const CircularProgressIndicator() : Text( - 'Отправить', + S.of(context).newPackSend, style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, diff --git a/pick_up_recipe/lib/src/features/recipes/presentation/recipe_small_card_widget.dart b/pick_up_recipe/lib/src/features/recipes/presentation/recipe_small_card_widget.dart index 410208c..8a9e015 100644 --- a/pick_up_recipe/lib/src/features/recipes/presentation/recipe_small_card_widget.dart +++ b/pick_up_recipe/lib/src/features/recipes/presentation/recipe_small_card_widget.dart @@ -13,6 +13,7 @@ import 'package:pick_up_recipe/src/features/recipes/presentation/recipe_tags_wid import 'package:pick_up_recipe/routing/app_router.dart'; import 'package:pick_up_recipe/src/features/recipes/domain/models/recipe_tag_model.dart'; import 'package:pick_up_recipe/src/mocked_recipes.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; String convertDate(String date) { return '${date.substring(8, 10)}.${date.substring(5, 7)}.${date.substring(0, 4)}'; @@ -133,12 +134,13 @@ class RecipeSmallCardWidgetState extends State Padding( padding: const EdgeInsets.symmetric(vertical: 7), child: Text( - _pack?.packName ?? 'Coffee', + _pack?.packName ?? S.of(context).recipesCoffee, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 21), ), ), - Text('Brewed ${convertDate(widget.recipe.date)}'), + Text( + '${S.of(context).recipesBrewed} ${convertDate(widget.recipe.date)}'), getTags(widget.recipe), ], ), diff --git a/pick_up_recipe/lib/src/features/recipes/presentation/recipe_step_animated_widget.dart b/pick_up_recipe/lib/src/features/recipes/presentation/recipe_step_animated_widget.dart index f0bc55b..9e70af9 100644 --- a/pick_up_recipe/lib/src/features/recipes/presentation/recipe_step_animated_widget.dart +++ b/pick_up_recipe/lib/src/features/recipes/presentation/recipe_step_animated_widget.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:percent_indicator/circular_percent_indicator.dart'; import 'package:pick_up_recipe/src/features/recipes/domain/models/recipe_step_model.dart'; import 'package:pick_up_recipe/src/features/recipes/presentation/recipe_icon_widget.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; class RecipeStepAnimatedWidget extends StatefulWidget { const RecipeStepAnimatedWidget({ @@ -78,7 +79,8 @@ class _RecipeStepAnimatedWidgetState extends State { ), const SizedBox(width: 10), RecipeIconWidget( - value: '${widget.step.water} мл', + value: + '${widget.step.water} ${S.of(context).recipesVolume}', icon: Icons.water_drop_outlined, color: Colors.blueAccent, ), diff --git a/pick_up_recipe/lib/src/pages/authentication_page.dart b/pick_up_recipe/lib/src/pages/authentication_page.dart index 547b262..5a79133 100644 --- a/pick_up_recipe/lib/src/pages/authentication_page.dart +++ b/pick_up_recipe/lib/src/pages/authentication_page.dart @@ -6,6 +6,7 @@ import 'package:pick_up_recipe/src/features/authentication/provider/authenticati import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; import '../features/authentication/presentation/login_form_widget.dart'; import '../features/authentication/presentation/registration_form_widget.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; @RoutePage() class AuthenticationPage extends ConsumerStatefulWidget { @@ -46,9 +47,9 @@ class _AuthenticationPageState extends ConsumerState { }; final buttonTitle = switch (mode) { - AuthPageMode.registration => "Have an account? Sign in", - AuthPageMode.verifyMail => "Have an account? Sign in", - AuthPageMode.login => "Not registered? Sign up", + AuthPageMode.registration => S.of(context).authPageButtonRegistration, + AuthPageMode.verifyMail => S.of(context).authPageButtonVerifyEmail, + AuthPageMode.login => S.of(context).authPageButtonLogin, }; return Scaffold( @@ -57,11 +58,11 @@ class _AuthenticationPageState extends ConsumerState { padding: const EdgeInsets.only(top: 50, left: 60, right: 60), child: ListView( children: [ - const Align( + Align( alignment: Alignment.center, child: Text( - 'PickUpRecipe', - style: TextStyle(fontSize: 30), + S.of(context).authPageTitle, + style: const TextStyle(fontSize: 30), )), const SizedBox( height: 50, diff --git a/pick_up_recipe/lib/src/pages/brew_page.dart b/pick_up_recipe/lib/src/pages/brew_page.dart index 66b6741..c1e5a6c 100644 --- a/pick_up_recipe/lib/src/pages/brew_page.dart +++ b/pick_up_recipe/lib/src/pages/brew_page.dart @@ -7,6 +7,7 @@ import 'package:pick_up_recipe/src/features/recipes/presentation/recipe_step_ani import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; import '../features/recipes/presentation/recipe_icon_widget.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; int getDuration(RecipeData recipe) { int recipeDuration = 0; @@ -99,14 +100,14 @@ class _BrewPageState extends State crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'Brewed on ${widget.recipe.device}', + '${S.of(context).brewPageBrewed} ${widget.recipe.device}', style: const TextStyle( fontSize: 30, fontWeight: FontWeight.w700, ), ), Text( - 'Рецепт для зерна ${widget.pack?.packName}', + '${S.of(context).brewPageRecipeFor} ${widget.pack?.packName}', style: const TextStyle(fontSize: 18), ), Padding( @@ -117,21 +118,23 @@ class _BrewPageState extends State children: [ RecipeIconWidget( value: - '${widget.recipe.temperature.toString()} °C', + '${widget.recipe.temperature.toString()} ${S.of(context).brewPageDegrees}', icon: Icons.thermostat_outlined, color: Colors.orange), RecipeIconWidget( - value: '${widget.recipe.load.toString()} г', + value: + '${widget.recipe.load.toString()} ${S.of(context).brewPageMass}', icon: Icons.scale_outlined, color: const Color.fromARGB(255, 154, 126, 101)), RecipeIconWidget( - value: '${widget.recipe.water.toString()} мл', + value: + '${widget.recipe.water.toString()} ${S.of(context).brewPageVolume}', icon: Icons.water_drop_outlined, color: Colors.blueAccent), RecipeIconWidget( value: - '${widget.recipe.grindStep.toString()} click', + '${widget.recipe.grindStep.toString()} ${S.of(context).brewPageGrind}', icon: Icons.blur_on_sharp, color: const Color.fromARGB(255, 205, 166, 255)), @@ -190,8 +193,8 @@ class _BrewPageState extends State }); }, child: Text(_isAnimationRunning - ? 'Stop brewing' - : 'Start brewing!'), + ? S.of(context).brewPageStop + : S.of(context).brewPageStart), ), ), ], diff --git a/pick_up_recipe/lib/src/pages/choosing_recipe_page.dart b/pick_up_recipe/lib/src/pages/choosing_recipe_page.dart index 83f0653..63509ba 100644 --- a/pick_up_recipe/lib/src/pages/choosing_recipe_page.dart +++ b/pick_up_recipe/lib/src/pages/choosing_recipe_page.dart @@ -9,6 +9,7 @@ import 'package:pick_up_recipe/src/features/recipes/data_sources/remote/recipe_s import 'package:pick_up_recipe/src/features/recipes/presentation/latest_recipes_widget.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; import 'package:pick_up_recipe/src/general_widgets/dropdown/custom_dropdown.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; @RoutePage() class ChoosingRecipePage extends ConsumerStatefulWidget { @@ -81,7 +82,7 @@ class _ChoosingRecipePageState extends ConsumerState { slivers: [ SliverToBoxAdapter( child: CustomDropdown( - placeholder: 'Choose brewing method', + placeholder: S.of(context).recipePageChoose, items: brewingMethods, onSelect: _onSelectBrewingMethod, ), @@ -98,18 +99,18 @@ class _ChoosingRecipePageState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ if (method != BrewingMethods.all) - const Text( - 'Generate', - style: TextStyle(fontSize: 24), + Text( + S.of(context).recipePageGenerate, + style: const TextStyle(fontSize: 24), ), method != BrewingMethods.all ? Text( - 'recipe for ${method?.getTitle()}', + '${S.of(context).recipePageFor} ${method?.getTitle()}', style: const TextStyle(fontSize: 14), ) - : const Text( - 'Choose brewing method to generate', - style: TextStyle(fontSize: 18), + : Text( + S.of(context).recipePageChooseGenerate, + style: const TextStyle(fontSize: 18), ), ], ), diff --git a/pick_up_recipe/lib/src/pages/main_page.dart b/pick_up_recipe/lib/src/pages/main_page.dart index 1195240..836f534 100644 --- a/pick_up_recipe/lib/src/pages/main_page.dart +++ b/pick_up_recipe/lib/src/pages/main_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:pick_up_recipe/src/features/packs/presentation/active_packs_widget.dart'; import 'package:pick_up_recipe/src/features/recipes/presentation/latest_recipes_widget.dart'; import 'package:pick_up_recipe/src/general_widgets/buttons/app_button.dart'; +import 'package:pick_up_recipe/l10n/s.dart'; @RoutePage() class MainPage extends StatelessWidget { @@ -13,13 +14,13 @@ class MainPage extends StatelessWidget { return Scaffold( body: CustomScrollView( slivers: [ - const SliverToBoxAdapter( + SliverToBoxAdapter( child: Padding( - padding: EdgeInsets.only(top: 70), + padding: const EdgeInsets.only(top: 70), child: Text( - 'Latest Recipes', + S.of(context).mainPageLatest, textAlign: TextAlign.center, - style: TextStyle( + style: const TextStyle( fontSize: 30, ), ), @@ -39,9 +40,9 @@ class MainPage extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - const Text( - 'Active packs', - style: TextStyle(fontSize: 30), + Text( + S.of(context).mainPageActive, + style: const TextStyle(fontSize: 30), ), const SizedBox( width: 20, diff --git a/pick_up_recipe/pubspec.lock b/pick_up_recipe/pubspec.lock index 654c42a..8832926 100644 --- a/pick_up_recipe/pubspec.lock +++ b/pick_up_recipe/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted - version: "2.11.0" + version: "2.12.0" auto_route: dependency: "direct main" description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" build: dependency: transitive description: @@ -181,10 +181,10 @@ packages: dependency: transitive description: name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" checked_yaml: dependency: transitive description: @@ -197,10 +197,10 @@ packages: dependency: transitive description: name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" code_builder: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: transitive description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: transitive description: @@ -269,10 +269,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" ffi: dependency: transitive description: @@ -351,7 +351,7 @@ packages: source: hosted version: "3.0.2" flutter_localizations: - dependency: transitive + dependency: "direct main" description: flutter source: sdk version: "0.0.0" @@ -561,18 +561,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.9" leak_tracker_testing: dependency: transitive description: @@ -609,10 +609,10 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.17" material_color_utilities: dependency: transitive description: @@ -625,10 +625,10 @@ packages: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.16.0" mime: dependency: transitive description: @@ -649,10 +649,10 @@ packages: dependency: transitive description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.9.1" path_provider: dependency: "direct main" description: @@ -849,7 +849,7 @@ packages: dependency: transitive description: flutter source: sdk - version: "0.0.99" + version: "0.0.0" sliver_text: dependency: "direct main" description: @@ -878,18 +878,18 @@ packages: dependency: transitive description: name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.10.1" stack_trace: dependency: transitive description: name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" url: "https://pub.dev" source: hosted - version: "1.11.1" + version: "1.12.1" state_notifier: dependency: transitive description: @@ -902,10 +902,10 @@ packages: dependency: transitive description: name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" stream_transform: dependency: transitive description: @@ -918,26 +918,26 @@ packages: dependency: transitive description: name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.4.1" term_glyph: dependency: transitive description: name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.2.2" test_api: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.4" timing: dependency: transitive description: @@ -966,10 +966,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.3.1" watcher: dependency: transitive description: @@ -1019,5 +1019,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.5.0 <4.0.0" + dart: ">=3.7.0-0 <4.0.0" flutter: ">=3.24.0" diff --git a/pick_up_recipe/pubspec.yaml b/pick_up_recipe/pubspec.yaml index 5bd989a..e5d1609 100644 --- a/pick_up_recipe/pubspec.yaml +++ b/pick_up_recipe/pubspec.yaml @@ -15,6 +15,8 @@ dependencies: encrypt_shared_preferences: ^0.8.2 flutter: sdk: flutter + flutter_localizations: + sdk: flutter flutter_date_pickers: ^0.4.3 flutter_riverpod: ^2.5.1 flutter_spinkit: ^5.2.1 @@ -37,4 +39,5 @@ dev_dependencies: auto_route_generator: ^8.0.0 flutter: - uses-material-design: true + generate: true + uses-material-design: true \ No newline at end of file