Adds localization support with English and Russian

Initializes internationalization (i18n) for the application.

Introduces `AppLocalizations` to manage localized strings, along with
English and Russian translations.

Configures Flutter to use the localization delegates and supported locales.
This allows the app to display text in the user's preferred language.
This commit is contained in:
2025-06-29 23:04:28 +03:00
parent 42f8e20bf0
commit 82af8ac11a
5 changed files with 584 additions and 2 deletions
+3
View File
@@ -0,0 +1,3 @@
{
"dart.flutterSdkPath": "C:\\Sanders\\Flutter\\flutter_windows_3.32.2-stable\\flutter"
}
+344
View File
@@ -0,0 +1,344 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:intl/intl.dart' as intl;
import 'app_localizations_en.dart';
import 'app_localizations_ru.dart';
// ignore_for_file: type=lint
/// Callers can lookup localized strings with an instance of AppLocalizations
/// returned by `AppLocalizations.of(context)`.
///
/// Applications need to include `AppLocalizations.delegate()` in their app's
/// `localizationDelegates` list, and the locales they support in the app's
/// `supportedLocales` list. For example:
///
/// ```dart
/// import 'l10n/app_localizations.dart';
///
/// return MaterialApp(
/// localizationsDelegates: AppLocalizations.localizationsDelegates,
/// supportedLocales: AppLocalizations.supportedLocales,
/// home: MyApplicationHome(),
/// );
/// ```
///
/// ## Update pubspec.yaml
///
/// Please make sure to update your pubspec.yaml to include the following
/// packages:
///
/// ```yaml
/// dependencies:
/// # Internationalization support.
/// flutter_localizations:
/// sdk: flutter
/// intl: any # Use the pinned version from flutter_localizations
///
/// # Rest of dependencies
/// ```
///
/// ## iOS Applications
///
/// iOS applications define key application metadata, including supported
/// locales, in an Info.plist file that is built into the application bundle.
/// To configure the locales supported by your app, youll need to edit this
/// file.
///
/// First, open your projects ios/Runner.xcworkspace Xcode workspace file.
/// Then, in the Project Navigator, open the Info.plist file under the Runner
/// projects Runner folder.
///
/// Next, select the Information Property List item, select Add Item from the
/// Editor menu, then select Localizations from the pop-up menu.
///
/// Select and expand the newly-created Localizations item then, for each
/// locale your application supports, add a new item and select the locale
/// you wish to add from the pop-up menu in the Value field. This list should
/// be consistent with the languages listed in the AppLocalizations.supportedLocales
/// property.
abstract class AppLocalizations {
AppLocalizations(String locale)
: localeName = intl.Intl.canonicalizedLocale(locale.toString());
final String localeName;
static AppLocalizations? of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations);
}
static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();
/// A list of this localizations delegate along with the default localizations
/// delegates.
///
/// Returns a list of localizations delegates containing this delegate along with
/// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
/// and GlobalWidgetsLocalizations.delegate.
///
/// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates =
<LocalizationsDelegate<dynamic>>[
delegate,
GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
];
/// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('ru'),
];
/// No description provided for @appTitle.
///
/// In en, this message translates to:
/// **'Budget App'**
String get appTitle;
/// No description provided for @homePageTitle.
///
/// In en, this message translates to:
/// **'Home'**
String get homePageTitle;
/// No description provided for @reportsPageTitle.
///
/// In en, this message translates to:
/// **'Reports'**
String get reportsPageTitle;
/// No description provided for @settingsPageTitle.
///
/// In en, this message translates to:
/// **'Settings'**
String get settingsPageTitle;
/// No description provided for @addTransactionButton.
///
/// In en, this message translates to:
/// **'Add new transaction'**
String get addTransactionButton;
/// No description provided for @noTransactionsText.
///
/// In en, this message translates to:
/// **'No transactions yet'**
String get noTransactionsText;
/// No description provided for @loadingTransactionsText.
///
/// In en, this message translates to:
/// **'Loading transactions...'**
String get loadingTransactionsText;
/// No description provided for @transactionErrorText.
///
/// In en, this message translates to:
/// **'Error: {message}'**
String transactionErrorText(Object message);
/// No description provided for @loginPageTitle.
///
/// In en, this message translates to:
/// **'Login'**
String get loginPageTitle;
/// No description provided for @nameFieldLabel.
///
/// In en, this message translates to:
/// **'Name'**
String get nameFieldLabel;
/// No description provided for @emailFieldLabel.
///
/// In en, this message translates to:
/// **'Email'**
String get emailFieldLabel;
/// No description provided for @nameFieldEmptyError.
///
/// In en, this message translates to:
/// **'Please enter your name'**
String get nameFieldEmptyError;
/// No description provided for @emailFieldEmptyError.
///
/// In en, this message translates to:
/// **'Please enter your email'**
String get emailFieldEmptyError;
/// No description provided for @loginButtonText.
///
/// In en, this message translates to:
/// **'Login / Register'**
String get loginButtonText;
/// No description provided for @darkModeSetting.
///
/// In en, this message translates to:
/// **'Dark Theme'**
String get darkModeSetting;
/// No description provided for @darkModeDescription.
///
/// In en, this message translates to:
/// **'Toggle between light and dark theme'**
String get darkModeDescription;
/// No description provided for @languageSetting.
///
/// In en, this message translates to:
/// **'Language'**
String get languageSetting;
/// No description provided for @languageDescription.
///
/// In en, this message translates to:
/// **'Change application language'**
String get languageDescription;
/// No description provided for @russianLanguage.
///
/// In en, this message translates to:
/// **'Russian'**
String get russianLanguage;
/// No description provided for @englishLanguage.
///
/// In en, this message translates to:
/// **'English'**
String get englishLanguage;
/// No description provided for @defaultUser.
///
/// In en, this message translates to:
/// **'Default User'**
String get defaultUser;
/// No description provided for @currencySetting.
///
/// In en, this message translates to:
/// **'Default Currency'**
String get currencySetting;
/// No description provided for @currencyDescription.
///
/// In en, this message translates to:
/// **'Set the default currency for transactions'**
String get currencyDescription;
/// No description provided for @transactionsHistoryTitle.
///
/// In en, this message translates to:
/// **'Transactions History'**
String get transactionsHistoryTitle;
/// No description provided for @balance.
///
/// In en, this message translates to:
/// **'Balance'**
String get balance;
/// No description provided for @income.
///
/// In en, this message translates to:
/// **'Income'**
String get income;
/// No description provided for @expense.
///
/// In en, this message translates to:
/// **'Expense'**
String get expense;
/// No description provided for @amount.
///
/// In en, this message translates to:
/// **'Amount'**
String get amount;
/// No description provided for @vendor.
///
/// In en, this message translates to:
/// **'Vendor'**
String get vendor;
/// No description provided for @category.
///
/// In en, this message translates to:
/// **'Category'**
String get category;
/// No description provided for @date.
///
/// In en, this message translates to:
/// **'Date'**
String get date;
/// No description provided for @requiredField.
///
/// In en, this message translates to:
/// **'Required field'**
String get requiredField;
/// No description provided for @invalidNumber.
///
/// In en, this message translates to:
/// **'Invalid number'**
String get invalidNumber;
/// No description provided for @cancel.
///
/// In en, this message translates to:
/// **'Cancel'**
String get cancel;
/// No description provided for @save.
///
/// In en, this message translates to:
/// **'Save'**
String get save;
}
class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();
@override
Future<AppLocalizations> load(Locale locale) {
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
}
@override
bool isSupported(Locale locale) =>
<String>['en', 'ru'].contains(locale.languageCode);
@override
bool shouldReload(_AppLocalizationsDelegate old) => false;
}
AppLocalizations lookupAppLocalizations(Locale locale) {
// Lookup logic when only language code is specified.
switch (locale.languageCode) {
case 'en':
return AppLocalizationsEn();
case 'ru':
return AppLocalizationsRu();
}
throw FlutterError(
'AppLocalizations.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.',
);
}
+117
View File
@@ -0,0 +1,117 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for English (`en`).
class AppLocalizationsEn extends AppLocalizations {
AppLocalizationsEn([String locale = 'en']) : super(locale);
@override
String get appTitle => 'Budget App';
@override
String get homePageTitle => 'Home';
@override
String get reportsPageTitle => 'Reports';
@override
String get settingsPageTitle => 'Settings';
@override
String get addTransactionButton => 'Add new transaction';
@override
String get noTransactionsText => 'No transactions yet';
@override
String get loadingTransactionsText => 'Loading transactions...';
@override
String transactionErrorText(Object message) {
return 'Error: $message';
}
@override
String get loginPageTitle => 'Login';
@override
String get nameFieldLabel => 'Name';
@override
String get emailFieldLabel => 'Email';
@override
String get nameFieldEmptyError => 'Please enter your name';
@override
String get emailFieldEmptyError => 'Please enter your email';
@override
String get loginButtonText => 'Login / Register';
@override
String get darkModeSetting => 'Dark Theme';
@override
String get darkModeDescription => 'Toggle between light and dark theme';
@override
String get languageSetting => 'Language';
@override
String get languageDescription => 'Change application language';
@override
String get russianLanguage => 'Russian';
@override
String get englishLanguage => 'English';
@override
String get defaultUser => 'Default User';
@override
String get currencySetting => 'Default Currency';
@override
String get currencyDescription => 'Set the default currency for transactions';
@override
String get transactionsHistoryTitle => 'Transactions History';
@override
String get balance => 'Balance';
@override
String get income => 'Income';
@override
String get expense => 'Expense';
@override
String get amount => 'Amount';
@override
String get vendor => 'Vendor';
@override
String get category => 'Category';
@override
String get date => 'Date';
@override
String get requiredField => 'Required field';
@override
String get invalidNumber => 'Invalid number';
@override
String get cancel => 'Cancel';
@override
String get save => 'Save';
}
+118
View File
@@ -0,0 +1,118 @@
// ignore: unused_import
import 'package:intl/intl.dart' as intl;
import 'app_localizations.dart';
// ignore_for_file: type=lint
/// The translations for Russian (`ru`).
class AppLocalizationsRu extends AppLocalizations {
AppLocalizationsRu([String locale = 'ru']) : super(locale);
@override
String get appTitle => 'Бюджетное приложение';
@override
String get homePageTitle => 'Главная';
@override
String get reportsPageTitle => 'Отчеты';
@override
String get settingsPageTitle => 'Настройки';
@override
String get addTransactionButton => 'Добавить новую транзакцию';
@override
String get noTransactionsText => 'Нет транзакций';
@override
String get loadingTransactionsText => 'Загрузка транзакций...';
@override
String transactionErrorText(Object message) {
return 'Ошибка: $message';
}
@override
String get loginPageTitle => 'Вход';
@override
String get nameFieldLabel => 'Имя';
@override
String get emailFieldLabel => 'Email';
@override
String get nameFieldEmptyError => 'Пожалуйста, введите имя';
@override
String get emailFieldEmptyError => 'Пожалуйста, введите email';
@override
String get loginButtonText => 'Войти / Зарегистрироваться';
@override
String get darkModeSetting => 'Темная тема';
@override
String get darkModeDescription => 'Переключить между светлой и темной темой';
@override
String get languageSetting => 'Язык';
@override
String get languageDescription => 'Изменить язык приложения';
@override
String get russianLanguage => 'Русский';
@override
String get englishLanguage => 'Английский';
@override
String get defaultUser => 'Пользователь по умолчанию';
@override
String get currencySetting => 'Валюта по умолчанию';
@override
String get currencyDescription =>
'Установить валюту по умолчанию для транзакций';
@override
String get transactionsHistoryTitle => 'История транзакций';
@override
String get balance => 'Баланс';
@override
String get income => 'Доходы';
@override
String get expense => 'Расходы';
@override
String get amount => 'Сумма';
@override
String get vendor => 'Название';
@override
String get category => 'Категория';
@override
String get date => 'Дата';
@override
String get requiredField => 'Обязательное поле';
@override
String get invalidNumber => 'Неверный формат числа';
@override
String get cancel => 'Отмена';
@override
String get save => 'Сохранить';
}
+2 -2
View File
@@ -9,6 +9,7 @@ import 'package:budget_app/pages/home/home_page.dart';
import 'theme/app_theme.dart';
import 'injection_container.dart' as di;
import 'logic/settings/settings_cubit.dart'; // Импортируем SettingsCubit
import 'logic/transaction/transaction_bloc.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -30,6 +31,7 @@ class _MyAppState extends State<MyApp> {
providers: [
BlocProvider(create: (context) => GetIt.instance<AuthBloc>()..add(AuthStarted())),
BlocProvider(create: (context) => GetIt.instance<SettingsCubit>()),
BlocProvider(create: (context) => GetIt.instance<TransactionBloc>()),
],
child: BlocBuilder<SettingsCubit, SettingsState>(
builder: (context, settingsState) {
@@ -62,5 +64,3 @@ class _MyAppState extends State<MyApp> {
);
}
}