From f68792e6a92e7718a7b6b5908f44decee9ef1aa0 Mon Sep 17 00:00:00 2001 From: Arsen Latipov Date: Thu, 9 Oct 2025 03:01:41 +0300 Subject: [PATCH 1/6] [wave-6] locale partialy implemented --- assets/i18n/en.json | 52 +++++++ assets/i18n/ru.json | 52 +++++++ l10n.yaml | 3 - lib/src/i18n/localizations.dart | 117 +++++++++++++++ lib/src/localization/app_en.arb | 6 - lib/src/localization/app_localizations.dart | 140 ------------------ .../localization/app_localizations_en.dart | 13 -- .../localization/app_localizations_ru.dart | 13 -- lib/src/localization/app_ru.arb | 6 - lib/src/screens/foreground_switch_screen.dart | 2 +- .../copy_code_screen.dart | 11 +- .../enable_microphone_screen.dart | 5 +- .../main_screen/connection_screen.dart | 48 +++--- .../paste_code_screen.dart | 5 +- .../start_connection_screen.dart | 18 ++- .../start_screen.dart | 5 +- lib/src/wave_app.dart | 103 ++++++------- pubspec.lock | 46 +++--- pubspec.yaml | 2 + 19 files changed, 347 insertions(+), 300 deletions(-) create mode 100644 assets/i18n/en.json create mode 100644 assets/i18n/ru.json delete mode 100644 l10n.yaml create mode 100644 lib/src/i18n/localizations.dart delete mode 100644 lib/src/localization/app_en.arb delete mode 100644 lib/src/localization/app_localizations.dart delete mode 100644 lib/src/localization/app_localizations_en.dart delete mode 100644 lib/src/localization/app_localizations_ru.dart delete mode 100644 lib/src/localization/app_ru.arb diff --git a/assets/i18n/en.json b/assets/i18n/en.json new file mode 100644 index 0000000..bc11f17 --- /dev/null +++ b/assets/i18n/en.json @@ -0,0 +1,52 @@ +{ + "appTitle": "Wave", + "@appTitle": { + "description": "The title of the application" + }, + "start_screen": { + "welcome": "Welcome!", + "start": "Start" + }, + "start_connection_screen": { + "create_code": "Create a code", + "initiate": "If you want to initiate a connection", + "create": "Create", + "or": "OR", + "paste_code": "Paste code from friend", + "connect": "If you want to connect to already created peer", + "paste": "Paste" + }, + "enable_microphone_screen": { + "allow": "Allow access, please", + "mic_on": "Mic on" + }, + "copy_code_screen": { + "your_code": "This is your two-word pair cod. Copy and send it to your friend", + "check": "Check pair", + "wait": "Wait your friend to paste the code for button enabling", + "fail": "Failed to create code" + }, + + "paste_code_screen": { + "paste_code": "Copy your friend’s code and paste it to the text input below:", + "connect": "Connect" + }, + + "connection_screen": { + "close": "Close peer", + "warn_termination": "This leads to the termination of your connection", + "help": "This might help: ", + "return_to_prev_step": "Return to the previous step and try to pair once again", + "return": "Return", + "connected": "Connected", + "connecting": "Connecting", + "fail_to_connect": "Failed to connect", + "disconnected": "Disconnected", + "success_connection": "Successful connection!", + "device_to_connect": "Waiting other device to connect..", + "device_to _accept": "Waiting your friend’s device to accept...", + "device_to_answer": "Waiting your friend’s device to answer...", + "failed": "Failed!", + "connection_lost": "Connection lost!" + } +} \ No newline at end of file diff --git a/assets/i18n/ru.json b/assets/i18n/ru.json new file mode 100644 index 0000000..bc11f17 --- /dev/null +++ b/assets/i18n/ru.json @@ -0,0 +1,52 @@ +{ + "appTitle": "Wave", + "@appTitle": { + "description": "The title of the application" + }, + "start_screen": { + "welcome": "Welcome!", + "start": "Start" + }, + "start_connection_screen": { + "create_code": "Create a code", + "initiate": "If you want to initiate a connection", + "create": "Create", + "or": "OR", + "paste_code": "Paste code from friend", + "connect": "If you want to connect to already created peer", + "paste": "Paste" + }, + "enable_microphone_screen": { + "allow": "Allow access, please", + "mic_on": "Mic on" + }, + "copy_code_screen": { + "your_code": "This is your two-word pair cod. Copy and send it to your friend", + "check": "Check pair", + "wait": "Wait your friend to paste the code for button enabling", + "fail": "Failed to create code" + }, + + "paste_code_screen": { + "paste_code": "Copy your friend’s code and paste it to the text input below:", + "connect": "Connect" + }, + + "connection_screen": { + "close": "Close peer", + "warn_termination": "This leads to the termination of your connection", + "help": "This might help: ", + "return_to_prev_step": "Return to the previous step and try to pair once again", + "return": "Return", + "connected": "Connected", + "connecting": "Connecting", + "fail_to_connect": "Failed to connect", + "disconnected": "Disconnected", + "success_connection": "Successful connection!", + "device_to_connect": "Waiting other device to connect..", + "device_to _accept": "Waiting your friend’s device to accept...", + "device_to_answer": "Waiting your friend’s device to answer...", + "failed": "Failed!", + "connection_lost": "Connection lost!" + } +} \ No newline at end of file diff --git a/l10n.yaml b/l10n.yaml deleted file mode 100644 index d480072..0000000 --- a/l10n.yaml +++ /dev/null @@ -1,3 +0,0 @@ -arb-dir: lib/src/localization -template-arb-file: app_en.arb -output-localization-file: app_localizations.dart diff --git a/lib/src/i18n/localizations.dart b/lib/src/i18n/localizations.dart new file mode 100644 index 0000000..3994c89 --- /dev/null +++ b/lib/src/i18n/localizations.dart @@ -0,0 +1,117 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class AppLocalisationDelegate extends LocalizationsDelegate { + const AppLocalisationDelegate(); + + @override + bool isSupported(Locale locale) => AppLocalizations.isSupported(locale); + + @override + bool shouldReload(LocalizationsDelegate old) => false; + + @override + Future load(Locale locale) async { + final loc = AppLocalizations(AppLocalizations.fetchLocale(locale)); + await loc.load(); + return loc; + } +} + +class AppLocalizations { + AppLocalizations(this.locale); + final Locale locale; + + late final Map _keys; + + static const Locale defaultLocale = Locale('en'); + static const supportedLocales = [Locale('ru'), defaultLocale]; + static const supportedLanguageCodes = {'en', 'ru'}; + + static bool isSupported(Locale locale) => + supportedLanguageCodes.contains(locale.languageCode); + + static Locale fetchLocale(Locale locale) => + isSupported(locale) ? Locale(locale.languageCode) : defaultLocale; + + Future load() async { + // 1) База en + final base = await _loadJsonMap('assets/i18n/en.json'); + // 2) Текущий язык (может совпадать с en) + final lang = locale.languageCode; + final overlay = lang == 'en' + ? const {} + : await _tryLoadJsonMap('assets/i18n/$lang.json'); + + // merge и сплющивание в плоские ключи "a.b.c" + final merged = {} + ..addAll(base) + ..addAll(overlay); + _keys = _flatten(merged); + } + + // ---- API ---- + + String t(String key, {Map params = const {}}) { + final raw = _keys[key] ?? key; + if (params.isEmpty) return raw; + return _fillPlaceholders(raw, params); + } + + String translate(String key, [Map? placeholders]) => + t(key, params: placeholders ?? const {}); + + static AppLocalizations of(BuildContext context) => + Localizations.of(context, AppLocalizations)!; + + // ---- helpers ---- + + Future> _loadJsonMap(String path) async { + final raw = await rootBundle.loadString(path); + return (json.decode(raw) as Map); + } + + Future> _tryLoadJsonMap(String path) async { + try { + final raw = await rootBundle.loadString(path); + return (json.decode(raw) as Map); + } catch (_) { + return const {}; + } + } + + Map _flatten(Map map, {String? prefix}) { + final out = {}; + + map.forEach((k, v) { + // пропускаем служебные ключи (на будущее, под ARB-стиль) + if (k.startsWith('@')) return; + + final key = prefix == null ? k : '$prefix.$k'; + if (v is Map) { + out.addAll(_flatten(v.cast(), prefix: key)); + } else if (v is String) { + out[key] = v; + } else if (v != null) { + out[key] = v.toString(); + } + }); + + return out; + } + + String _fillPlaceholders(String text, Map params) { + // поддерживаем как ${name}, так и {name} + return text.replaceAllMapped(RegExp(r'\$\{(\w+)\}|\{(\w+)\}'), (m) { + final key = m.group(1) ?? m.group(2)!; + final val = params[key]; + return val?.toString() ?? m.group(0)!; + }); + } +} + +// syntactic sugar: context.l10n.t('key') +extension L10nX on BuildContext { + AppLocalizations get l10n => AppLocalizations.of(this); +} diff --git a/lib/src/localization/app_en.arb b/lib/src/localization/app_en.arb deleted file mode 100644 index df04ea5..0000000 --- a/lib/src/localization/app_en.arb +++ /dev/null @@ -1,6 +0,0 @@ -{ - "appTitle": "Wave", - "@appTitle": { - "description": "The title of the application" - } -} diff --git a/lib/src/localization/app_localizations.dart b/lib/src/localization/app_localizations.dart deleted file mode 100644 index c3a351e..0000000 --- a/lib/src/localization/app_localizations.dart +++ /dev/null @@ -1,140 +0,0 @@ -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 'localization/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, you’ll need to edit this -/// file. -/// -/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. -/// Then, in the Project Navigator, open the Info.plist file under the Runner -/// project’s 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(context, AppLocalizations); - } - - static const LocalizationsDelegate 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> localizationsDelegates = - >[ - delegate, - GlobalMaterialLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - ]; - - /// A list of this localizations delegate's supported locales. - static const List supportedLocales = [ - Locale('en'), - Locale('ru'), - ]; - - /// The title of the application - /// - /// In en, this message translates to: - /// **'Wave'** - String get appTitle; -} - -class _AppLocalizationsDelegate - extends LocalizationsDelegate { - const _AppLocalizationsDelegate(); - - @override - Future load(Locale locale) { - return SynchronousFuture(lookupAppLocalizations(locale)); - } - - @override - bool isSupported(Locale locale) => - ['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.', - ); -} diff --git a/lib/src/localization/app_localizations_en.dart b/lib/src/localization/app_localizations_en.dart deleted file mode 100644 index 5adbb7a..0000000 --- a/lib/src/localization/app_localizations_en.dart +++ /dev/null @@ -1,13 +0,0 @@ -// 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 => 'Wave'; -} diff --git a/lib/src/localization/app_localizations_ru.dart b/lib/src/localization/app_localizations_ru.dart deleted file mode 100644 index 90e3c1f..0000000 --- a/lib/src/localization/app_localizations_ru.dart +++ /dev/null @@ -1,13 +0,0 @@ -// 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 => 'Вэйв'; -} diff --git a/lib/src/localization/app_ru.arb b/lib/src/localization/app_ru.arb deleted file mode 100644 index 27fe4ba..0000000 --- a/lib/src/localization/app_ru.arb +++ /dev/null @@ -1,6 +0,0 @@ -{ - "appTitle": "Вэйв", - "@appTitle": { - "description": "Название приложения" - } -} diff --git a/lib/src/screens/foreground_switch_screen.dart b/lib/src/screens/foreground_switch_screen.dart index b359d16..9a9483a 100644 --- a/lib/src/screens/foreground_switch_screen.dart +++ b/lib/src/screens/foreground_switch_screen.dart @@ -31,7 +31,7 @@ class ForegroundSwitchScreen extends StatefulWidget { class ForegroundSwitchScreenState extends State { // TODO back to 0 if stable - VisibleScreenType _stepper = VisibleScreenType.startButton; + VisibleScreenType _stepper = VisibleScreenType.main; bool _isPeerInitiator = true; diff --git a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart index 757895d..7424b8e 100644 --- a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart @@ -6,6 +6,7 @@ import 'package:md_ui_kit/md_ui_kit.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:wave_p2p/src/core/keys.dart'; import 'package:wave_p2p/src/core/webrtc_manager.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; class CopyCodeScreen extends StatefulWidget { const CopyCodeScreen({super.key, required this.onCheckPairPressed}); @@ -36,10 +37,10 @@ class _CopyCodeScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, children: [ SizedBox(height: 280), - const Padding( + Padding( padding: EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - 'This is your two-word pair code. Copy and send it to your friend', + context.l10n.t("copy_code_screen.your_code"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -56,12 +57,12 @@ class _CopyCodeScreenState extends State { ), ] else ...[ // TODO change - const Text('Failed to create code'), + Text(context.l10n.t("copy_code_screen.fail")), ], const SizedBox(height: 135), // Check pair: enabled когда пришёл answer WaveSimpleButton( - label: 'Check pair', + label: context.l10n.t("copy_code_screen.check"), onPressed: answerReady ? _onButtonPressed : null, ), const SizedBox(height: 20), @@ -69,7 +70,7 @@ class _CopyCodeScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - 'Wait your friend to paste the code for button enabling', + context.l10n.t("copy_code_screen.wait"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, diff --git a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart index 5396532..ae686e9 100644 --- a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart +++ b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:md_ui_kit/widgets/wave_simple_button.dart'; import 'package:md_ui_kit/widgets/wave_text.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; class EnableMicrophoneScreen extends StatelessWidget { const EnableMicrophoneScreen({ @@ -16,12 +17,12 @@ class EnableMicrophoneScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - 'Allow access, please', + context.l10n.t('enable_microphone_screen.allow'), type: WaveTextType.subtitle, ), SizedBox(height: 20), WaveSimpleButton( - label: 'Mic on', + label: context.l10n.t('enable_microphone_screen.mic_on'), onPressed: onNext, showShadow: true, type: WaveButtonType.alternative, diff --git a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart index 77d49cb..96bf0c8 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart @@ -5,6 +5,7 @@ import 'package:md_ui_kit/md_ui_kit.dart'; import 'package:md_ui_kit/widgets/wave_hint_text.dart' hide WaveTextType, WaveTextWeight; import 'package:wave_p2p/models/call_state.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; import 'package:wave_p2p/src/widgets/animated_status_line.dart'; class ConnectionScreen extends StatelessWidget { @@ -15,7 +16,8 @@ class ConnectionScreen extends StatelessWidget { required this.localId, required this.isPeerInitiator, required this.onReturnPressed, - required this.onClosePeerPressed, required this.state, + required this.onClosePeerPressed, + required this.state, }); final bool isNavBarShowed; @@ -37,8 +39,8 @@ class ConnectionScreen extends StatelessWidget { Padding( padding: const EdgeInsets.all(20.0), child: WaveStatus( - type: _resolveStatusType(state), - label: _resolveStatusText(state), + type: _resolveStatusType(state, context), + label: _resolveStatusText(state, context), ), ), SizedBox(height: 20), @@ -80,7 +82,7 @@ class ConnectionScreen extends StatelessWidget { child: Row( children: [ WaveText( - _resolveSubtitleText(state, isPeerInitiator), + _resolveSubtitleText(state, isPeerInitiator, context), type: WaveTextType.caption, color: _resolveSubtitleColor(state), ), @@ -90,12 +92,12 @@ class ConnectionScreen extends StatelessWidget { if (state == CallState.connected) ...[ SizedBox(height: 305), WaveSimpleButton( - label: 'Close peer', + label: context.l10n.t('connection_screen.close'), onPressed: onClosePeerPressed, ), SizedBox(height: 20), WaveText( - 'This leads to the termination of your connection', + context.l10n.t('connection_screen.warn_termination'), type: WaveTextType.caption, textAlign: TextAlign.center, color: MdColors.disabledColor, @@ -109,14 +111,14 @@ class ConnectionScreen extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: WaveHintText( textAlign: TextAlign.start, - boldPart: 'This might help: ', + boldPart: context.l10n.t('connection_screen.help'), normalPart: - 'Return to the previous step and try to pair once again', + context.l10n.t('connection_screen.return_to_prev_step'), ), ), SizedBox(height: 260), WaveSimpleButton( - label: 'Return', + label: context.l10n.t('connection_screen.return'), onPressed: onReturnPressed, ), SizedBox(height: 260), @@ -127,7 +129,7 @@ class ConnectionScreen extends StatelessWidget { ); } - WaveStatusType _resolveStatusType(CallState callState) { + WaveStatusType _resolveStatusType(CallState callState, BuildContext context) { switch (callState) { case CallState.connected: return WaveStatusType.positive; @@ -140,32 +142,34 @@ class ConnectionScreen extends StatelessWidget { } } - _resolveStatusText(CallState callState) { + _resolveStatusText(CallState callState, BuildContext context) { switch (callState) { case CallState.connected: - return 'Connected'; + return context.l10n.t('connection_screen.connected'); case CallState.connecting: - return 'Connecting'; + return context.l10n.t('connection_screen.connecting'); case CallState.failed: - return 'Failed to connect'; + return context.l10n.t('connection_screen.fail_to_connect'); case CallState.disconnected: - return 'Disconnected'; + return context.l10n.t('connection_screen.disconnected'); } } - String _resolveSubtitleText(CallState callState, bool? isPeerInitiator) { + String _resolveSubtitleText( + CallState callState, bool? isPeerInitiator, BuildContext context) { switch (callState) { case CallState.connected: - return 'Successful connection!'; + return context.l10n.t('connection_screen.success_connection'); case CallState.connecting: - if (isPeerInitiator == null) return 'Waiting other device to connect..'; + if (isPeerInitiator == null) + return context.l10n.t('connection_screen.device_to_connect'); return isPeerInitiator - ? 'Waiting your friend’s device to accept..' - : 'Waiting your friend’s device to answer..'; + ? context.l10n.t('connection_screen.device_to _accept') + : context.l10n.t('connection_screen.device_to_answer'); case CallState.failed: - return 'Failed!'; + return context.l10n.t('connection_screen.failed'); case CallState.disconnected: - return 'Connection lost!'; + return context.l10n.t('connection_screen.connection_lost'); } } diff --git a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart index f9f91af..71e9e7e 100644 --- a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:md_ui_kit/md_ui_kit.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:wave_p2p/src/core/keys.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; class PasteCodeScreen extends StatefulWidget { const PasteCodeScreen({ @@ -26,7 +27,7 @@ class _PasteCodeScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - 'Copy your friend’s code and paste it to the text input below:', + context.l10n.t("paste_code_screen.paste_code"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -41,7 +42,7 @@ class _PasteCodeScreenState extends State { ), SizedBox(height: 135), WaveSimpleButton( - label: 'Connect', + label: context.l10n.t("paste_code_screen.connect"), onPressed: _onAcceptOfferPressed, ), ], diff --git a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart index ee47376..b253ad7 100644 --- a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:md_ui_kit/_core/colors.dart'; import 'package:md_ui_kit/md_ui_kit.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; class StartConnectionScreen extends StatelessWidget { const StartConnectionScreen({ @@ -21,25 +22,28 @@ class StartConnectionScreen extends StatelessWidget { Widget build(BuildContext context) { final orWidget = Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: WaveDivider(type: WaveDividerType.disabled, label: 'OR'), + child: WaveDivider( + type: WaveDividerType.disabled, + label: context.l10n.t('start_connection_screen.or'), + ), ); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - 'Create a code', + context.l10n.t('start_connection_screen.create_code'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - 'If you want to initiate a connection', + context.l10n.t('start_connection_screen.initiate'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: 'Create', + label: context.l10n.t('start_connection_screen.create'), onPressed: onCreateCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( @@ -66,19 +70,19 @@ class StartConnectionScreen extends StatelessWidget { SizedBox(height: 80), WaveText( - 'Paste code from friend', + context.l10n.t('start_connection_screen.paste_code'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - 'If you want to connect to already created peer', + context.l10n.t('start_connection_screen.connect'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: 'Paste', + label: context.l10n.t('start_connection_screen.paste'), onPressed: onPasteCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( diff --git a/lib/src/screens/foreground_switch_screen/start_screen.dart b/lib/src/screens/foreground_switch_screen/start_screen.dart index fda486f..8313fb2 100644 --- a/lib/src/screens/foreground_switch_screen/start_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_screen.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:md_ui_kit/_core/colors.dart'; import 'package:md_ui_kit/md_ui_kit.dart'; import 'package:wave_p2p/src/widgets/quad_painter.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; // где лежит extension class StartScreen extends StatefulWidget { const StartScreen({super.key, required this.onNext}); @@ -189,7 +190,7 @@ class _StartScreenState extends State child: Padding( padding: const EdgeInsets.all(20.0), child: WaveText( - 'Welcome!', + context.l10n.t('start_screen.welcome'), type: WaveTextType.subtitle, weight: WaveTextWeight.bold, color: MdColors.brandColor, @@ -237,7 +238,7 @@ class _StartScreenState extends State child: Padding( padding: EdgeInsets.only(top: screenH / 3 - 68), child: WaveSimpleButton( - label: 'Start', + label: context.l10n.t('start_screen.start'), onPressed: _onStartPressed, type: WaveButtonType.alternative, showShadow: true, diff --git a/lib/src/wave_app.dart b/lib/src/wave_app.dart index 9343ba8..0dd8c75 100644 --- a/lib/src/wave_app.dart +++ b/lib/src/wave_app.dart @@ -1,9 +1,10 @@ import 'package:flutter/material.dart'; +//import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:provider/provider.dart'; import 'package:wave_p2p/src/core/storage.dart'; import 'package:wave_p2p/src/core/webrtc_manager.dart'; -import 'package:wave_p2p/src/localization/app_localizations.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; import 'package:wave_p2p/src/screens/initial_screen_impl.dart'; // import 'sample_feature/sample_item_details_view.dart'; @@ -11,7 +12,6 @@ import 'package:wave_p2p/src/screens/initial_screen_impl.dart'; import 'settings/settings_controller.dart'; import 'settings/settings_view.dart'; - /// The Widget that configures your application. class WaveApp extends StatelessWidget { const WaveApp({ @@ -38,59 +38,60 @@ class WaveApp extends StatelessWidget { listenable: settingsController, builder: (BuildContext context, Widget? child) { return MaterialApp( - debugShowCheckedModeBanner: false, - // Providing a restorationScopeId allows the Navigator built by the - // MaterialApp to restore the navigation stack when a user leaves and - // returns to the app after it has been killed while running in the - // background. - restorationScopeId: 'app', + debugShowCheckedModeBanner: false, + // Providing a restorationScopeId allows the Navigator built by the + // MaterialApp to restore the navigation stack when a user leaves and + // returns to the app after it has been killed while running in the + // background. + restorationScopeId: 'app', - // Provide the generated AppLocalizations to the MaterialApp. This - // allows descendant Widgets to display the correct translations - // depending on the user's locale. - localizationsDelegates: const [ - AppLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: const [ - Locale('ru', ''), // English, no country code - ], + // Provide the generated AppLocalizations to the MaterialApp. This + // allows descendant Widgets to display the correct translations + // depending on the user's locale. + localizationsDelegates: const [ + AppLocalisationDelegate(), + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: const [ + Locale('ru'), + Locale('en'), + ], - // Use AppLocalizations to configure the correct application title - // depending on the user's locale. - // - // The appTitle is defined in .arb files found in the localization - // directory. - onGenerateTitle: (BuildContext context) => - AppLocalizations.of(context)!.appTitle, + // Use AppLocalizations to configure the correct application title + // depending on the user's locale. + // + // The appTitle is defined in .arb files found in the localization + // directory. + // onGenerateTitle: (BuildContext context) => + // AppLocalizations.of(context)!.appTitle, - // Define a light and dark color theme. Then, read the user's - // preferred ThemeMode (light, dark, or system default) from the - // SettingsController to display the correct theme. - theme: ThemeData(), - darkTheme: ThemeData.dark(), - themeMode: settingsController.themeMode, + // Define a light and dark color theme. Then, read the user's + // preferred ThemeMode (light, dark, or system default) from the + // SettingsController to display the correct theme. + theme: ThemeData(), + darkTheme: ThemeData.dark(), + themeMode: settingsController.themeMode, - // Define a function to handle named routes in order to support - // Flutter web url navigation and deep linking. - onGenerateRoute: (RouteSettings routeSettings) { - return MaterialPageRoute( - settings: routeSettings, - builder: (BuildContext context) { - switch (routeSettings.name) { - case SettingsView.routeName: - return SettingsView(controller: settingsController); - // case SampleItemDetailsView.routeName: - // return const SampleItemDetailsView(); - // case SampleItemListView.routeName: - default: - return const InitialScreenImpl(); - } - }, - ); - }, + // Define a function to handle named routes in order to support + // Flutter web url navigation and deep linking. + onGenerateRoute: (RouteSettings routeSettings) { + return MaterialPageRoute( + settings: routeSettings, + builder: (BuildContext context) { + switch (routeSettings.name) { + case SettingsView.routeName: + return SettingsView(controller: settingsController); + // case SampleItemDetailsView.routeName: + // return const SampleItemDetailsView(); + // case SampleItemListView.routeName: + default: + return const InitialScreenImpl(); + } + }, + ); + }, ); }, ), diff --git a/pubspec.lock b/pubspec.lock index faa64c9..7b5618a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -61,10 +61,10 @@ packages: dependency: transitive description: name: build - sha256: "5b887c55a0f734b433b3b2d89f9cd1f99eb636b17e268a5b4259258bc916504b" + sha256: dfb67ccc9a78c642193e0c2d94cb9e48c2c818b3178a86097d644acdcde6a8d9 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.2" build_config: dependency: transitive description: @@ -85,10 +85,10 @@ packages: dependency: "direct main" description: name: build_runner - sha256: "804c47c936df75e1911c19a4fb8c46fa8ff2b3099b9f2b2aa4726af3774f734b" + sha256: "4e54dbeefdc70691ba80b3bce3976af63b5425c8c07dface348dfee664a0edc1" url: "https://pub.dev" source: hosted - version: "2.8.0" + version: "2.9.0" built_collection: dependency: transitive description: @@ -405,14 +405,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" - frontend_server_client: - dependency: transitive - description: - name: frontend_server_client - sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 - url: "https://pub.dev" - source: hosted - version: "4.0.0" glob: dependency: transitive description: @@ -454,7 +446,7 @@ packages: source: hosted version: "4.1.2" intl: - dependency: transitive + dependency: "direct main" description: name: intl sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" @@ -521,10 +513,10 @@ packages: dependency: transitive description: name: logger - sha256: "55d6c23a6c15db14920e037fe7e0dc32e7cdaf3b64b4b25df2d541b5b6b81c0c" + sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" logging: dependency: transitive description: @@ -626,10 +618,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "993381400e94d18469750e5b9dcb8206f15bc09f9da86b9e44a9b0092a0066db" + sha256: "3b4c1fc3aa55ddc9cd4aa6759984330d5c8e66aa7702a6223c61540dc6380c37" url: "https://pub.dev" source: hosted - version: "2.2.18" + version: "2.2.19" path_provider_foundation: dependency: transitive description: @@ -786,26 +778,26 @@ packages: dependency: transitive description: name: record - sha256: "9dbc6ff3e784612f90a9b001373c45ff76b7a08abd2bd9fdf72c242320c8911c" + sha256: "6bad72fb3ea6708d724cf8b6c97c4e236cf9f43a52259b654efeb6fd9b737f1f" url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" record_android: dependency: transitive description: name: record_android - sha256: "854627cd78d8d66190377f98477eee06ca96ab7c9f2e662700daf33dbf7e6673" + sha256: f05677eeed074898327f890f232f9eb49cd99d1c20d0daaf22b5612f4b2301bb url: "https://pub.dev" source: hosted - version: "1.4.2" + version: "1.4.3" record_ios: dependency: transitive description: name: record_ios - sha256: "13e241ed9cbc220534a40ae6b66222e21288db364d96dd66fb762ebd3cb77c71" + sha256: "765b42ac1be019b1674ddd809b811fc721fe5a93f7bb1da7803f0d16772fd6d7" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.4" record_linux: dependency: transitive description: @@ -818,10 +810,10 @@ packages: dependency: transitive description: name: record_macos - sha256: "2849068bb59072f300ad63ed146e543d66afaef8263edba4de4834fc7c8d4d35" + sha256: "842ea4b7e95f4dd237aacffc686d1b0ff4277e3e5357865f8d28cd28bc18ed95" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" record_platform_interface: dependency: transitive description: @@ -1063,10 +1055,10 @@ packages: dependency: transitive description: name: watcher - sha256: "5bf046f41320ac97a469d506261797f35254fa61c641741ef32dacda98b7d39c" + sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.1.4" wave: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 0eaba63..1291ee3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: uuid: ^4.5.1 callkeep: ^0.4.1 wave: ^0.2.2 + intl: ^0.20.2 # redux: ^5.0.0 # flutter_redux: ^0.10.0 @@ -60,6 +61,7 @@ flutter: - assets/icons/mic/ - assets/icons/circle_button/ - assets/icons/participants/ + - assets/i18n/ fonts: - family: Play From 966641439e6943a3ce9d0ea335103d7b8507b970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B8=D1=81=D0=B8=D0=BC=D0=BE=D0=B2=20=D0=90?= =?UTF-8?q?=D1=80=D1=82=D1=91=D0=BC=20=D0=9A=D0=BE=D0=BD=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BD=D1=82=D0=B8=D0=BD=D0=BE=D0=B2=D0=B8=D1=87?= <127617131+AnisimovTema@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:19:52 +0300 Subject: [PATCH 2/6] [wave-6] applocalization provided --- .../enable_microphone_screen.dart | 5 +- .../main_screen/connection_screen.dart | 86 ++++++++++--------- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart index ae686e9..58bc660 100644 --- a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart +++ b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart @@ -13,16 +13,17 @@ class EnableMicrophoneScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - context.l10n.t('enable_microphone_screen.allow'), + locale.translate('enable_microphone_screen.allow'), type: WaveTextType.subtitle, ), SizedBox(height: 20), WaveSimpleButton( - label: context.l10n.t('enable_microphone_screen.mic_on'), + label: locale.translate('enable_microphone_screen.mic_on'), onPressed: onNext, showShadow: true, type: WaveButtonType.alternative, diff --git a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart index 96bf0c8..4ca308a 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart @@ -30,6 +30,39 @@ class ConnectionScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); + + String resolveStatusText(CallState callState) { + switch (callState) { + case CallState.connected: + return locale.translate('connection_screen.connected'); + case CallState.connecting: + return locale.translate('connection_screen.connecting'); + case CallState.failed: + return locale.translate('connection_screen.fail_to_connect'); + case CallState.disconnected: + return locale.translate('connection_screen.disconnected'); + } + } + + String resolveSubtitleText(CallState callState, bool? isPeerInitiator) { + switch (callState) { + case CallState.connected: + return locale.translate('connection_screen.success_connection'); + case CallState.connecting: + if (isPeerInitiator == null) { + return locale.translate('connection_screen.device_to_connect'); + } + return isPeerInitiator + ? locale.translate('connection_screen.device_to _accept') + : locale.translate('connection_screen.device_to_answer'); + case CallState.failed: + return locale.translate('connection_screen.failed'); + case CallState.disconnected: + return locale.translate('connection_screen.connection_lost'); + } + } + return Center( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), @@ -39,8 +72,8 @@ class ConnectionScreen extends StatelessWidget { Padding( padding: const EdgeInsets.all(20.0), child: WaveStatus( - type: _resolveStatusType(state, context), - label: _resolveStatusText(state, context), + type: resolveStatusType(state), + label: resolveStatusText(state), ), ), SizedBox(height: 20), @@ -82,9 +115,9 @@ class ConnectionScreen extends StatelessWidget { child: Row( children: [ WaveText( - _resolveSubtitleText(state, isPeerInitiator, context), + resolveSubtitleText(state, isPeerInitiator), type: WaveTextType.caption, - color: _resolveSubtitleColor(state), + color: resolveSubtitleColor(state), ), ], ), @@ -92,12 +125,12 @@ class ConnectionScreen extends StatelessWidget { if (state == CallState.connected) ...[ SizedBox(height: 305), WaveSimpleButton( - label: context.l10n.t('connection_screen.close'), + label: locale.translate('connection_screen.close'), onPressed: onClosePeerPressed, ), SizedBox(height: 20), WaveText( - context.l10n.t('connection_screen.warn_termination'), + locale.translate('connection_screen.warn_termination'), type: WaveTextType.caption, textAlign: TextAlign.center, color: MdColors.disabledColor, @@ -111,14 +144,14 @@ class ConnectionScreen extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: WaveHintText( textAlign: TextAlign.start, - boldPart: context.l10n.t('connection_screen.help'), + boldPart: locale.translate('connection_screen.help'), normalPart: - context.l10n.t('connection_screen.return_to_prev_step'), + locale.translate('connection_screen.return_to_prev_step'), ), ), SizedBox(height: 260), WaveSimpleButton( - label: context.l10n.t('connection_screen.return'), + label: locale.translate('connection_screen.return'), onPressed: onReturnPressed, ), SizedBox(height: 260), @@ -129,7 +162,7 @@ class ConnectionScreen extends StatelessWidget { ); } - WaveStatusType _resolveStatusType(CallState callState, BuildContext context) { + WaveStatusType resolveStatusType(CallState callState) { switch (callState) { case CallState.connected: return WaveStatusType.positive; @@ -142,38 +175,7 @@ class ConnectionScreen extends StatelessWidget { } } - _resolveStatusText(CallState callState, BuildContext context) { - switch (callState) { - case CallState.connected: - return context.l10n.t('connection_screen.connected'); - case CallState.connecting: - return context.l10n.t('connection_screen.connecting'); - case CallState.failed: - return context.l10n.t('connection_screen.fail_to_connect'); - case CallState.disconnected: - return context.l10n.t('connection_screen.disconnected'); - } - } - - String _resolveSubtitleText( - CallState callState, bool? isPeerInitiator, BuildContext context) { - switch (callState) { - case CallState.connected: - return context.l10n.t('connection_screen.success_connection'); - case CallState.connecting: - if (isPeerInitiator == null) - return context.l10n.t('connection_screen.device_to_connect'); - return isPeerInitiator - ? context.l10n.t('connection_screen.device_to _accept') - : context.l10n.t('connection_screen.device_to_answer'); - case CallState.failed: - return context.l10n.t('connection_screen.failed'); - case CallState.disconnected: - return context.l10n.t('connection_screen.connection_lost'); - } - } - - _resolveSubtitleColor(CallState callState) { + resolveSubtitleColor(CallState callState) { switch (callState) { case CallState.connected: return MdColors.positiveColor; From 702ef57a845efa2865c7cb5485d88e6ffaf77524 Mon Sep 17 00:00:00 2001 From: Arsen Latipov Date: Thu, 9 Oct 2025 22:24:57 +0300 Subject: [PATCH 3/6] [wave-6] locale implemented --- assets/i18n/en.json | 21 ++++++ assets/i18n/ru.json | 21 ++++++ .../copy_code_screen.dart | 9 +-- .../foreground_switch_screen/main_screen.dart | 1 + .../main_screen/call_screen.dart | 68 +++++++++++-------- .../paste_code_screen.dart | 5 +- .../start_connection_screen.dart | 15 ++-- .../start_screen.dart | 5 +- 8 files changed, 103 insertions(+), 42 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index bc11f17..5765129 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -48,5 +48,26 @@ "device_to_answer": "Waiting your friend’s device to answer...", "failed": "Failed!", "connection_lost": "Connection lost!" + }, + + "main_screen": { + "invalid": "Invalid two-word code" + }, + + "call_screen": { + "you": "You", + "peer": "Peer", + "encrypted": "Your call is end-to-end encrypted", + "current_input_device": "Current Input Device", + "current_output_device": "Current Output Device", + "dfl_mic": "Default Microphone", + "dfl_speaker": "Default Speaker", + "settings": "Settings", + "leave": "Leave Call", + "join": "Join Call", + "connected": "Connected", + "call_failed": "Call Failed", + "connecting": "Connecting...", + "ready": "Ready to call" } } \ No newline at end of file diff --git a/assets/i18n/ru.json b/assets/i18n/ru.json index bc11f17..5765129 100644 --- a/assets/i18n/ru.json +++ b/assets/i18n/ru.json @@ -48,5 +48,26 @@ "device_to_answer": "Waiting your friend’s device to answer...", "failed": "Failed!", "connection_lost": "Connection lost!" + }, + + "main_screen": { + "invalid": "Invalid two-word code" + }, + + "call_screen": { + "you": "You", + "peer": "Peer", + "encrypted": "Your call is end-to-end encrypted", + "current_input_device": "Current Input Device", + "current_output_device": "Current Output Device", + "dfl_mic": "Default Microphone", + "dfl_speaker": "Default Speaker", + "settings": "Settings", + "leave": "Leave Call", + "join": "Join Call", + "connected": "Connected", + "call_failed": "Call Failed", + "connecting": "Connecting...", + "ready": "Ready to call" } } \ No newline at end of file diff --git a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart index 7424b8e..d483676 100644 --- a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart @@ -29,6 +29,7 @@ class _CopyCodeScreenState extends State { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); // следим за наличием ответа в менеджере — при изменении UI перестроится автоматически final manager = context.watch(); final answerReady = manager.isAnswerAvailable; @@ -40,7 +41,7 @@ class _CopyCodeScreenState extends State { Padding( padding: EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - context.l10n.t("copy_code_screen.your_code"), + locale.translate("copy_code_screen.your_code"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -57,12 +58,12 @@ class _CopyCodeScreenState extends State { ), ] else ...[ // TODO change - Text(context.l10n.t("copy_code_screen.fail")), + Text(locale.translate("copy_code_screen.fail")), ], const SizedBox(height: 135), // Check pair: enabled когда пришёл answer WaveSimpleButton( - label: context.l10n.t("copy_code_screen.check"), + label: locale.translate("copy_code_screen.check"), onPressed: answerReady ? _onButtonPressed : null, ), const SizedBox(height: 20), @@ -70,7 +71,7 @@ class _CopyCodeScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - context.l10n.t("copy_code_screen.wait"), + locale.translate("copy_code_screen.wait"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, diff --git a/lib/src/screens/foreground_switch_screen/main_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen.dart index 477c69d..f527d49 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen.dart @@ -44,6 +44,7 @@ class _MainScreenState extends State { Future _getLocalOfferId() async { final prefs = await SharedPreferences.getInstance(); // TODO: обработать случай когда нет кода в локальной памяти + // TODO: что-то сделать с локалькой final id = prefs.getString(currentPeerLocalIdKey) ?? 'Invalid two-word code'; setState(() { diff --git a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart index 0261917..aa251c8 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart @@ -9,6 +9,7 @@ import 'package:provider/provider.dart'; import 'package:callkeep/callkeep.dart' show FlutterCallkeep; import 'package:wave_p2p/models/call_state.dart'; import 'package:wave_p2p/src/core/webrtc_manager.dart'; +import 'package:wave_p2p/src/i18n/localizations.dart'; import 'package:wave_p2p/src/widgets/swipe_switcher.dart'; class CallScreen extends StatefulWidget { @@ -31,6 +32,7 @@ class _CallScreenState extends State { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); final manager = widget.disposableManager ?? Provider.of(context); @@ -43,29 +45,50 @@ class _CallScreenState extends State { // Находим локального участника (you) final localParticipant = participants.firstWhere( (p) => p.id == manager.localId, - orElse: () => - ParticipantState(id: '1', inCall: false, muted: true, name: 'You'), + orElse: () => ParticipantState( + id: '1', + inCall: false, + muted: true, + name: locale.translate("call_screen.you"), + ), ); // Находим удаленного участника (peer) - первого из оставшихся final remoteParticipant = participants.firstWhere( (p) => p.id != manager.localId, - orElse: () => - ParticipantState(id: '2', inCall: false, muted: true, name: 'Peer'), + orElse: () => ParticipantState( + id: '2', + inCall: false, + muted: true, + name: locale.translate("call_screen.peer"), + ), ); + String resolveDividerText(CallState state) { + switch (state) { + case CallState.connected: + return locale.translate("call_screen.connected"); + case CallState.failed: + return locale.translate("call_screen.call_failed"); + case CallState.connecting: + return locale.translate("call_screen.connecting"); + default: + return locale.translate("call_screen.ready"); + } + } + return Column( children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 12.0), child: WaveDivider( type: _resolveDividerType(manager.callState), - label: _resolveDividerText(manager.callState), + label: resolveDividerText(manager.callState), ), ), WaveChatBubble( type: WaveChatBubbleType.bubbleMessageInfo, - label: 'Your call is end-to-end encrypted', + label: locale.translate("call_screen.encrypted"), ), SizedBox(height: 40), @@ -84,8 +107,9 @@ class _CallScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 36.0), child: WaveDeviceMenu( items: mics, - subtitle: 'Current Input Device', - labelBuilder: (item) => item.label ?? 'Default Microphone', + subtitle: locale.translate("call_screen.current_input_device"), + labelBuilder: (item) => + item.label ?? locale.translate("call_screen.dfl_mic"), onChanged: (v) => manager.selectMic(v.deviceId), ), ), @@ -94,8 +118,9 @@ class _CallScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 36.0), child: WaveDeviceMenu( items: outs, - subtitle: 'Current Output Device', - labelBuilder: (item) => item.label ?? 'Default Speaker', + subtitle: locale.translate("call_screen.current_output_device"), + labelBuilder: (item) => + item.label ?? locale.translate("call_screen.dfl_speaker"), onChanged: (v) => manager.selectSpeaker(v.deviceId), ), ), @@ -108,7 +133,7 @@ class _CallScreenState extends State { children: [ if (localParticipant != null) WaveParticipant( - label: 'You', + label: locale.translate("call_screen.you"), inCall: localParticipant.inCall, muted: localParticipant.muted, ), @@ -117,7 +142,7 @@ class _CallScreenState extends State { SizedBox(width: 16), if (remoteParticipant != null) WaveParticipant( - label: 'Peer', + label: locale.translate("call_screen.peer"), inCall: remoteParticipant.inCall, muted: remoteParticipant.muted, ), @@ -141,7 +166,7 @@ class _CallScreenState extends State { ), child: WaveCircleButton( type: WaveCircleButtonType.setting, - subtitle: 'Settings', + subtitle: locale.translate("call_screen.settings"), onTap: () => setState(() => isSettingsOpen = !isSettingsOpen), ), ), @@ -183,7 +208,9 @@ class _CallScreenState extends State { type: manager.inCall ? WaveCircleButtonType.leaveCall : WaveCircleButtonType.startCall, - subtitle: manager.inCall ? 'Leave Call' : 'Join Call', + subtitle: manager.inCall + ? locale.translate("call_screen.leave") + : locale.translate("call_screen.join"), onTap: () async { if (manager.inCall) { await manager.leaveCall(); @@ -266,17 +293,4 @@ class _CallScreenState extends State { return WaveDividerType.disabled; } } - - String _resolveDividerText(CallState state) { - switch (state) { - case CallState.connected: - return 'Connected'; - case CallState.failed: - return 'Call Failed'; - case CallState.connecting: - return 'Connecting...'; - default: - return 'Ready to call'; - } - } } diff --git a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart index 71e9e7e..8073f41 100644 --- a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart @@ -21,13 +21,14 @@ class _PasteCodeScreenState extends State { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - context.l10n.t("paste_code_screen.paste_code"), + locale.translate("paste_code_screen.paste_code"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -42,7 +43,7 @@ class _PasteCodeScreenState extends State { ), SizedBox(height: 135), WaveSimpleButton( - label: context.l10n.t("paste_code_screen.connect"), + label: locale.translate("paste_code_screen.connect"), onPressed: _onAcceptOfferPressed, ), ], diff --git a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart index b253ad7..080ea95 100644 --- a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart @@ -20,30 +20,31 @@ class StartConnectionScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); final orWidget = Padding( padding: const EdgeInsets.symmetric(horizontal: 20.0), child: WaveDivider( type: WaveDividerType.disabled, - label: context.l10n.t('start_connection_screen.or'), + label: locale.translate('start_connection_screen.or'), ), ); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - context.l10n.t('start_connection_screen.create_code'), + locale.translate('start_connection_screen.create_code'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - context.l10n.t('start_connection_screen.initiate'), + locale.translate('start_connection_screen.initiate'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: context.l10n.t('start_connection_screen.create'), + label: locale.translate('start_connection_screen.create'), onPressed: onCreateCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( @@ -70,19 +71,19 @@ class StartConnectionScreen extends StatelessWidget { SizedBox(height: 80), WaveText( - context.l10n.t('start_connection_screen.paste_code'), + locale.translate('start_connection_screen.paste_code'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - context.l10n.t('start_connection_screen.connect'), + locale.translate('start_connection_screen.connect'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: context.l10n.t('start_connection_screen.paste'), + label: locale.translate('start_connection_screen.paste'), onPressed: onPasteCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( diff --git a/lib/src/screens/foreground_switch_screen/start_screen.dart b/lib/src/screens/foreground_switch_screen/start_screen.dart index 8313fb2..aa24314 100644 --- a/lib/src/screens/foreground_switch_screen/start_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_screen.dart @@ -121,6 +121,7 @@ class _StartScreenState extends State @override Widget build(BuildContext context) { + final locale = AppLocalizations.of(context); const double topPadding = 40 + 28; return LayoutBuilder( @@ -190,7 +191,7 @@ class _StartScreenState extends State child: Padding( padding: const EdgeInsets.all(20.0), child: WaveText( - context.l10n.t('start_screen.welcome'), + locale.translate('start_screen.welcome'), type: WaveTextType.subtitle, weight: WaveTextWeight.bold, color: MdColors.brandColor, @@ -238,7 +239,7 @@ class _StartScreenState extends State child: Padding( padding: EdgeInsets.only(top: screenH / 3 - 68), child: WaveSimpleButton( - label: context.l10n.t('start_screen.start'), + label: locale.translate('start_screen.start'), onPressed: _onStartPressed, type: WaveButtonType.alternative, showShadow: true, From 0e0e80ea27ab656685ad12796a47347a3f594045 Mon Sep 17 00:00:00 2001 From: Arsen Latipov Date: Fri, 10 Oct 2025 14:57:21 +0300 Subject: [PATCH 4/6] [wave-6] locale better expirience add --- assets/i18n/en.json | 94 +++++++++---------- .../copy_code_screen.dart | 8 +- .../enable_microphone_screen.dart | 4 +- .../main_screen/call_screen.dart | 35 +++---- .../main_screen/connection_screen.dart | 32 +++---- .../paste_code_screen.dart | 4 +- .../start_connection_screen.dart | 14 +-- .../start_screen.dart | 4 +- 8 files changed, 99 insertions(+), 96 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 5765129..28ec772 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -4,70 +4,70 @@ "description": "The title of the application" }, "start_screen": { - "welcome": "Welcome!", - "start": "Start" + "welcome_text": "Welcome!", + "start_button": "Start" }, "start_connection_screen": { - "create_code": "Create a code", - "initiate": "If you want to initiate a connection", - "create": "Create", - "or": "OR", - "paste_code": "Paste code from friend", - "connect": "If you want to connect to already created peer", - "paste": "Paste" + "create_code_text": "Create a code", + "initiate_text": "If you want to initiate a connection", + "create_button": "Create", + "or_text": "OR", + "paste_code_text": "Paste code from friend", + "connect_text": "If you want to connect to already created peer", + "paste_button": "Paste" }, "enable_microphone_screen": { - "allow": "Allow access, please", - "mic_on": "Mic on" + "allow_text": "Allow access, please", + "mic_on_button": "Mic on" }, "copy_code_screen": { - "your_code": "This is your two-word pair cod. Copy and send it to your friend", - "check": "Check pair", - "wait": "Wait your friend to paste the code for button enabling", - "fail": "Failed to create code" + "your_code_text": "This is your two-word pair cod. Copy and send it to your friend", + "check_button": "Check pair", + "wait_text": "Wait your friend to paste the code for button enabling", + "fail_text": "Failed to create code" }, "paste_code_screen": { - "paste_code": "Copy your friend’s code and paste it to the text input below:", - "connect": "Connect" + "paste_code_text": "Copy your friend’s code and paste it to the text input below:", + "connect_button": "Connect" }, "connection_screen": { - "close": "Close peer", - "warn_termination": "This leads to the termination of your connection", - "help": "This might help: ", - "return_to_prev_step": "Return to the previous step and try to pair once again", - "return": "Return", - "connected": "Connected", - "connecting": "Connecting", - "fail_to_connect": "Failed to connect", - "disconnected": "Disconnected", - "success_connection": "Successful connection!", - "device_to_connect": "Waiting other device to connect..", - "device_to _accept": "Waiting your friend’s device to accept...", - "device_to_answer": "Waiting your friend’s device to answer...", - "failed": "Failed!", - "connection_lost": "Connection lost!" + "close_peer_button": "Close peer", + "warn_termination_text": "This leads to the termination of your connection", + "help_text": "This might help: ", + "return_to_prev_step_text": "Return to the previous step and try to pair once again", + "return_button": "Return", + "connected_text": "Connected", + "connecting_text": "Connecting", + "fail_to_connect_text": "Failed to connect", + "disconnected_text": "Disconnected", + "success_connection_text": "Successful connection!", + "device_to_connect_text": "Waiting other device to connect..", + "device_to_accept_text": "Waiting your friend’s device to accept...", + "device_to_answer_text": "Waiting your friend’s device to answer...", + "failed_text": "Failed!", + "connection_lost_text": "Connection lost!" }, "main_screen": { - "invalid": "Invalid two-word code" + "invalid_text": "Invalid two-word code" }, "call_screen": { - "you": "You", - "peer": "Peer", - "encrypted": "Your call is end-to-end encrypted", - "current_input_device": "Current Input Device", - "current_output_device": "Current Output Device", - "dfl_mic": "Default Microphone", - "dfl_speaker": "Default Speaker", - "settings": "Settings", - "leave": "Leave Call", - "join": "Join Call", - "connected": "Connected", - "call_failed": "Call Failed", - "connecting": "Connecting...", - "ready": "Ready to call" + "you_text": "You", + "peer_text": "Peer", + "encrypted_text": "Your call is end-to-end encrypted", + "current_input_device_text": "Current Input Device", + "current_output_device_text": "Current Output Device", + "dfl_mic_text": "Default Microphone", + "dfl_speaker_text": "Default Speaker", + "settings_text": "Settings", + "leave_text": "Leave Call", + "join_text": "Join Call", + "connected_text": "Connected", + "call_failed_text": "Call Failed", + "connecting_text": "Connecting...", + "ready_text": "Ready to call" } } \ No newline at end of file diff --git a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart index d483676..19de594 100644 --- a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart @@ -41,7 +41,7 @@ class _CopyCodeScreenState extends State { Padding( padding: EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - locale.translate("copy_code_screen.your_code"), + locale.translate("copy_code_screen.your_code_text"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -58,12 +58,12 @@ class _CopyCodeScreenState extends State { ), ] else ...[ // TODO change - Text(locale.translate("copy_code_screen.fail")), + Text(locale.translate("copy_code_screen.fail_text")), ], const SizedBox(height: 135), // Check pair: enabled когда пришёл answer WaveSimpleButton( - label: locale.translate("copy_code_screen.check"), + label: locale.translate("copy_code_screen.check_button"), onPressed: answerReady ? _onButtonPressed : null, ), const SizedBox(height: 20), @@ -71,7 +71,7 @@ class _CopyCodeScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - locale.translate("copy_code_screen.wait"), + locale.translate("copy_code_screen.wait_text"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, diff --git a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart index 58bc660..1bded40 100644 --- a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart +++ b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart @@ -18,12 +18,12 @@ class EnableMicrophoneScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - locale.translate('enable_microphone_screen.allow'), + locale.translate('enable_microphone_screen.allow_text'), type: WaveTextType.subtitle, ), SizedBox(height: 20), WaveSimpleButton( - label: locale.translate('enable_microphone_screen.mic_on'), + label: locale.translate('enable_microphone_screen.mic_on_button'), onPressed: onNext, showShadow: true, type: WaveButtonType.alternative, diff --git a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart index aa251c8..c4abac0 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart @@ -49,7 +49,7 @@ class _CallScreenState extends State { id: '1', inCall: false, muted: true, - name: locale.translate("call_screen.you"), + name: locale.translate("call_screen.you_text"), ), ); @@ -60,20 +60,20 @@ class _CallScreenState extends State { id: '2', inCall: false, muted: true, - name: locale.translate("call_screen.peer"), + name: locale.translate("call_screen.peer_text"), ), ); String resolveDividerText(CallState state) { switch (state) { case CallState.connected: - return locale.translate("call_screen.connected"); + return locale.translate("call_screen.connected_text"); case CallState.failed: - return locale.translate("call_screen.call_failed"); + return locale.translate("call_screen.call_failed_text"); case CallState.connecting: - return locale.translate("call_screen.connecting"); + return locale.translate("call_screen.connecting_text"); default: - return locale.translate("call_screen.ready"); + return locale.translate("call_screen.ready_text"); } } @@ -88,7 +88,7 @@ class _CallScreenState extends State { ), WaveChatBubble( type: WaveChatBubbleType.bubbleMessageInfo, - label: locale.translate("call_screen.encrypted"), + label: locale.translate("call_screen.encrypted_text"), ), SizedBox(height: 40), @@ -107,9 +107,10 @@ class _CallScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 36.0), child: WaveDeviceMenu( items: mics, - subtitle: locale.translate("call_screen.current_input_device"), + subtitle: + locale.translate("call_screen.current_input_device_text"), labelBuilder: (item) => - item.label ?? locale.translate("call_screen.dfl_mic"), + item.label ?? locale.translate("call_screen.dfl_mic_text"), onChanged: (v) => manager.selectMic(v.deviceId), ), ), @@ -118,9 +119,11 @@ class _CallScreenState extends State { padding: const EdgeInsets.symmetric(horizontal: 36.0), child: WaveDeviceMenu( items: outs, - subtitle: locale.translate("call_screen.current_output_device"), + subtitle: + locale.translate("call_screen.current_output_device_text"), labelBuilder: (item) => - item.label ?? locale.translate("call_screen.dfl_speaker"), + item.label ?? + locale.translate("call_screen.dfl_speaker_text"), onChanged: (v) => manager.selectSpeaker(v.deviceId), ), ), @@ -133,7 +136,7 @@ class _CallScreenState extends State { children: [ if (localParticipant != null) WaveParticipant( - label: locale.translate("call_screen.you"), + label: locale.translate("call_screen.you_text"), inCall: localParticipant.inCall, muted: localParticipant.muted, ), @@ -142,7 +145,7 @@ class _CallScreenState extends State { SizedBox(width: 16), if (remoteParticipant != null) WaveParticipant( - label: locale.translate("call_screen.peer"), + label: locale.translate("call_screen.peer_text"), inCall: remoteParticipant.inCall, muted: remoteParticipant.muted, ), @@ -166,7 +169,7 @@ class _CallScreenState extends State { ), child: WaveCircleButton( type: WaveCircleButtonType.setting, - subtitle: locale.translate("call_screen.settings"), + subtitle: locale.translate("call_screen.settings_text"), onTap: () => setState(() => isSettingsOpen = !isSettingsOpen), ), ), @@ -209,8 +212,8 @@ class _CallScreenState extends State { ? WaveCircleButtonType.leaveCall : WaveCircleButtonType.startCall, subtitle: manager.inCall - ? locale.translate("call_screen.leave") - : locale.translate("call_screen.join"), + ? locale.translate("call_screen.leave_text") + : locale.translate("call_screen.join_text"), onTap: () async { if (manager.inCall) { await manager.leaveCall(); diff --git a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart index 4ca308a..bbbf504 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart @@ -35,31 +35,31 @@ class ConnectionScreen extends StatelessWidget { String resolveStatusText(CallState callState) { switch (callState) { case CallState.connected: - return locale.translate('connection_screen.connected'); + return locale.translate('connection_screen.connected_text'); case CallState.connecting: - return locale.translate('connection_screen.connecting'); + return locale.translate('connection_screen.connecting_text'); case CallState.failed: - return locale.translate('connection_screen.fail_to_connect'); + return locale.translate('connection_screen.fail_to_connect_text'); case CallState.disconnected: - return locale.translate('connection_screen.disconnected'); + return locale.translate('connection_screen.disconnected_text'); } } String resolveSubtitleText(CallState callState, bool? isPeerInitiator) { switch (callState) { case CallState.connected: - return locale.translate('connection_screen.success_connection'); + return locale.translate('connection_screen.success_connection_text'); case CallState.connecting: if (isPeerInitiator == null) { - return locale.translate('connection_screen.device_to_connect'); + return locale.translate('connection_screen.device_to_connect_text'); } return isPeerInitiator - ? locale.translate('connection_screen.device_to _accept') - : locale.translate('connection_screen.device_to_answer'); + ? locale.translate('connection_screen.device_to_accept_text') + : locale.translate('connection_screen.device_to_answer_text'); case CallState.failed: - return locale.translate('connection_screen.failed'); + return locale.translate('connection_screen.failed_text'); case CallState.disconnected: - return locale.translate('connection_screen.connection_lost'); + return locale.translate('connection_screen.connection_lost_text'); } } @@ -125,12 +125,12 @@ class ConnectionScreen extends StatelessWidget { if (state == CallState.connected) ...[ SizedBox(height: 305), WaveSimpleButton( - label: locale.translate('connection_screen.close'), + label: locale.translate('connection_screen.close_peer_button'), onPressed: onClosePeerPressed, ), SizedBox(height: 20), WaveText( - locale.translate('connection_screen.warn_termination'), + locale.translate('connection_screen.warn_termination_text'), type: WaveTextType.caption, textAlign: TextAlign.center, color: MdColors.disabledColor, @@ -144,14 +144,14 @@ class ConnectionScreen extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 16.0), child: WaveHintText( textAlign: TextAlign.start, - boldPart: locale.translate('connection_screen.help'), - normalPart: - locale.translate('connection_screen.return_to_prev_step'), + boldPart: locale.translate('connection_screen.help_text'), + normalPart: locale + .translate('connection_screen.return_to_prev_step_text'), ), ), SizedBox(height: 260), WaveSimpleButton( - label: locale.translate('connection_screen.return'), + label: locale.translate('connection_screen.return_button'), onPressed: onReturnPressed, ), SizedBox(height: 260), diff --git a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart index 8073f41..23505c0 100644 --- a/lib/src/screens/foreground_switch_screen/paste_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/paste_code_screen.dart @@ -28,7 +28,7 @@ class _PasteCodeScreenState extends State { Padding( padding: const EdgeInsets.symmetric(horizontal: 57.0), child: WaveText( - locale.translate("paste_code_screen.paste_code"), + locale.translate("paste_code_screen.paste_code_text"), type: WaveTextType.caption, maxLines: 3, textAlign: TextAlign.center, @@ -43,7 +43,7 @@ class _PasteCodeScreenState extends State { ), SizedBox(height: 135), WaveSimpleButton( - label: locale.translate("paste_code_screen.connect"), + label: locale.translate("paste_code_screen.connect_button"), onPressed: _onAcceptOfferPressed, ), ], diff --git a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart index 080ea95..d98e39c 100644 --- a/lib/src/screens/foreground_switch_screen/start_connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_connection_screen.dart @@ -25,26 +25,26 @@ class StartConnectionScreen extends StatelessWidget { padding: const EdgeInsets.symmetric(horizontal: 20.0), child: WaveDivider( type: WaveDividerType.disabled, - label: locale.translate('start_connection_screen.or'), + label: locale.translate('start_connection_screen.or_text'), ), ); return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - locale.translate('start_connection_screen.create_code'), + locale.translate('start_connection_screen.create_code_text'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - locale.translate('start_connection_screen.initiate'), + locale.translate('start_connection_screen.initiate_text'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: locale.translate('start_connection_screen.create'), + label: locale.translate('start_connection_screen.create_button'), onPressed: onCreateCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( @@ -71,19 +71,19 @@ class StartConnectionScreen extends StatelessWidget { SizedBox(height: 80), WaveText( - locale.translate('start_connection_screen.paste_code'), + locale.translate('start_connection_screen.paste_code_text'), type: WaveTextType.title, weight: WaveTextWeight.bold, ), SizedBox(height: 10), WaveText( - locale.translate('start_connection_screen.connect'), + locale.translate('start_connection_screen.connect_text'), type: WaveTextType.caption, color: MdColors.disabledColor, ), SizedBox(height: 24), WaveSimpleButton( - label: locale.translate('start_connection_screen.paste'), + label: locale.translate('start_connection_screen.paste_button'), onPressed: onPasteCode, type: WaveButtonType.main, padding: EdgeInsets.symmetric( diff --git a/lib/src/screens/foreground_switch_screen/start_screen.dart b/lib/src/screens/foreground_switch_screen/start_screen.dart index aa24314..f1938b6 100644 --- a/lib/src/screens/foreground_switch_screen/start_screen.dart +++ b/lib/src/screens/foreground_switch_screen/start_screen.dart @@ -191,7 +191,7 @@ class _StartScreenState extends State child: Padding( padding: const EdgeInsets.all(20.0), child: WaveText( - locale.translate('start_screen.welcome'), + locale.translate('start_screen.welcome_text'), type: WaveTextType.subtitle, weight: WaveTextWeight.bold, color: MdColors.brandColor, @@ -239,7 +239,7 @@ class _StartScreenState extends State child: Padding( padding: EdgeInsets.only(top: screenH / 3 - 68), child: WaveSimpleButton( - label: locale.translate('start_screen.start'), + label: locale.translate('start_screen.start_button'), onPressed: _onStartPressed, type: WaveButtonType.alternative, showShadow: true, From 4cfa0fa9c600865b2b1c2b2050054d883b3c75ed Mon Sep 17 00:00:00 2001 From: Arsen Latipov Date: Fri, 10 Oct 2025 14:59:13 +0300 Subject: [PATCH 5/6] [wave-6] locale better expirience add --- assets/i18n/en.json | 4 ++-- .../screens/foreground_switch_screen/copy_code_screen.dart | 2 +- .../foreground_switch_screen/enable_microphone_screen.dart | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 28ec772..2e45cb9 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -17,14 +17,14 @@ "paste_button": "Paste" }, "enable_microphone_screen": { - "allow_text": "Allow access, please", + "allow_access_text": "Allow access, please", "mic_on_button": "Mic on" }, "copy_code_screen": { "your_code_text": "This is your two-word pair cod. Copy and send it to your friend", "check_button": "Check pair", "wait_text": "Wait your friend to paste the code for button enabling", - "fail_text": "Failed to create code" + "fail_create_code_text": "Failed to create code" }, "paste_code_screen": { diff --git a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart index 19de594..38c6dc4 100644 --- a/lib/src/screens/foreground_switch_screen/copy_code_screen.dart +++ b/lib/src/screens/foreground_switch_screen/copy_code_screen.dart @@ -58,7 +58,7 @@ class _CopyCodeScreenState extends State { ), ] else ...[ // TODO change - Text(locale.translate("copy_code_screen.fail_text")), + Text(locale.translate("copy_code_screen.fail_create_code_text")), ], const SizedBox(height: 135), // Check pair: enabled когда пришёл answer diff --git a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart index 1bded40..847075d 100644 --- a/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart +++ b/lib/src/screens/foreground_switch_screen/enable_microphone_screen.dart @@ -18,7 +18,7 @@ class EnableMicrophoneScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ WaveText( - locale.translate('enable_microphone_screen.allow_text'), + locale.translate('enable_microphone_screen.allow_access_text'), type: WaveTextType.subtitle, ), SizedBox(height: 20), From 1b00e24c4edc5c8db8ffc2f0d49b3286c0a4c28d Mon Sep 17 00:00:00 2001 From: Arsen Latipov Date: Wed, 22 Oct 2025 22:37:51 +0300 Subject: [PATCH 6/6] [wave-6] locale update according to comments --- assets/i18n/en.json | 10 +- assets/i18n/ru.json | 94 +++++++++---------- lib/src/screens/foreground_switch_screen.dart | 2 +- .../main_screen/call_screen.dart | 9 +- .../main_screen/connection_screen.dart | 3 +- 5 files changed, 60 insertions(+), 58 deletions(-) diff --git a/assets/i18n/en.json b/assets/i18n/en.json index 2e45cb9..2a6aaa8 100644 --- a/assets/i18n/en.json +++ b/assets/i18n/en.json @@ -42,7 +42,7 @@ "connecting_text": "Connecting", "fail_to_connect_text": "Failed to connect", "disconnected_text": "Disconnected", - "success_connection_text": "Successful connection!", + "successful_connection_text": "Successful connection!", "device_to_connect_text": "Waiting other device to connect..", "device_to_accept_text": "Waiting your friend’s device to accept...", "device_to_answer_text": "Waiting your friend’s device to answer...", @@ -60,11 +60,11 @@ "encrypted_text": "Your call is end-to-end encrypted", "current_input_device_text": "Current Input Device", "current_output_device_text": "Current Output Device", - "dfl_mic_text": "Default Microphone", - "dfl_speaker_text": "Default Speaker", + "default_microphone_text": "Default Microphone", + "default_speaker_text": "Default Speaker", "settings_text": "Settings", - "leave_text": "Leave Call", - "join_text": "Join Call", + "leave_call_text": "Leave Call", + "join_call_text": "Join Call", "connected_text": "Connected", "call_failed_text": "Call Failed", "connecting_text": "Connecting...", diff --git a/assets/i18n/ru.json b/assets/i18n/ru.json index 5765129..2a6aaa8 100644 --- a/assets/i18n/ru.json +++ b/assets/i18n/ru.json @@ -4,70 +4,70 @@ "description": "The title of the application" }, "start_screen": { - "welcome": "Welcome!", - "start": "Start" + "welcome_text": "Welcome!", + "start_button": "Start" }, "start_connection_screen": { - "create_code": "Create a code", - "initiate": "If you want to initiate a connection", - "create": "Create", - "or": "OR", - "paste_code": "Paste code from friend", - "connect": "If you want to connect to already created peer", - "paste": "Paste" + "create_code_text": "Create a code", + "initiate_text": "If you want to initiate a connection", + "create_button": "Create", + "or_text": "OR", + "paste_code_text": "Paste code from friend", + "connect_text": "If you want to connect to already created peer", + "paste_button": "Paste" }, "enable_microphone_screen": { - "allow": "Allow access, please", - "mic_on": "Mic on" + "allow_access_text": "Allow access, please", + "mic_on_button": "Mic on" }, "copy_code_screen": { - "your_code": "This is your two-word pair cod. Copy and send it to your friend", - "check": "Check pair", - "wait": "Wait your friend to paste the code for button enabling", - "fail": "Failed to create code" + "your_code_text": "This is your two-word pair cod. Copy and send it to your friend", + "check_button": "Check pair", + "wait_text": "Wait your friend to paste the code for button enabling", + "fail_create_code_text": "Failed to create code" }, "paste_code_screen": { - "paste_code": "Copy your friend’s code and paste it to the text input below:", - "connect": "Connect" + "paste_code_text": "Copy your friend’s code and paste it to the text input below:", + "connect_button": "Connect" }, "connection_screen": { - "close": "Close peer", - "warn_termination": "This leads to the termination of your connection", - "help": "This might help: ", - "return_to_prev_step": "Return to the previous step and try to pair once again", - "return": "Return", - "connected": "Connected", - "connecting": "Connecting", - "fail_to_connect": "Failed to connect", - "disconnected": "Disconnected", - "success_connection": "Successful connection!", - "device_to_connect": "Waiting other device to connect..", - "device_to _accept": "Waiting your friend’s device to accept...", - "device_to_answer": "Waiting your friend’s device to answer...", - "failed": "Failed!", - "connection_lost": "Connection lost!" + "close_peer_button": "Close peer", + "warn_termination_text": "This leads to the termination of your connection", + "help_text": "This might help: ", + "return_to_prev_step_text": "Return to the previous step and try to pair once again", + "return_button": "Return", + "connected_text": "Connected", + "connecting_text": "Connecting", + "fail_to_connect_text": "Failed to connect", + "disconnected_text": "Disconnected", + "successful_connection_text": "Successful connection!", + "device_to_connect_text": "Waiting other device to connect..", + "device_to_accept_text": "Waiting your friend’s device to accept...", + "device_to_answer_text": "Waiting your friend’s device to answer...", + "failed_text": "Failed!", + "connection_lost_text": "Connection lost!" }, "main_screen": { - "invalid": "Invalid two-word code" + "invalid_text": "Invalid two-word code" }, "call_screen": { - "you": "You", - "peer": "Peer", - "encrypted": "Your call is end-to-end encrypted", - "current_input_device": "Current Input Device", - "current_output_device": "Current Output Device", - "dfl_mic": "Default Microphone", - "dfl_speaker": "Default Speaker", - "settings": "Settings", - "leave": "Leave Call", - "join": "Join Call", - "connected": "Connected", - "call_failed": "Call Failed", - "connecting": "Connecting...", - "ready": "Ready to call" + "you_text": "You", + "peer_text": "Peer", + "encrypted_text": "Your call is end-to-end encrypted", + "current_input_device_text": "Current Input Device", + "current_output_device_text": "Current Output Device", + "default_microphone_text": "Default Microphone", + "default_speaker_text": "Default Speaker", + "settings_text": "Settings", + "leave_call_text": "Leave Call", + "join_call_text": "Join Call", + "connected_text": "Connected", + "call_failed_text": "Call Failed", + "connecting_text": "Connecting...", + "ready_text": "Ready to call" } } \ No newline at end of file diff --git a/lib/src/screens/foreground_switch_screen.dart b/lib/src/screens/foreground_switch_screen.dart index 9a9483a..b359d16 100644 --- a/lib/src/screens/foreground_switch_screen.dart +++ b/lib/src/screens/foreground_switch_screen.dart @@ -31,7 +31,7 @@ class ForegroundSwitchScreen extends StatefulWidget { class ForegroundSwitchScreenState extends State { // TODO back to 0 if stable - VisibleScreenType _stepper = VisibleScreenType.main; + VisibleScreenType _stepper = VisibleScreenType.startButton; bool _isPeerInitiator = true; diff --git a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart index c4abac0..70d8959 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/call_screen.dart @@ -110,7 +110,8 @@ class _CallScreenState extends State { subtitle: locale.translate("call_screen.current_input_device_text"), labelBuilder: (item) => - item.label ?? locale.translate("call_screen.dfl_mic_text"), + item.label ?? + locale.translate("call_screen.default_microphone_text"), onChanged: (v) => manager.selectMic(v.deviceId), ), ), @@ -123,7 +124,7 @@ class _CallScreenState extends State { locale.translate("call_screen.current_output_device_text"), labelBuilder: (item) => item.label ?? - locale.translate("call_screen.dfl_speaker_text"), + locale.translate("call_screen.default_speaker_text"), onChanged: (v) => manager.selectSpeaker(v.deviceId), ), ), @@ -212,8 +213,8 @@ class _CallScreenState extends State { ? WaveCircleButtonType.leaveCall : WaveCircleButtonType.startCall, subtitle: manager.inCall - ? locale.translate("call_screen.leave_text") - : locale.translate("call_screen.join_text"), + ? locale.translate("call_screen.leave_call_text") + : locale.translate("call_screen.join_call_text"), onTap: () async { if (manager.inCall) { await manager.leaveCall(); diff --git a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart index bbbf504..3260a8b 100644 --- a/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart +++ b/lib/src/screens/foreground_switch_screen/main_screen/connection_screen.dart @@ -48,7 +48,8 @@ class ConnectionScreen extends StatelessWidget { String resolveSubtitleText(CallState callState, bool? isPeerInitiator) { switch (callState) { case CallState.connected: - return locale.translate('connection_screen.success_connection_text'); + return locale + .translate('connection_screen.successful_connection_text'); case CallState.connecting: if (isPeerInitiator == null) { return locale.translate('connection_screen.device_to_connect_text');