mirror of
https://github.com/johrpan/memor.git
synced 2025-10-28 19:27:25 +01:00
Add german translation
This commit is contained in:
parent
4be8aa8ff5
commit
3b33e6879a
8 changed files with 117 additions and 28 deletions
13
lib/app.dart
13
lib/app.dart
|
|
@ -1,6 +1,9 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
|
||||||
|
import 'backend.dart';
|
||||||
import 'home_screen.dart';
|
import 'home_screen.dart';
|
||||||
|
import 'localizations.dart';
|
||||||
|
|
||||||
/// A simple reminder app.
|
/// A simple reminder app.
|
||||||
///
|
///
|
||||||
|
|
@ -9,6 +12,15 @@ class MemorApp extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
localizationsDelegates: const [
|
||||||
|
MemorLocalizations.delegate,
|
||||||
|
GlobalMaterialLocalizations.delegate,
|
||||||
|
GlobalWidgetsLocalizations.delegate,
|
||||||
|
],
|
||||||
|
supportedLocales: const [
|
||||||
|
Locale('en'),
|
||||||
|
Locale('de'),
|
||||||
|
],
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
primaryColor: Colors.black,
|
primaryColor: Colors.black,
|
||||||
accentColor: Colors.amber,
|
accentColor: Colors.amber,
|
||||||
|
|
@ -21,6 +33,7 @@ class MemorApp extends StatelessWidget {
|
||||||
),
|
),
|
||||||
fontFamily: 'Libertinus Sans',
|
fontFamily: 'Libertinus Sans',
|
||||||
),
|
),
|
||||||
|
builder: (context, child) => MemorBackend(child: child),
|
||||||
home: HomeScreen(),
|
home: HomeScreen(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:path/path.dart' as p;
|
||||||
import 'package:path_provider/path_provider.dart' as pp;
|
import 'package:path_provider/path_provider.dart' as pp;
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
|
|
||||||
|
import 'localizations.dart';
|
||||||
import 'memo.dart';
|
import 'memo.dart';
|
||||||
|
|
||||||
/// Widget for managing resources and state for Memor.
|
/// Widget for managing resources and state for Memor.
|
||||||
|
|
@ -46,10 +47,6 @@ class MemorBackendState extends State<MemorBackend> {
|
||||||
|
|
||||||
static const _fileName = 'memos.json';
|
static const _fileName = 'memos.json';
|
||||||
|
|
||||||
static const _notificationDetails = NotificationDetails(
|
|
||||||
AndroidNotificationDetails('memor', 'Memor', 'Memor reminders'),
|
|
||||||
IOSNotificationDetails());
|
|
||||||
|
|
||||||
final _notifications = FlutterLocalNotificationsPlugin();
|
final _notifications = FlutterLocalNotificationsPlugin();
|
||||||
File _file;
|
File _file;
|
||||||
|
|
||||||
|
|
@ -133,12 +130,20 @@ class MemorBackendState extends State<MemorBackend> {
|
||||||
|
|
||||||
/// Schedule a notification for a memo.
|
/// Schedule a notification for a memo.
|
||||||
Future<void> _schedule(Memo memo) async {
|
Future<void> _schedule(Memo memo) async {
|
||||||
|
final l10n = MemorLocalizations.of(context);
|
||||||
_notifications.schedule(
|
_notifications.schedule(
|
||||||
memo.id,
|
memo.id,
|
||||||
'Reminder',
|
l10n.reminder,
|
||||||
memo.text,
|
memo.text,
|
||||||
memo.scheduled,
|
memo.scheduled,
|
||||||
_notificationDetails,
|
NotificationDetails(
|
||||||
|
AndroidNotificationDetails(
|
||||||
|
'memor',
|
||||||
|
'Memor',
|
||||||
|
l10n.notificationDescription,
|
||||||
|
),
|
||||||
|
IOSNotificationDetails(),
|
||||||
|
),
|
||||||
androidAllowWhileIdle: true,
|
androidAllowWhileIdle: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
import 'localizations.dart';
|
||||||
|
|
||||||
/// Utilities for handling DateTime objects.
|
/// Utilities for handling DateTime objects.
|
||||||
extension DateUtils on DateTime {
|
extension DateUtils on DateTime {
|
||||||
/// Create a new instance with identical values.
|
/// Create a new instance with identical values.
|
||||||
|
|
@ -21,18 +23,20 @@ extension DateUtils on DateTime {
|
||||||
time.minute,
|
time.minute,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Get a string representation of the represented day suitable for display.
|
/// Get a localized string representation of the represented day suitable for
|
||||||
String get dateString {
|
/// display.
|
||||||
|
String dateString(BuildContext context) {
|
||||||
|
final l10n = MemorLocalizations.of(context);
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
if (this.year == now.year && this.month == now.month) {
|
if (this.year == now.year && this.month == now.month) {
|
||||||
if (this.day == now.day) {
|
if (this.day == now.day) {
|
||||||
return 'Today';
|
return l10n.today;
|
||||||
} else if (this.day == now.day + 1) {
|
} else if (this.day == now.day + 1) {
|
||||||
return 'Tomorrow';
|
return l10n.tomorrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final format = DateFormat.yMd();
|
final format = DateFormat.yMd(l10n.languageCode);
|
||||||
return format.format(this);
|
return format.format(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'backend.dart';
|
import 'backend.dart';
|
||||||
import 'date_utils.dart';
|
import 'date_utils.dart';
|
||||||
|
import 'localizations.dart';
|
||||||
import 'memo.dart';
|
import 'memo.dart';
|
||||||
import 'memo_editor.dart';
|
import 'memo_editor.dart';
|
||||||
|
|
||||||
|
|
@ -25,10 +26,11 @@ class HomeScreen extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final backend = MemorBackend.of(context);
|
final backend = MemorBackend.of(context);
|
||||||
|
final l10n = MemorLocalizations.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Memor'),
|
title: Text(l10n.title),
|
||||||
),
|
),
|
||||||
body: backend.loading
|
body: backend.loading
|
||||||
? Center(
|
? Center(
|
||||||
|
|
@ -46,7 +48,7 @@ class HomeScreen extends StatelessWidget {
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final memo = memos[index];
|
final memo = memos[index];
|
||||||
final scheduled = memo.scheduled;
|
final scheduled = memo.scheduled;
|
||||||
final dateString = scheduled.dateString;
|
final dateString = scheduled.dateString(context);
|
||||||
final timeOfDayString =
|
final timeOfDayString =
|
||||||
scheduled.timeOfDay.format(context);
|
scheduled.timeOfDay.format(context);
|
||||||
|
|
||||||
|
|
@ -66,7 +68,8 @@ class HomeScreen extends StatelessWidget {
|
||||||
),
|
),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(memo.text),
|
title: Text(memo.text),
|
||||||
subtitle: Text('$dateString at $timeOfDayString'),
|
subtitle: Text(
|
||||||
|
l10n.scheduled(dateString, timeOfDayString)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result =
|
final result =
|
||||||
await _showMemoEditor(context, memo);
|
await _showMemoEditor(context, memo);
|
||||||
|
|
@ -79,9 +82,9 @@ class HomeScreen extends StatelessWidget {
|
||||||
await backend.deleteMemo(index);
|
await backend.deleteMemo(index);
|
||||||
Scaffold.of(context).showSnackBar(
|
Scaffold.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Deleted "${memo.text}"'),
|
content: Text(l10n.deleted(memo.text)),
|
||||||
action: SnackBarAction(
|
action: SnackBarAction(
|
||||||
label: 'UNDO',
|
label: l10n.undo,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await backend.addMemo(memo);
|
await backend.addMemo(memo);
|
||||||
},
|
},
|
||||||
|
|
@ -95,7 +98,7 @@ class HomeScreen extends StatelessWidget {
|
||||||
} else {
|
} else {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
'No reminders scheduled',
|
l10n.noReminders,
|
||||||
style: Theme.of(context).textTheme.headline6.copyWith(
|
style: Theme.of(context).textTheme.headline6.copyWith(
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
63
lib/localizations.dart
Normal file
63
lib/localizations.dart
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
class MemorLocalizations {
|
||||||
|
static const delegate = MemorLocalizationsDelegate();
|
||||||
|
|
||||||
|
static MemorLocalizations of(BuildContext context) =>
|
||||||
|
Localizations.of<MemorLocalizations>(context, MemorLocalizations);
|
||||||
|
|
||||||
|
final String languageCode;
|
||||||
|
|
||||||
|
MemorLocalizations(this.languageCode);
|
||||||
|
|
||||||
|
bool get de => languageCode == 'de';
|
||||||
|
|
||||||
|
// Home screen
|
||||||
|
|
||||||
|
String get title => 'Memor';
|
||||||
|
String scheduled(String date, String time) =>
|
||||||
|
de ? '$date um $time' : '$date at $time';
|
||||||
|
String deleted(String msg) => de ? '"$msg" gelöscht' : 'Deleted "$msg"';
|
||||||
|
String get undo => de ? 'RÜCKGÄNGIG' : 'UNDO';
|
||||||
|
String get noReminders =>
|
||||||
|
de ? 'Keine Erinnerungen eingerichtet' : 'No reminders scheduled';
|
||||||
|
|
||||||
|
// Memo editor
|
||||||
|
|
||||||
|
String get editTitle => de ? 'Memo bearbeiten' : 'Edit memo';
|
||||||
|
String get addTitle => de ? 'Memo erstellen' : 'Create memo';
|
||||||
|
String get save => de ? 'SPEICHERN' : 'SAVE';
|
||||||
|
String get create => de ? 'ERSTELLEN' : 'CREATE';
|
||||||
|
String get memo => 'Memo';
|
||||||
|
String get date => de ? 'Datum' : 'Date';
|
||||||
|
String get time => de ? 'Zeit' : 'Time';
|
||||||
|
|
||||||
|
// Backend
|
||||||
|
|
||||||
|
String get notificationDescription =>
|
||||||
|
de ? 'Memors Erinnerungen' : 'Memor reminders';
|
||||||
|
String get reminder => de ? 'Erinnerung' : 'Reminder';
|
||||||
|
|
||||||
|
// Date utils
|
||||||
|
|
||||||
|
String get today => de ? 'Heute' : 'Today';
|
||||||
|
String get tomorrow => de ? 'Morgen' : 'Tomorrow';
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemorLocalizationsDelegate
|
||||||
|
extends LocalizationsDelegate<MemorLocalizations> {
|
||||||
|
const MemorLocalizationsDelegate();
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isSupported(Locale locale) => ['en', 'de'].contains(locale.languageCode);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MemorLocalizations> load(Locale locale) {
|
||||||
|
return SynchronousFuture<MemorLocalizations>(
|
||||||
|
MemorLocalizations(locale.languageCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldReload(MemorLocalizationsDelegate old) => false;
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,9 @@
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'backend.dart';
|
|
||||||
import 'app.dart';
|
import 'app.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(
|
runApp(
|
||||||
MemorBackend(
|
MemorApp(),
|
||||||
child: MemorApp(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'localizations.dart';
|
||||||
import 'memo.dart';
|
import 'memo.dart';
|
||||||
import 'date_utils.dart';
|
import 'date_utils.dart';
|
||||||
|
|
||||||
|
|
@ -46,15 +47,16 @@ class _MemoEditorState extends State<MemoEditor> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = MemorLocalizations.of(context);
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(widget.memo != null ? 'Edit memo' : 'Add memo'),
|
title: Text(widget.memo != null ? l10n.editTitle : l10n.addTitle),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
FlatButton(
|
FlatButton(
|
||||||
child: Text(
|
child: Text(
|
||||||
widget.memo != null ? 'SAVE' : 'CREATE',
|
widget.memo != null ? l10n.save : l10n.create,
|
||||||
style: theme.textTheme.button.copyWith(
|
style: theme.textTheme.button.copyWith(
|
||||||
color: theme.colorScheme.onPrimary,
|
color: theme.colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
|
|
@ -80,13 +82,13 @@ class _MemoEditorState extends State<MemoEditor> {
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
labelText: 'Memo',
|
labelText: l10n.memo,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text('Date'),
|
title: Text(l10n.date),
|
||||||
subtitle: Text(_date.dateString),
|
subtitle: Text(_date.dateString(context)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result = await showDatePicker(
|
final result = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
|
|
@ -103,7 +105,7 @@ class _MemoEditorState extends State<MemoEditor> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text('Time'),
|
title: Text(l10n.time),
|
||||||
subtitle: Text(_time.format(context)),
|
subtitle: Text(_time.format(context)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final result = await showTimePicker(
|
final result = await showTimePicker(
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_localizations:
|
||||||
|
sdk: flutter
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
intl:
|
intl:
|
||||||
meta:
|
meta:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue