feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.
Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 10:26:49 +01:00
|
|
|
|
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_de.dart';
|
|
|
|
|
|
import 'app_localizations_en.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, 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<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('de'),
|
|
|
|
|
|
Locale('en'),
|
|
|
|
|
|
Locale('en', 'GB'),
|
|
|
|
|
|
Locale('en', 'US'),
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
/// The app's name: the window's title, and where halkyon_app's texts name the app.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Halkyon Train'**
|
|
|
|
|
|
String get appTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// The app's word in its wordmark, under "Halkyon".
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Train'**
|
|
|
|
|
|
String get launchProduct;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @instanceFirstStartSubtitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Choose the instance to keep your workouts on. Someone runs each one; you can add others later.'**
|
|
|
|
|
|
String get instanceFirstStartSubtitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @homeEmptyTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Nothing here yet'**
|
|
|
|
|
|
String get homeEmptyTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @homeEmptyHint.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Workouts come with a later version of Halkyon Train.'**
|
|
|
|
|
|
String get homeEmptyHint;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @accountTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Account'**
|
|
|
|
|
|
String get accountTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @accountDeleteMessage.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Your account is deleted on the server and on all your devices. This can\'t be undone.'**
|
|
|
|
|
|
String get accountDeleteMessage;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @aboutTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'About'**
|
|
|
|
|
|
String get aboutTitle;
|
feat(train): recording a workout on Android (ADR 0030, D13, D16, D19, D21)
RecorderService, a foreground service of the types location and health
started from the open app, takes fixes from LocationManager's GPS and
steps from the step detector, pauses by itself (AutoPause, tested on the
JVM) and appends each sample to the person's recording file, flushed
every five seconds. MainActivity asks for location, notifications and,
for auto-pause on foot, physical activity, never background location
(D19), and bridges the service to the app.
The app follows the file's lines with RecordingBloc and shows the moving
time, the distance, the pace or speed and GPS's state; the notification
shows the time and the distance with Pause or Resume. Stop is held down;
a stopped recording is saved as a workout and its series, or discarded
after asking, and one cut off or left unsaved is offered as the app
opens. Home has the Record button where the device records.
Three choices of the implementation's are recorded under D21 for review:
rowing waits for 5f, auto-pause on foot without steps goes by GPS speed
(below 2 km/h, on above 3 km/h), and Stop's hint shows above the button.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 13:24:56 +01:00
|
|
|
|
|
|
|
|
|
|
/// No description provided for @homeRecordHint.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Record a workout with the button below. The list of your workouts comes with the next version of Halkyon Train.'**
|
|
|
|
|
|
String get homeRecordHint;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordAction.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Record'**
|
|
|
|
|
|
String get recordAction;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordBack.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Back to the recording'**
|
|
|
|
|
|
String get recordBack;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordSheetTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Record a workout'**
|
|
|
|
|
|
String get recordSheetTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @activityRunning.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Running'**
|
|
|
|
|
|
String get activityRunning;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @activityWalking.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Walking'**
|
|
|
|
|
|
String get activityWalking;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @activityHiking.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Hiking'**
|
|
|
|
|
|
String get activityHiking;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @activityCycling.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Cycling'**
|
|
|
|
|
|
String get activityCycling;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @activityIndoorRowing.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Rowing indoors'**
|
|
|
|
|
|
String get activityIndoorRowing;
|
|
|
|
|
|
|
|
|
|
|
|
/// The switch for auto-pause, as the recording starts.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Pause by itself'**
|
|
|
|
|
|
String get recordAutoPause;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordAutoPauseHint.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'When you stand still, and going on as you move again'**
|
|
|
|
|
|
String get recordAutoPauseHint;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordStart.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Start'**
|
|
|
|
|
|
String get recordStart;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordLocationRefused.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Train needs your location to record this. You can allow it in the system\'s settings.'**
|
|
|
|
|
|
String get recordLocationRefused;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingWaitingForGps.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Waiting for GPS'**
|
|
|
|
|
|
String get recordingWaitingForGps;
|
|
|
|
|
|
|
|
|
|
|
|
/// Before a fix precise enough: how far off the last one may be.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Waiting for GPS · ±{metres} m'**
|
|
|
|
|
|
String recordingWaitingForGpsAccuracy(int metres);
|
|
|
|
|
|
|
|
|
|
|
|
/// How far off the last fix may be.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'GPS ±{metres} m'**
|
|
|
|
|
|
String recordingGpsAccuracy(int metres);
|
|
|
|
|
|
|
|
|
|
|
|
/// Under the time, lower case: the time moved, pauses left out.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'moving time'**
|
|
|
|
|
|
String get recordingMovingTime;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingDistance.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'distance'**
|
|
|
|
|
|
String get recordingDistance;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingPace.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'pace'**
|
|
|
|
|
|
String get recordingPace;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingSpeed.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'speed'**
|
|
|
|
|
|
String get recordingSpeed;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingDistanceValue.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'{km} km'**
|
|
|
|
|
|
String recordingDistanceValue(String km);
|
|
|
|
|
|
|
|
|
|
|
|
/// Minutes and seconds a kilometre takes.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'{pace} /km'**
|
|
|
|
|
|
String recordingPaceValue(String pace);
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingSpeedValue.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'{kmh} km/h'**
|
|
|
|
|
|
String recordingSpeedValue(String kmh);
|
|
|
|
|
|
|
|
|
|
|
|
/// Train paused the recording by itself (auto-pause).
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Paused: not moving'**
|
|
|
|
|
|
String get recordingPausedAuto;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingPausedByHand.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Paused'**
|
|
|
|
|
|
String get recordingPausedByHand;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingPause.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Pause'**
|
|
|
|
|
|
String get recordingPause;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingResume.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Resume'**
|
|
|
|
|
|
String get recordingResume;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingStop.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Stop'**
|
|
|
|
|
|
String get recordingStop;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingHoldToStop.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Hold Stop to end the workout'**
|
|
|
|
|
|
String get recordingHoldToStop;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingStoppedTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Save this workout?'**
|
|
|
|
|
|
String get recordingStoppedTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingSave.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Save'**
|
|
|
|
|
|
String get recordingSave;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingDiscard.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Discard'**
|
|
|
|
|
|
String get recordingDiscard;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingDiscardTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Discard this workout?'**
|
|
|
|
|
|
String get recordingDiscardTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingDiscardMessage.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Its time and track are deleted from this device. This can\'t be undone.'**
|
|
|
|
|
|
String get recordingDiscardMessage;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingSaveFailed.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'It can\'t be saved on this device, which doesn\'t hold your account\'s keys. It stays here until it can be.'**
|
|
|
|
|
|
String get recordingSaveFailed;
|
|
|
|
|
|
|
|
|
|
|
|
/// No description provided for @recordingCutOffTitle.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'A recording was cut off'**
|
|
|
|
|
|
String get recordingCutOffTitle;
|
|
|
|
|
|
|
|
|
|
|
|
/// A recording found unfinished as the app opened: when it started and its last sample.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'A recording from {start} was cut off. Save it up to {end}, or discard it?'**
|
|
|
|
|
|
String recordingCutOffMessage(String start, String end);
|
|
|
|
|
|
|
|
|
|
|
|
/// The name of the recording's notification channel, in the system's settings.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'Recording'**
|
|
|
|
|
|
String get recordingNotificationChannel;
|
|
|
|
|
|
|
|
|
|
|
|
/// The notification's title while paused.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// In en, this message translates to:
|
|
|
|
|
|
/// **'{activity} · paused'**
|
|
|
|
|
|
String recordingNotificationPaused(String activity);
|
feat(train): Halkyon Train's shell, Todo's copied and renamed (ADR 0030, D12)
apps/train with halkyon_train_server, _client and _flutter, as Todo's:
halkyon_base configured by trainBase(), its own register alone and a
member of the instance's where the operator names one, the app on
halkyon_app's gates with Train's frame, account sheet and About, texts
in British English and German that speak of workouts, app.halkyon.train
on Android, iOS, Linux, macOS and Windows.
Where it differs from Todo: development ports of its own (8180 to 8190),
so it runs beside Learn's server; one initial migration with the schema
Todo's migrations end at (the same tables, compared line by line), not
Todo's seventeen; and Todo's icon as a placeholder until the icon tool
of ADR 0031 draws Train's bike. The workspace, the licences, the READMEs
and AGENTS.md name it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-28 10:26:49 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class _AppLocalizationsDelegate
|
|
|
|
|
|
extends LocalizationsDelegate<AppLocalizations> {
|
|
|
|
|
|
const _AppLocalizationsDelegate();
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
Future<AppLocalizations> load(Locale locale) {
|
|
|
|
|
|
return SynchronousFuture<AppLocalizations>(lookupAppLocalizations(locale));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
bool isSupported(Locale locale) =>
|
|
|
|
|
|
<String>['de', 'en'].contains(locale.languageCode);
|
|
|
|
|
|
|
|
|
|
|
|
@override
|
|
|
|
|
|
bool shouldReload(_AppLocalizationsDelegate old) => false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AppLocalizations lookupAppLocalizations(Locale locale) {
|
|
|
|
|
|
// Lookup logic when language+country codes are specified.
|
|
|
|
|
|
switch (locale.languageCode) {
|
|
|
|
|
|
case 'en':
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (locale.countryCode) {
|
|
|
|
|
|
case 'GB':
|
|
|
|
|
|
return AppLocalizationsEnGb();
|
|
|
|
|
|
case 'US':
|
|
|
|
|
|
return AppLocalizationsEnUs();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Lookup logic when only language code is specified.
|
|
|
|
|
|
switch (locale.languageCode) {
|
|
|
|
|
|
case 'de':
|
|
|
|
|
|
return AppLocalizationsDe();
|
|
|
|
|
|
case 'en':
|
|
|
|
|
|
return AppLocalizationsEn();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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.',
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|