mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-15 00:25:17 +00:00
feat: setup localization (l10n) and language switcher, add sidebar and navbar locale
This commit is contained in:
parent
8432dc6286
commit
f12d81259f
3
l10n.yaml
Normal file
3
l10n.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
arb-dir: lib/l10n
|
||||
template-arb-file: app_en.arb
|
||||
output-localization-file: app_localizations.dart
|
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
class SideBarTiles {
|
||||
final IconData icon;
|
||||
@ -7,16 +8,16 @@ class SideBarTiles {
|
||||
SideBarTiles({required this.icon, required this.title});
|
||||
}
|
||||
|
||||
List<SideBarTiles> sidebarTileList = [
|
||||
SideBarTiles(icon: SpotubeIcons.home, title: "Browse"),
|
||||
SideBarTiles(icon: SpotubeIcons.search, title: "Search"),
|
||||
SideBarTiles(icon: SpotubeIcons.library, title: "Library"),
|
||||
SideBarTiles(icon: SpotubeIcons.music, title: "Lyrics")
|
||||
];
|
||||
List<SideBarTiles> getSidebarTileList(AppLocalizations l10n) => [
|
||||
SideBarTiles(icon: SpotubeIcons.home, title: l10n.browse),
|
||||
SideBarTiles(icon: SpotubeIcons.search, title: l10n.search),
|
||||
SideBarTiles(icon: SpotubeIcons.library, title: l10n.library),
|
||||
SideBarTiles(icon: SpotubeIcons.music, title: l10n.lyrics),
|
||||
];
|
||||
|
||||
List<SideBarTiles> navbarTileList = [
|
||||
SideBarTiles(icon: SpotubeIcons.home, title: "Browse"),
|
||||
SideBarTiles(icon: SpotubeIcons.search, title: "Search"),
|
||||
SideBarTiles(icon: SpotubeIcons.library, title: "Library"),
|
||||
SideBarTiles(icon: SpotubeIcons.settings, title: "Settings")
|
||||
];
|
||||
List<SideBarTiles> getNavbarTileList(AppLocalizations l10n) => [
|
||||
SideBarTiles(icon: SpotubeIcons.home, title: l10n.browse),
|
||||
SideBarTiles(icon: SpotubeIcons.search, title: l10n.search),
|
||||
SideBarTiles(icon: SpotubeIcons.library, title: l10n.library),
|
||||
SideBarTiles(icon: SpotubeIcons.settings, title: l10n.settings)
|
||||
];
|
||||
|
@ -77,4 +77,5 @@ abstract class SpotubeIcons {
|
||||
static const dragHandle = Icons.drag_indicator;
|
||||
static const lightning = Icons.flash_on_rounded;
|
||||
static const colorSync = FeatherIcons.activity;
|
||||
static const language = FeatherIcons.globe;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import 'package:spotube/collections/assets.gen.dart';
|
||||
import 'package:spotube/collections/side_bar_tiles.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/hooks/use_breakpoints.dart';
|
||||
import 'package:spotube/hooks/use_brightness_value.dart';
|
||||
import 'package:spotube/hooks/use_sidebarx_controller.dart';
|
||||
@ -70,6 +71,9 @@ class Sidebar extends HookConsumerWidget {
|
||||
Color.lerp(bg, Colors.black, 0.45)!,
|
||||
);
|
||||
|
||||
final sidebarTileList =
|
||||
useMemoized(() => getSidebarTileList(context.l10n), [context.l10n]);
|
||||
|
||||
useEffect(() {
|
||||
controller.addListener(() {
|
||||
onSelectedIndexChanged(controller.selectedIndex);
|
||||
@ -263,7 +267,7 @@ class SidebarFooter extends HookConsumerWidget {
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Text(
|
||||
data.displayName ?? "Guest",
|
||||
data.displayName ?? context.l10n.guest,
|
||||
maxLines: 1,
|
||||
softWrap: false,
|
||||
overflow: TextOverflow.fade,
|
||||
|
@ -7,6 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:spotube/collections/side_bar_tiles.dart';
|
||||
import 'package:spotube/components/root/sidebar.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/hooks/use_breakpoints.dart';
|
||||
import 'package:spotube/hooks/use_brightness_value.dart';
|
||||
import 'package:spotube/provider/downloader_provider.dart';
|
||||
@ -39,6 +40,9 @@ class SpotubeNavigationBar extends HookConsumerWidget {
|
||||
theme.colorScheme.primary.withOpacity(0.2),
|
||||
);
|
||||
|
||||
final navbarTileList =
|
||||
useMemoized(() => getNavbarTileList(context.l10n), [context.l10n]);
|
||||
|
||||
useEffect(() {
|
||||
insideSelectedIndex.value = selectedIndex;
|
||||
return null;
|
||||
|
6
lib/extensions/context.dart
Normal file
6
lib/extensions/context.dart
Normal file
@ -0,0 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
extension AppLocale on BuildContext {
|
||||
AppLocalizations get l10n => AppLocalizations.of(this)!;
|
||||
}
|
8
lib/l10n/app_bn.arb
Normal file
8
lib/l10n/app_bn.arb
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"guest": "অতিথি",
|
||||
"browse": "ব্রাউজ করুন",
|
||||
"search": "অনুসন্ধান করুন",
|
||||
"library": "লাইব্রেরী",
|
||||
"lyrics": "গানের কথা",
|
||||
"settings": "সেটিংস"
|
||||
}
|
8
lib/l10n/app_en.arb
Normal file
8
lib/l10n/app_en.arb
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"guest": "Guest",
|
||||
"browse": "Browse",
|
||||
"search": "Search",
|
||||
"library": "Library",
|
||||
"lyrics": "Lyrics",
|
||||
"settings": "Settings"
|
||||
}
|
8
lib/l10n/l10n.dart
Normal file
8
lib/l10n/l10n.dart
Normal file
@ -0,0 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class L10n {
|
||||
static final all = [
|
||||
const Locale('en'),
|
||||
const Locale('bn', 'BD'),
|
||||
];
|
||||
}
|
@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_desktop_tools/flutter_desktop_tools.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:metadata_god/metadata_god.dart';
|
||||
@ -17,6 +18,7 @@ import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart
|
||||
import 'package:spotube/entities/cache_track.dart';
|
||||
import 'package:spotube/collections/routes.dart';
|
||||
import 'package:spotube/collections/intents.dart';
|
||||
import 'package:spotube/l10n/l10n.dart';
|
||||
import 'package:spotube/models/logger.dart';
|
||||
import 'package:spotube/provider/downloader_provider.dart';
|
||||
import 'package:spotube/provider/palette_provider.dart';
|
||||
@ -29,6 +31,7 @@ import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||
import 'package:system_theme/system_theme.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:spotube/hooks/use_init_sys_tray.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
Future<void> main(List<String> rawArgs) async {
|
||||
final parser = ArgParser();
|
||||
@ -189,6 +192,7 @@ class SpotubeState extends ConsumerState<Spotube> {
|
||||
ref.watch(userPreferencesProvider.select((s) => s.themeMode));
|
||||
final accentMaterialColor =
|
||||
ref.watch(userPreferencesProvider.select((s) => s.accentColorScheme));
|
||||
final locale = ref.watch(userPreferencesProvider.select((s) => s.locale));
|
||||
final paletteColor =
|
||||
ref.watch(paletteProvider.select((s) => s?.dominantColor?.color));
|
||||
|
||||
@ -203,6 +207,14 @@ class SpotubeState extends ConsumerState<Spotube> {
|
||||
}, []);
|
||||
|
||||
return MaterialApp.router(
|
||||
supportedLocales: L10n.all,
|
||||
locale: locale.languageCode == "system" ? null : locale,
|
||||
localizationsDelegates: const [
|
||||
AppLocalizations.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
routeInformationParser: router.routeInformationParser,
|
||||
routerDelegate: router.routerDelegate,
|
||||
routeInformationProvider: router.routeInformationProvider,
|
||||
|
@ -12,6 +12,7 @@ import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
|
||||
import 'package:spotube/components/shared/adaptive/adaptive_list_tile.dart';
|
||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||
import 'package:spotube/collections/spotify_markets.dart';
|
||||
import 'package:spotube/l10n/l10n.dart';
|
||||
import 'package:spotube/provider/authentication_provider.dart';
|
||||
import 'package:spotube/provider/downloader_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences_provider.dart';
|
||||
@ -127,6 +128,60 @@ class SettingsPage extends HookConsumerWidget {
|
||||
),
|
||||
);
|
||||
}),
|
||||
Text(
|
||||
" Language & Region",
|
||||
style: theme.textTheme.headlineSmall
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(SpotubeIcons.language),
|
||||
title: const Text("Language"),
|
||||
trailing: DropdownButton<Locale>(
|
||||
value: preferences.locale,
|
||||
items: [
|
||||
const DropdownMenuItem(
|
||||
value: Locale("system"),
|
||||
child: Text("System Default"),
|
||||
),
|
||||
for (final locale in L10n.all)
|
||||
DropdownMenuItem(
|
||||
value: locale,
|
||||
child: Text(locale.languageCode),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
preferences.setLocale(value);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
AdaptiveListTile(
|
||||
leading: const Icon(SpotubeIcons.shoppingBag),
|
||||
title: const Text("Market Place Region"),
|
||||
subtitle: const Text("Recommendation Country"),
|
||||
trailing: (context, update) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 350),
|
||||
child: DropdownMenu(
|
||||
initialSelection: preferences.recommendationMarket,
|
||||
dropdownMenuEntries: spotifyMarkets
|
||||
.map(
|
||||
(country) => DropdownMenuEntry(
|
||||
value: country.first,
|
||||
label: country.last,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onSelected: (value) {
|
||||
if (value == null) return;
|
||||
preferences.setRecommendationMarket(
|
||||
value as String,
|
||||
);
|
||||
update?.call(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
" Appearance",
|
||||
style: theme.textTheme.headlineSmall
|
||||
@ -273,37 +328,6 @@ class SettingsPage extends HookConsumerWidget {
|
||||
},
|
||||
trailing: const Icon(SpotubeIcons.angleRight),
|
||||
),
|
||||
Text(
|
||||
" Search",
|
||||
style: theme.textTheme.headlineSmall
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
),
|
||||
AdaptiveListTile(
|
||||
leading: const Icon(SpotubeIcons.shoppingBag),
|
||||
title: const Text("Market Place"),
|
||||
subtitle: const Text("Recommendation Country"),
|
||||
trailing: (context, update) => ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 350),
|
||||
child: DropdownMenu(
|
||||
initialSelection: preferences.recommendationMarket,
|
||||
dropdownMenuEntries: spotifyMarkets
|
||||
.map(
|
||||
(country) => DropdownMenuEntry(
|
||||
value: country.first,
|
||||
label: country.last,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onSelected: (value) {
|
||||
if (value == null) return;
|
||||
preferences.setRecommendationMarket(
|
||||
value as String,
|
||||
);
|
||||
update?.call(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(
|
||||
" Downloads",
|
||||
style: theme.textTheme.headlineSmall
|
||||
|
@ -48,6 +48,8 @@ class UserPreferences extends PersistedChangeNotifier {
|
||||
|
||||
bool showSystemTrayIcon;
|
||||
|
||||
Locale locale;
|
||||
|
||||
final Ref ref;
|
||||
|
||||
UserPreferences(
|
||||
@ -65,6 +67,7 @@ class UserPreferences extends PersistedChangeNotifier {
|
||||
this.downloadLocation = "",
|
||||
this.closeBehavior = CloseBehavior.minimizeToTray,
|
||||
this.showSystemTrayIcon = true,
|
||||
this.locale = const Locale("system"),
|
||||
}) : super() {
|
||||
if (downloadLocation.isEmpty) {
|
||||
_getDefaultDownloadDirectory().then(
|
||||
@ -159,6 +162,12 @@ class UserPreferences extends PersistedChangeNotifier {
|
||||
updatePersistence();
|
||||
}
|
||||
|
||||
void setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
notifyListeners();
|
||||
updatePersistence();
|
||||
}
|
||||
|
||||
Future<String> _getDefaultDownloadDirectory() async {
|
||||
if (kIsAndroid) return "/storage/emulated/0/Download/Spotube";
|
||||
|
||||
@ -201,6 +210,11 @@ class UserPreferences extends PersistedChangeNotifier {
|
||||
: closeBehavior;
|
||||
|
||||
showSystemTrayIcon = map["showSystemTrayIcon"] ?? showSystemTrayIcon;
|
||||
|
||||
locale = Locale(
|
||||
map["locale"]?["lc"] ?? locale.languageCode,
|
||||
map["locale"]?["cc"] ?? locale.countryCode,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -219,6 +233,7 @@ class UserPreferences extends PersistedChangeNotifier {
|
||||
"predownload": predownload,
|
||||
"closeBehavior": closeBehavior.index,
|
||||
"showSystemTrayIcon": showSystemTrayIcon,
|
||||
"locale": {"lc": locale.languageCode, "cc": locale.countryCode},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -467,7 +467,7 @@ packages:
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
dbus:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dbus
|
||||
sha256: "6f07cba3f7b3448d42d015bfd3d53fe12e5b36da2423f23838efc1d5fb31a263"
|
||||
@ -701,6 +701,11 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
flutter_localizations:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_mailer:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -946,7 +951,7 @@ packages:
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
intl:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
|
||||
|
28
pubspec.yaml
28
pubspec.yaml
@ -32,9 +32,15 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_cache_manager: ^3.3.0
|
||||
flutter_desktop_tools:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/flutter_desktop_tools.git
|
||||
ref: 1f0bec3283626dcbd8ee2f54e238d096d8dea50e
|
||||
flutter_feather_icons: ^2.0.0+1
|
||||
flutter_hooks: ^0.18.2+1
|
||||
flutter_inappwebview: ^5.7.2+3
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
flutter_riverpod: ^2.1.1
|
||||
flutter_secure_storage: ^8.0.0
|
||||
flutter_svg: ^1.1.6
|
||||
@ -45,12 +51,16 @@ dependencies:
|
||||
hooks_riverpod: ^2.1.1
|
||||
html: ^0.15.1
|
||||
http: ^0.13.5
|
||||
intl: ^0.17.0
|
||||
introduction_screen: ^3.0.2
|
||||
json_annotation: ^4.8.0
|
||||
json_serializable: ^6.6.0
|
||||
logger: ^1.1.0
|
||||
metadata_god: ^0.4.1
|
||||
mime: ^1.0.2
|
||||
mpris_service:
|
||||
git:
|
||||
url: https://github.com/alexmercerind/mpris_service
|
||||
package_info_plus: ^3.0.2
|
||||
palette_generator: ^0.3.3
|
||||
path: ^1.8.0
|
||||
@ -64,6 +74,11 @@ dependencies:
|
||||
sidebarx: ^0.15.0
|
||||
simple_circular_progress_bar: ^1.0.2
|
||||
skeleton_text: ^3.0.0
|
||||
smtc_windows:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/smtc_windows.git
|
||||
ref: 6cc93624b8fab8d7727c8693e91577a7413ccd13
|
||||
path: packages/smtc_windows
|
||||
spotify: ^0.11.0
|
||||
system_theme: ^2.1.0
|
||||
titlebar_buttons: ^1.0.0
|
||||
@ -79,18 +94,6 @@ dependencies:
|
||||
ref: a738913c8ce2c9f47515382d40827e794a334274
|
||||
path: plugins/window_size
|
||||
youtube_explode_dart: ^1.12.1
|
||||
flutter_desktop_tools:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/flutter_desktop_tools.git
|
||||
ref: 1f0bec3283626dcbd8ee2f54e238d096d8dea50e
|
||||
smtc_windows:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/smtc_windows.git
|
||||
ref: 6cc93624b8fab8d7727c8693e91577a7413ccd13
|
||||
path: packages/smtc_windows
|
||||
mpris_service:
|
||||
git:
|
||||
url: https://github.com/alexmercerind/mpris_service
|
||||
|
||||
dev_dependencies:
|
||||
build_runner: ^2.3.2
|
||||
@ -111,6 +114,7 @@ dependency_overrides:
|
||||
package_info_plus: ^3.0.2
|
||||
|
||||
flutter:
|
||||
generate: true
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/
|
||||
|
Loading…
Reference in New Issue
Block a user