Add german translation

This commit is contained in:
Elias Projahn 2020-05-23 10:58:06 +02:00
parent 4be8aa8ff5
commit 3b33e6879a
8 changed files with 117 additions and 28 deletions

View file

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'backend.dart';
import 'home_screen.dart';
import 'localizations.dart';
/// A simple reminder app.
///
@ -9,6 +12,15 @@ class MemorApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: const [
MemorLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: const [
Locale('en'),
Locale('de'),
],
theme: ThemeData(
primaryColor: Colors.black,
accentColor: Colors.amber,
@ -21,6 +33,7 @@ class MemorApp extends StatelessWidget {
),
fontFamily: 'Libertinus Sans',
),
builder: (context, child) => MemorBackend(child: child),
home: HomeScreen(),
);
}

View file

@ -8,6 +8,7 @@ import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart' as pp;
import 'package:rxdart/rxdart.dart';
import 'localizations.dart';
import 'memo.dart';
/// Widget for managing resources and state for Memor.
@ -46,10 +47,6 @@ class MemorBackendState extends State<MemorBackend> {
static const _fileName = 'memos.json';
static const _notificationDetails = NotificationDetails(
AndroidNotificationDetails('memor', 'Memor', 'Memor reminders'),
IOSNotificationDetails());
final _notifications = FlutterLocalNotificationsPlugin();
File _file;
@ -133,12 +130,20 @@ class MemorBackendState extends State<MemorBackend> {
/// Schedule a notification for a memo.
Future<void> _schedule(Memo memo) async {
final l10n = MemorLocalizations.of(context);
_notifications.schedule(
memo.id,
'Reminder',
l10n.reminder,
memo.text,
memo.scheduled,
_notificationDetails,
NotificationDetails(
AndroidNotificationDetails(
'memor',
'Memor',
l10n.notificationDescription,
),
IOSNotificationDetails(),
),
androidAllowWhileIdle: true,
);
}

View file

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'localizations.dart';
/// Utilities for handling DateTime objects.
extension DateUtils on DateTime {
/// Create a new instance with identical values.
@ -21,18 +23,20 @@ extension DateUtils on DateTime {
time.minute,
);
/// Get a string representation of the represented day suitable for display.
String get dateString {
/// Get a localized string representation of the represented day suitable for
/// display.
String dateString(BuildContext context) {
final l10n = MemorLocalizations.of(context);
final now = DateTime.now();
if (this.year == now.year && this.month == now.month) {
if (this.day == now.day) {
return 'Today';
return l10n.today;
} 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);
}

View file

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'backend.dart';
import 'date_utils.dart';
import 'localizations.dart';
import 'memo.dart';
import 'memo_editor.dart';
@ -25,10 +26,11 @@ class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final backend = MemorBackend.of(context);
final l10n = MemorLocalizations.of(context);
return Scaffold(
appBar: AppBar(
title: Text('Memor'),
title: Text(l10n.title),
),
body: backend.loading
? Center(
@ -46,7 +48,7 @@ class HomeScreen extends StatelessWidget {
itemBuilder: (context, index) {
final memo = memos[index];
final scheduled = memo.scheduled;
final dateString = scheduled.dateString;
final dateString = scheduled.dateString(context);
final timeOfDayString =
scheduled.timeOfDay.format(context);
@ -66,7 +68,8 @@ class HomeScreen extends StatelessWidget {
),
child: ListTile(
title: Text(memo.text),
subtitle: Text('$dateString at $timeOfDayString'),
subtitle: Text(
l10n.scheduled(dateString, timeOfDayString)),
onTap: () async {
final result =
await _showMemoEditor(context, memo);
@ -79,9 +82,9 @@ class HomeScreen extends StatelessWidget {
await backend.deleteMemo(index);
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('Deleted "${memo.text}"'),
content: Text(l10n.deleted(memo.text)),
action: SnackBarAction(
label: 'UNDO',
label: l10n.undo,
onPressed: () async {
await backend.addMemo(memo);
},
@ -95,7 +98,7 @@ class HomeScreen extends StatelessWidget {
} else {
return Center(
child: Text(
'No reminders scheduled',
l10n.noReminders,
style: Theme.of(context).textTheme.headline6.copyWith(
color: Colors.grey,
),

63
lib/localizations.dart Normal file
View 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;
}

View file

@ -1,12 +1,9 @@
import 'package:flutter/widgets.dart';
import 'backend.dart';
import 'app.dart';
void main() {
runApp(
MemorBackend(
child: MemorApp(),
),
MemorApp(),
);
}

View file

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'localizations.dart';
import 'memo.dart';
import 'date_utils.dart';
@ -46,15 +47,16 @@ class _MemoEditorState extends State<MemoEditor> {
@override
Widget build(BuildContext context) {
final l10n = MemorLocalizations.of(context);
final theme = Theme.of(context);
return Scaffold(
appBar: AppBar(
title: Text(widget.memo != null ? 'Edit memo' : 'Add memo'),
title: Text(widget.memo != null ? l10n.editTitle : l10n.addTitle),
actions: <Widget>[
FlatButton(
child: Text(
widget.memo != null ? 'SAVE' : 'CREATE',
widget.memo != null ? l10n.save : l10n.create,
style: theme.textTheme.button.copyWith(
color: theme.colorScheme.onPrimary,
),
@ -80,13 +82,13 @@ class _MemoEditorState extends State<MemoEditor> {
maxLines: null,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Memo',
labelText: l10n.memo,
),
),
),
ListTile(
title: Text('Date'),
subtitle: Text(_date.dateString),
title: Text(l10n.date),
subtitle: Text(_date.dateString(context)),
onTap: () async {
final result = await showDatePicker(
context: context,
@ -103,7 +105,7 @@ class _MemoEditorState extends State<MemoEditor> {
},
),
ListTile(
title: Text('Time'),
title: Text(l10n.time),
subtitle: Text(_time.format(context)),
onTap: () async {
final result = await showTimePicker(

View file

@ -8,6 +8,8 @@ environment:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
flutter_local_notifications:
intl:
meta: