diff --git a/lib/components/player/player_actions.dart b/lib/components/player/player_actions.dart index 673c3e15b..6c51825a4 100644 --- a/lib/components/player/player_actions.dart +++ b/lib/components/player/player_actions.dart @@ -8,6 +8,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/player/player_queue.dart'; import 'package:spotube/components/player/sibling_tracks_sheet.dart'; import 'package:spotube/components/shared/heart_button.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -55,7 +56,7 @@ class PlayerActions extends HookConsumerWidget { children: [ IconButton( icon: const Icon(SpotubeIcons.queue), - tooltip: 'Queue', + tooltip: context.l10n.queue, onPressed: playlist != null ? () { showModalBottomSheet( @@ -81,7 +82,7 @@ class PlayerActions extends HookConsumerWidget { if (!isLocalTrack) IconButton( icon: const Icon(SpotubeIcons.alternativeRoute), - tooltip: "Alternative Track Sources", + tooltip: context.l10n.alternative_track_sources, onPressed: playlist?.activeTrack != null ? () { showModalBottomSheet( @@ -115,7 +116,7 @@ class PlayerActions extends HookConsumerWidget { ) else IconButton( - tooltip: 'Download track', + tooltip: context.l10n.download_track, icon: Icon( isDownloaded ? SpotubeIcons.done : SpotubeIcons.download, ), diff --git a/lib/components/player/player_controls.dart b/lib/components/player/player_controls.dart index 57027a5b1..91f336158 100644 --- a/lib/components/player/player_controls.dart +++ b/lib/components/player/player_controls.dart @@ -6,6 +6,7 @@ import 'package:palette_generator/palette_generator.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/use_progress.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/playlist_queue_provider.dart'; @@ -133,7 +134,7 @@ class PlayerControls extends HookConsumerWidget { return Column( children: [ Tooltip( - message: "Slide to seek forward or backward", + message: context.l10n.slide_to_seek, child: Slider( // cannot divide by zero // there's an edge case for value being bigger @@ -181,8 +182,8 @@ class PlayerControls extends HookConsumerWidget { children: [ IconButton( tooltip: playlist?.isShuffled == true - ? "Unshuffle playlist" - : "Shuffle playlist", + ? context.l10n.unshuffle_playlist + : context.l10n.shuffle_playlist, icon: const Icon(SpotubeIcons.shuffle), style: playlist?.isShuffled == true ? activeButtonStyle @@ -198,13 +199,15 @@ class PlayerControls extends HookConsumerWidget { }, ), IconButton( - tooltip: "Previous track", + tooltip: context.l10n.previous_track, icon: const Icon(SpotubeIcons.skipBack), style: buttonStyle, onPressed: playlistNotifier.previous, ), IconButton( - tooltip: playing ? "Pause playback" : "Resume playback", + tooltip: playing + ? context.l10n.pause_playback + : context.l10n.resume_playback, icon: playlist?.isLoading == true ? SizedBox( height: 20, @@ -224,15 +227,15 @@ class PlayerControls extends HookConsumerWidget { ), ), IconButton( - tooltip: "Next track", + tooltip: context.l10n.next_track, icon: const Icon(SpotubeIcons.skipForward), style: buttonStyle, onPressed: playlistNotifier.next, ), IconButton( tooltip: playlist?.isLooping != true - ? "Loop Track" - : "Repeat playlist", + ? context.l10n.loop_track + : context.l10n.repeat_playlist, icon: Icon( playlist?.isLooping == true ? SpotubeIcons.repeatOne diff --git a/lib/components/root/bottom_player.dart b/lib/components/root/bottom_player.dart index efec40542..3b15698e6 100644 --- a/lib/components/root/bottom_player.dart +++ b/lib/components/root/bottom_player.dart @@ -12,6 +12,7 @@ import 'package:spotube/components/player/player_actions.dart'; import 'package:spotube/components/player/player_overlay.dart'; import 'package:spotube/components/player/player_track_details.dart'; import 'package:spotube/components/player/player_controls.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/models/logger.dart'; @@ -130,7 +131,7 @@ class BottomPlayer extends HookConsumerWidget { PlayerActions( extraActions: [ IconButton( - tooltip: 'Mini Player', + tooltip: context.l10n.mini_player, icon: const Icon(SpotubeIcons.miniPlayer), onPressed: () async { await DesktopTools.window.setMinimumSize( diff --git a/lib/components/shared/heart_button.dart b/lib/components/shared/heart_button.dart index cff6ff4d3..8ec376ade 100644 --- a/lib/components/shared/heart_button.dart +++ b/lib/components/shared/heart_button.dart @@ -4,6 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/use_palette_color.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/services/mutations/mutations.dart'; @@ -120,7 +121,9 @@ class TrackHeartButton extends HookConsumerWidget { } return HeartButton( - tooltip: toggler.item1 ? "Remove from Favorite" : "Add to Favorite", + tooltip: toggler.item1 + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, isLiked: toggler.item1, onPressed: savedTracks.hasData ? () { @@ -174,8 +177,8 @@ class PlaylistHeartButton extends HookConsumerWidget { return HeartButton( isLiked: isLikedQuery.data ?? false, tooltip: isLikedQuery.data ?? false - ? "Remove from Favorite" - : "Add to Favorite", + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, color: color?.titleTextColor, onPressed: isLikedQuery.hasData ? () { @@ -216,7 +219,9 @@ class AlbumHeartButton extends HookConsumerWidget { return HeartButton( isLiked: isLiked, - tooltip: isLiked ? "Remove from Favorite" : "Add to Favorite", + tooltip: isLiked + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, onPressed: albumIsSaved.hasData ? () { toggleAlbumLike.mutate(isLiked); diff --git a/lib/components/shared/track_table/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view.dart index eb276ebe3..125ad1830 100644 --- a/lib/components/shared/track_table/track_collection_view.dart +++ b/lib/components/shared/track_table/track_collection_view.dart @@ -13,6 +13,7 @@ import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/use_custom_status_bar_color.dart'; import 'package:spotube/hooks/use_palette_color.dart'; import 'package:spotube/models/logger.dart'; @@ -80,7 +81,7 @@ class TrackCollectionView extends HookConsumerWidget { ), if (heartBtn != null && auth != null) heartBtn!, IconButton( - tooltip: "Shuffle", + tooltip: context.l10n.shuffle, icon: Icon( SpotubeIcons.shuffle, color: color?.titleTextColor, @@ -166,7 +167,7 @@ class TrackCollectionView extends HookConsumerWidget { onChanged: (value) => searchText.value = value, style: TextStyle(color: color?.titleTextColor), decoration: InputDecoration( - hintText: "Search tracks...", + hintText: context.l10n.search_tracks, hintStyle: TextStyle(color: color?.titleTextColor), border: theme.inputDecorationTheme.border?.copyWith( borderSide: BorderSide( @@ -211,7 +212,7 @@ class TrackCollectionView extends HookConsumerWidget { if (kIsMobile) CompactSearch( onChanged: (value) => searchText.value = value, - placeholder: "Search tracks...", + placeholder: context.l10n.search_tracks, iconColor: color?.titleTextColor, ), if (collapsed.value) ...buttons, @@ -287,7 +288,7 @@ class TrackCollectionView extends HookConsumerWidget { ), if (album != null) Text( - "${AlbumType.from(album?.albumType).formatted} • Released • ${DateTime.tryParse( + "${AlbumType.from(album?.albumType).formatted} • ${context.l10n.released} • ${DateTime.tryParse( album?.releaseDate ?? "", )?.year}", style: @@ -325,7 +326,10 @@ class TrackCollectionView extends HookConsumerWidget { return const ShimmerTrackTile(); } else if (tracksSnapshot.hasError) { return SliverToBoxAdapter( - child: Text("Error ${tracksSnapshot.error}")); + child: Text( + context.l10n.error(tracksSnapshot.error ?? ""), + ), + ); } return TracksTableView( diff --git a/lib/components/shared/track_table/track_tile.dart b/lib/components/shared/track_table/track_tile.dart index 98710bfc8..e5bc5d006 100644 --- a/lib/components/shared/track_table/track_tile.dart +++ b/lib/components/shared/track_table/track_tile.dart @@ -10,6 +10,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/heart_button.dart'; import 'package:spotube/components/shared/links/link_text.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/models/logger.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -90,7 +91,7 @@ class TrackTile extends HookConsumerWidget { width: 300, behavior: SnackBarBehavior.floating, content: Text( - "Copied $data to clipboard", + context.l10n.copied_to_clipboard(data), textAlign: TextAlign.center, ), ), @@ -114,7 +115,8 @@ class TrackTile extends HookConsumerWidget { final playlistsCheck = useState({}); return AlertDialog( title: Text( - "Add `${track.value.name}` to following Playlists", + context.l10n + .add_to_following_playlists(track.value.name!), style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, @@ -122,11 +124,11 @@ class TrackTile extends HookConsumerWidget { ), actions: [ OutlinedButton( - child: const Text("Cancel"), + child: Text(context.l10n.cancel), onPressed: () => Navigator.pop(context), ), FilledButton( - child: const Text("Add"), + child: Text(context.l10n.add), onPressed: () async { final selectedPlaylists = playlistsCheck .value.entries @@ -263,7 +265,7 @@ class TrackTile extends HookConsumerWidget { if (isBlackListed) ...[ const SizedBox(width: 5), Text( - "Blacklisted", + context.l10n.blacklisted, style: TextStyle( color: Colors.red[400], fontSize: 12, @@ -307,7 +309,7 @@ class TrackTile extends HookConsumerWidget { PopupMenuButton( icon: const Icon(SpotubeIcons.moreHorizontal), position: PopupMenuPosition.under, - tooltip: "More options", + tooltip: context.l10n.more_actions, itemBuilder: (context) { return [ if (!playlistQueueNotifier.isTrackOnQueue(track.value)) ...[ @@ -318,14 +320,15 @@ class TrackTile extends HookConsumerWidget { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - "Added ${track.value.name} to queue", + context.l10n + .added_track_to_queue(track.value.name!), ), ), ); }, - child: const ListTile( - leading: Icon(SpotubeIcons.queueAdd), - title: Text("Add to Queue"), + child: ListTile( + leading: const Icon(SpotubeIcons.queueAdd), + title: Text(context.l10n.add_to_queue), ), ), PopupMenuItem( @@ -334,14 +337,16 @@ class TrackTile extends HookConsumerWidget { playlistQueueNotifier.playNext([track.value]); ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: - Text("${track.value.name} will play next"), + content: Text( + context.l10n + .track_will_play_next(track.value.name!), + ), ), ); }, - child: const ListTile( - leading: Icon(SpotubeIcons.lightning), - title: Text("Play next"), + child: ListTile( + leading: const Icon(SpotubeIcons.lightning), + title: Text(context.l10n.play_next), ), ), ] else @@ -354,14 +359,17 @@ class TrackTile extends HookConsumerWidget { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( - "Removed ${track.value.name} from queue"), + context.l10n.removed_track_from_queue( + track.value.name!, + ), + ), ), ); }, enabled: playlist?.activeTrack.id != track.value.id, - child: const ListTile( - leading: Icon(SpotubeIcons.queueRemove), - title: Text("Remove from queue"), + child: ListTile( + leading: const Icon(SpotubeIcons.queueRemove), + title: Text(context.l10n.remove_from_queue), ), ), if (toggler.item3.hasData) @@ -378,7 +386,9 @@ class TrackTile extends HookConsumerWidget { ) : const Icon(SpotubeIcons.heart), title: Text( - "${toggler.item1 ? "Remove from" : "Save as "} favorite", + toggler.item1 + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, ), ), ), @@ -386,9 +396,9 @@ class TrackTile extends HookConsumerWidget { PopupMenuItem( padding: EdgeInsets.zero, onTap: actionAddToPlaylist, - child: const ListTile( - leading: Icon(SpotubeIcons.playlistAdd), - title: Text("Add To playlist"), + child: ListTile( + leading: const Icon(SpotubeIcons.playlistAdd), + title: Text(context.l10n.add_to_playlist), ), ), if (userPlaylist && auth != null) @@ -406,7 +416,7 @@ class TrackTile extends HookConsumerWidget { child: CircularProgressIndicator(), ) : const Icon(SpotubeIcons.removeFilled), - title: const Text("Remove from playlist"), + title: Text(context.l10n.remove_from_playlist), ), ), PopupMenuItem( @@ -429,7 +439,9 @@ class TrackTile extends HookConsumerWidget { iconColor: !isBlackListed ? Colors.red[400] : null, textColor: !isBlackListed ? Colors.red[400] : null, title: Text( - "${isBlackListed ? "Remove from" : "Add to"} blacklist", + isBlackListed + ? context.l10n.remove_from_blacklist + : context.l10n.add_to_blacklist, ), ), ), @@ -438,9 +450,9 @@ class TrackTile extends HookConsumerWidget { onTap: () { actionShare(track.value); }, - child: const ListTile( - leading: Icon(SpotubeIcons.share), - title: Text("Share"), + child: ListTile( + leading: const Icon(SpotubeIcons.share), + title: Text(context.l10n.share), ), ) ]; diff --git a/lib/components/shared/track_table/tracks_table_view.dart b/lib/components/shared/track_table/tracks_table_view.dart index a95dcd211..aab060083 100644 --- a/lib/components/shared/track_table/tracks_table_view.dart +++ b/lib/components/shared/track_table/tracks_table_view.dart @@ -10,6 +10,7 @@ import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; import 'package:spotube/components/shared/track_table/track_tile.dart'; import 'package:spotube/components/library/user_local_tracks.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/use_breakpoints.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/downloader_provider.dart'; @@ -96,7 +97,7 @@ class TracksTableView extends HookConsumerWidget { child: Row( children: [ Text( - "Title", + context.l10n.title, style: tableHeadStyle, overflow: TextOverflow.ellipsis, ), @@ -110,7 +111,7 @@ class TracksTableView extends HookConsumerWidget { child: Row( children: [ Text( - "Album", + context.l10n.album, overflow: TextOverflow.ellipsis, style: tableHeadStyle, ), @@ -120,7 +121,7 @@ class TracksTableView extends HookConsumerWidget { ], if (!breakpoint.isSm) ...[ const SizedBox(width: 10), - Text("Time", style: tableHeadStyle), + Text(context.l10n.time, style: tableHeadStyle), const SizedBox(width: 10), ], SortTracksDropdown( @@ -133,7 +134,7 @@ class TracksTableView extends HookConsumerWidget { }, ), PopupMenuButton( - tooltip: "More Actions", + tooltip: context.l10n.more_actions, itemBuilder: (context) { return [ PopupMenuItem( @@ -144,7 +145,8 @@ class TracksTableView extends HookConsumerWidget { const Icon(SpotubeIcons.download), const SizedBox(width: 5), Text( - "Download ${selectedTracks.isNotEmpty ? "(${selectedTracks.length})" : ""}", + context.l10n + .download_count(selectedTracks.length), ), ], ), @@ -158,7 +160,9 @@ class TracksTableView extends HookConsumerWidget { const Icon(SpotubeIcons.playlistAdd), const SizedBox(width: 5), Text( - "Add (${selectedTracks.length}) to Playlist", + context.l10n.add_count_to_playlist( + selectedTracks.length, + ), ), ], ), @@ -171,7 +175,8 @@ class TracksTableView extends HookConsumerWidget { const Icon(SpotubeIcons.queueAdd), const SizedBox(width: 5), Text( - "Add (${selectedTracks.length}) to Queue", + context.l10n + .add_count_to_queue(selectedTracks.length), ), ], ), @@ -184,7 +189,8 @@ class TracksTableView extends HookConsumerWidget { const Icon(SpotubeIcons.lightning), const SizedBox(width: 5), Text( - "Play (${selectedTracks.length}) Next", + context.l10n + .play_count_next(selectedTracks.length), ), ], ), diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 5c9265795..a3d676903 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -57,5 +57,46 @@ "added_to_queue": "{tracks}টি গানের ট্র্যাক কিউতে যোগ করা হয়েছে", "filter_albums": "অ্যালবাম অনুসন্ধান করুন...", "synced": "সময়ের সাথে সুসংগত", - "plain": "অসুসংগত" + "plain": "অসুসংগত", + "shuffle": "অদলবদল", + "search_tracks": "গান অনুসন্ধান করুন...", + "released": "প্রকাশিত হয়েছে", + "error": "ত্রুটি {error}", + "title": "শিরোনাম", + "time": "সময়", + "more_actions": "আরও অপশন", + "download_count": "ডাউনলোড ({count}টি)", + "add_count_to_playlist": "প্লেলিস্টে যোগ করুন ({count}টি)", + "add_count_to_queue": "কিউতে যোগ করুন ({count}টি)", + "play_count_next": "পরবর্তীতে চালান ({count}টি)", + "album": "অ্যালবাম", + "copied_to_clipboard": "{data} ক্লিপবোর্ডে কপি করা হয়েছে", + "add_to_following_playlists": "নিম্নলিখিত প্লেলিস্টে {track} যোগ করুন", + "add": "যোগ করুন", + "added_track_to_queue": "কিউতে {track} যোগ করা হয়েছে", + "add_to_queue": "কিউতে যোগ করুন", + "track_will_play_next": "{track} পরবর্তীতে চালানো হবে", + "play_next": "পরবর্তীতে চালান", + "removed_track_from_queue": "কিউ থেকে {track} সরিয়ে নেওয়া হয়েছে", + "remove_from_queue": "কিউ থেকে সরান", + "remove_from_favorites": "পছন্দের তালিকা থেকে অপসারণ করুন", + "save_as_favorite": "পছন্দের তালিকায় সংরক্ষণ করুন", + "add_to_playlist": "প্লেলিস্টে যোগ করুন", + "remove_from_playlist": "প্লেলিস্ট থেকে সরান", + "add_to_blacklist": "ব্ল্যাকলিস্টে যোগ করুন", + "remove_from_blacklist": "ব্ল্যাকলিস্ট থেকে সরান", + "share": "শেয়ার করুন", + "mini_player": "মিনি প্লেয়ার", + "slide_to_seek": "গান সামনে বা পিছনে নিতে স্লাইড করুন", + "shuffle_playlist": "প্লেলিস্ট এলোমেলো করুন", + "unshuffle_playlist": "প্লেলিস্ট আগের মতো করুন", + "previous_track": "আগের গানের ট্র্যাক", + "next_track": "পরের গানের ট্র্যাক", + "pause_playback": "গান বন্ধ করুন", + "resume_playback": "গান চালু করুন", + "loop_track": "গান শেষে পুনরায় চালান", + "repeat_playlist": "প্লেলিস্ট শেষে পুনরায় চালান", + "queue": "গানের কিউ", + "alternative_track_sources": "বিকল্প গানের উৎস", + "download_track": "গান ডাউনলোড করুন" } \ No newline at end of file diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 01b8b4474..66adc2912 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -57,5 +57,46 @@ "added_to_queue": "Added {tracks} tracks to queue", "filter_albums": "Filter albums...", "synced": "Synced", - "plain": "Plain" + "plain": "Plain", + "shuffle": "Shuffle", + "search_tracks": "Search tracks...", + "released": "Released", + "error": "Error {error}", + "title": "Title", + "time": "Time", + "more_actions": "More actions", + "download_count": "Download ({count})", + "add_count_to_playlist": "Add ({count}) to Playlist", + "add_count_to_queue": "Add ({count}) to Queue", + "play_count_next": "Play ({count}) next", + "album": "Album", + "copied_to_clipboard": "Copied {data} to clipboard", + "add_to_following_playlists": "Add {track} to following Playlists", + "add": "Add", + "added_track_to_queue": "Added {track} to queue", + "add_to_queue": "Add to queue", + "track_will_play_next": "{track} will play next", + "play_next": "Play next", + "removed_track_from_queue": "Removed {track} from queue", + "remove_from_queue": "Remove from queue", + "remove_from_favorites": "Remove from favorites", + "save_as_favorite": "Save as favorite", + "add_to_playlist": "Add to playlist", + "remove_from_playlist": "Remove from playlist", + "add_to_blacklist": "Add to blacklist", + "remove_from_blacklist": "Remove from blacklist", + "share": "Share", + "mini_player": "Mini Player", + "slide_to_seek": "Slide to seek forward or backward", + "shuffle_playlist": "Shuffle playlist", + "unshuffle_playlist": "Unshuffle playlist", + "previous_track": "Previous track", + "next_track": "Next track", + "pause_playback": "Pause Playback", + "resume_playback": "Resume Playback", + "loop_track": "Loop track", + "repeat_playlist": "Repeat playlist", + "queue": "Queue", + "alternative_track_sources": "Alternative track sources", + "download_track": "Download track" } \ No newline at end of file