feat: Add i18n using slang
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
/// The type of medium we are tracking. Useful for UI stuff.
|
||||
@@ -74,25 +75,25 @@ extension MediumStateExtension on MediumTrackingState {
|
||||
case MediumTrackingState.ongoing:
|
||||
switch (type) {
|
||||
case TrackingMediumType.anime:
|
||||
return 'Watching';
|
||||
return t.data.ongoing.anime;
|
||||
case TrackingMediumType.manga:
|
||||
return 'Reading';
|
||||
return t.data.ongoing.manga;
|
||||
}
|
||||
case MediumTrackingState.completed:
|
||||
return 'Completed';
|
||||
return t.data.completed;
|
||||
case MediumTrackingState.planned:
|
||||
switch (type) {
|
||||
case TrackingMediumType.anime:
|
||||
return 'Plan to watch';
|
||||
return t.data.planned.anime;
|
||||
case TrackingMediumType.manga:
|
||||
return 'Plan to read';
|
||||
return t.data.planned.manga;
|
||||
}
|
||||
case MediumTrackingState.dropped:
|
||||
return 'Dropped';
|
||||
return t.data.dropped;
|
||||
case MediumTrackingState.paused:
|
||||
return 'Paused';
|
||||
return t.data.paused;
|
||||
case MediumTrackingState.all:
|
||||
return 'All';
|
||||
return t.data.all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:anitrack/licenses.g.dart';
|
||||
import 'package:anitrack/src/ui/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -19,7 +20,7 @@ class AboutPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('About'),
|
||||
title: Text(t.about.title),
|
||||
),
|
||||
body: ListView.builder(
|
||||
itemCount: ossLicenses.length + 1,
|
||||
@@ -41,7 +42,7 @@ class AboutPage extends StatelessWidget {
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
child: const Text('Source'),
|
||||
child: Text(t.about.source),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:anitrack/src/data/type.dart';
|
||||
import 'package:anitrack/src/ui/bloc/anime_list_bloc.dart';
|
||||
import 'package:anitrack/src/ui/bloc/anime_search_bloc.dart';
|
||||
@@ -58,9 +59,9 @@ class AnimeListPageState extends State<AnimeListPage> {
|
||||
String _getPageTitle(TrackingMediumType type) {
|
||||
switch (type) {
|
||||
case TrackingMediumType.anime:
|
||||
return 'Anime';
|
||||
return t.content.anime;
|
||||
case TrackingMediumType.manga:
|
||||
return 'Manga';
|
||||
return t.content.manga;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,14 +157,14 @@ class AnimeListPageState extends State<AnimeListPage> {
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.settings),
|
||||
title: const Text('Settings'),
|
||||
title: Text(t.settings.title),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(settingsRoute);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info),
|
||||
title: const Text('About'),
|
||||
title: Text(t.about.title),
|
||||
onTap: () {
|
||||
Navigator.of(context).pushNamed(aboutRoute);
|
||||
},
|
||||
@@ -294,7 +295,7 @@ class AnimeListPageState extends State<AnimeListPage> {
|
||||
AnimeSearchRequestedEvent(state.trackingType),
|
||||
);
|
||||
},
|
||||
tooltip: 'Add new item',
|
||||
tooltip: t.tooltips.addNewItem,
|
||||
child: const Icon(Icons.add),
|
||||
),
|
||||
);
|
||||
@@ -314,15 +315,15 @@ class AnimeListPageState extends State<AnimeListPage> {
|
||||
|
||||
_controller.jumpToPage(index);
|
||||
},
|
||||
items: const [
|
||||
items: [
|
||||
BottomBarItem(
|
||||
icon: Icon(Icons.tv),
|
||||
title: Text('Anime'),
|
||||
icon: const Icon(Icons.tv),
|
||||
title: Text(t.content.anime),
|
||||
activeColor: Colors.blue,
|
||||
),
|
||||
BottomBarItem(
|
||||
icon: Icon(Icons.auto_stories),
|
||||
title: Text('Manga'),
|
||||
icon: const Icon(Icons.auto_stories),
|
||||
title: Text(t.content.manga),
|
||||
activeColor: Colors.red,
|
||||
),
|
||||
],
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:anitrack/src/data/type.dart';
|
||||
import 'package:anitrack/src/ui/bloc/anime_search_bloc.dart';
|
||||
import 'package:anitrack/src/ui/constants.dart';
|
||||
@@ -25,8 +26,8 @@ class AnimeSearchPage extends StatelessWidget {
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
state.trackingType == TrackingMediumType.anime
|
||||
? 'Anime Search'
|
||||
: 'Manga Search',
|
||||
? t.search.anime
|
||||
: t.search.manga,
|
||||
),
|
||||
),
|
||||
body: Column(
|
||||
@@ -34,9 +35,9 @@ class AnimeSearchPage extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: TextField(
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
labelText: 'Search query',
|
||||
decoration: InputDecoration(
|
||||
border: const OutlineInputBorder(),
|
||||
labelText: t.search.query,
|
||||
),
|
||||
onSubmitted: (_) {
|
||||
context.read<AnimeSearchBloc>().add(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:anitrack/src/data/anime.dart';
|
||||
import 'package:anitrack/src/data/manga.dart';
|
||||
import 'package:anitrack/src/data/type.dart';
|
||||
@@ -26,7 +27,7 @@ class DetailsPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Details'),
|
||||
title: Text(t.details.title),
|
||||
),
|
||||
body: BlocBuilder<DetailsBloc, DetailsState>(
|
||||
builder: (context, state) {
|
||||
@@ -68,10 +69,10 @@ class DetailsPage extends StatelessWidget {
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text(
|
||||
'Remove "${state.data!.title}"?',
|
||||
t.details.removeTitle(title: state.data!.title),
|
||||
),
|
||||
content: Text(
|
||||
'Are you sure you want to remove "${state.data!.title}" from the list?',
|
||||
t.details.removeBody(title: state.data!.title),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
@@ -82,14 +83,14 @@ class DetailsPage extends StatelessWidget {
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.red,
|
||||
),
|
||||
child: const Text('Remove'),
|
||||
child: Text(t.details.removeButton),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
.pop(false);
|
||||
},
|
||||
child: const Text('Cancel'),
|
||||
child: Text(t.details.cancelButton),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -120,8 +121,8 @@ class DetailsPage extends StatelessWidget {
|
||||
),
|
||||
child: DropdownSelector<MediumTrackingState>(
|
||||
title: state.trackingType == TrackingMediumType.anime
|
||||
? 'Watch state'
|
||||
: 'Read state',
|
||||
? t.details.watchState
|
||||
: t.details.readState,
|
||||
onChanged: (MediumTrackingState newState) {
|
||||
if (state.trackingType ==
|
||||
TrackingMediumType.anime) {
|
||||
@@ -182,8 +183,8 @@ class DetailsPage extends StatelessWidget {
|
||||
child: IntegerInput(
|
||||
labelText:
|
||||
state.trackingType == TrackingMediumType.anime
|
||||
? 'Episodes'
|
||||
: 'Chapters',
|
||||
? t.details.episodes
|
||||
: t.details.chapters,
|
||||
onChanged: (value) {
|
||||
switch (state.trackingType) {
|
||||
case TrackingMediumType.anime:
|
||||
@@ -221,7 +222,7 @@ class DetailsPage extends StatelessWidget {
|
||||
vertical: 8,
|
||||
),
|
||||
child: IntegerInput(
|
||||
labelText: 'Volumes owned',
|
||||
labelText: t.details.volumesOwned,
|
||||
onChanged: (value) {
|
||||
final data = state.data! as MangaTrackingData;
|
||||
context.read<DetailsBloc>().add(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:anitrack/i18n/strings.g.dart';
|
||||
import 'package:anitrack/src/ui/bloc/settings_bloc.dart';
|
||||
import 'package:anitrack/src/ui/constants.dart';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
@@ -32,15 +33,13 @@ class SettingsPage extends StatelessWidget {
|
||||
bottom: 0,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Settings'),
|
||||
title: Text(t.settings.title),
|
||||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
ListTile(
|
||||
title: const Text('Import anime list'),
|
||||
subtitle: const Text(
|
||||
'Import anime list exported from MyAnimeList.',
|
||||
),
|
||||
title: Text(t.settings.importAnime),
|
||||
subtitle: Text(t.settings.importAnimeDesc),
|
||||
onTap: () async {
|
||||
// Pick the file
|
||||
final result = await FilePicker.platform.pickFiles();
|
||||
@@ -49,11 +48,9 @@ class SettingsPage extends StatelessWidget {
|
||||
if (!result.files.first.path!.endsWith('.xml.gz')) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => const AlertDialog(
|
||||
title: Text('Invalid anime list'),
|
||||
content: Text(
|
||||
'The selected file is not a MAL anime list. It lacks the ".xml.gz" suffix.',
|
||||
),
|
||||
builder: (_) => AlertDialog(
|
||||
title: Text(t.settings.invalidAnimeListTitle),
|
||||
content: Text(t.settings.invalidAnimeListBody),
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -68,10 +65,8 @@ class SettingsPage extends StatelessWidget {
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: const Text('Import manga list'),
|
||||
subtitle: const Text(
|
||||
'Import manga list exported from MyAnimeList.',
|
||||
),
|
||||
title: Text(t.settings.importManga),
|
||||
subtitle: Text(t.settings.importMangaDesc),
|
||||
onTap: () async {
|
||||
// Pick the file
|
||||
final result = await FilePicker.platform.pickFiles();
|
||||
@@ -80,11 +75,9 @@ class SettingsPage extends StatelessWidget {
|
||||
if (!result.files.first.path!.endsWith('.xml.gz')) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => const AlertDialog(
|
||||
title: Text('Invalid manga list'),
|
||||
content: Text(
|
||||
'The selected file is not a MAL manga list. It lacks the ".xml.gz" suffix.',
|
||||
),
|
||||
builder: (_) => AlertDialog(
|
||||
title: Text(t.settings.invalidMangaListTitle),
|
||||
content: Text(t.settings.invalidMangaListBody),
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -137,7 +130,10 @@ class SettingsPage extends StatelessWidget {
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
Text(
|
||||
'${state.importCurrent} of ${state.importTotal}',
|
||||
t.settings.importIndicator(
|
||||
current: state.importCurrent,
|
||||
total: state.importTotal,
|
||||
),
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user