more translations

This commit is contained in:
Drew Weymouth
2024-07-21 11:13:26 -07:00
parent 1096e4434b
commit 9910d54f8e
9 changed files with 121 additions and 60 deletions
+55 -1
View File
@@ -1,54 +1,93 @@
{ {
"Add Server": "Add Server",
"Add to playlist": "Add to playlist", "Add to playlist": "Add to playlist",
"Add to queue": "Add to queue", "Add to queue": "Add to queue",
"Album": "Album", "Album": "Album",
"Album count": "Album count", "Album count": "Album count",
"Album filters": "Album filters",
"Album gain": "Album gain", "Album gain": "Album gain",
"Album info not available": "Album info not available", "Album info not available": "Album info not available",
"Album peak": "Album peak", "Album peak": "Album peak",
"Albums": "Albums", "Albums": "Albums",
"All": "All",
"All Tracks": "All Tracks", "All Tracks": "All Tracks",
"Alt. URL": "Alt. URL", "Alt. URL": "Alt. URL",
"Are you sure you want to delete the server": "Are you sure you want to delete the server",
"Artist": "Artist", "Artist": "Artist",
"Artists": "Artists", "Artists": "Artists",
"Artist biography not available.": "Artist biography not available.", "Artist biography not available.": "Artist biography not available.",
"Audio Drama": "Audio Drama",
"Audiobook": "Audiobook",
"Authentication failed": "Authentication failed",
"Autoselect device": "Autoselect device",
"Bit rate": "Bit rate", "Bit rate": "Bit rate",
"BPM": "BPM", "BPM": "BPM",
"Broadcast": "Broadcast",
"Cancel": "Cancel", "Cancel": "Cancel",
"Close": "Close", "Close": "Close",
"Close to system tray": "Close to system tray", "Close to system tray": "Close to system tray",
"Comment": "Comment", "Comment": "Comment",
"Compilation": "Compilation",
"Composer": "Composer", "Composer": "Composer",
"Configure your music server to add radio stations": "Configure your music server to add radio stations", "Configure your music server to add radio stations": "Configure your music server to add radio stations",
"Confirm Delete Playlist": "Confirm Delete Playlist",
"Confirm Delete Server": "Confirm Delete Server",
"Connect to Server": "Connect to Server",
"Connecting": "Connecting",
"Connecting to": "Connecting to",
"Content type": "Content type", "Content type": "Content type",
"Could not reach server": "Could not reach server",
"Create new playlist": "Create new playlist", "Create new playlist": "Create new playlist",
"day": "day",
"days": "days",
"Delete Playlist": "Delete Playlist", "Delete Playlist": "Delete Playlist",
"Demo": "Demo",
"Description": "Description", "Description": "Description",
"Disable server transcoding": "Disable server transcoding", "Disable server transcoding": "Disable server transcoding",
"Disc number": "Disc number", "Disc number": "Disc number",
"Discography": "Discography", "Discography": "Discography",
"DJ-Mix": "DJ-Mix",
"Download": "Download", "Download": "Download",
"Download completed": "Download completed",
"Duration": "Duration", "Duration": "Duration",
"Edit": "Edit", "Edit": "Edit",
"Edit Playlist": "Edit Playlist", "Edit Playlist": "Edit Playlist",
"Edit server": "Edit server",
"Enable system tray": "Enable system tray", "Enable system tray": "Enable system tray",
"Enabled": "Enabled", "Enabled": "Enabled",
"Enter": "Enter", "Enter": "Enter",
"EP": "EP",
"Equalizer": "Equalizer", "Equalizer": "Equalizer",
"Favorites": "Favorites", "Favorites": "Favorites",
"Field Recording": "Field Recording",
"File path": "File path", "File path": "File path",
"File size": "File size", "File size": "File size",
"Filter genres": "Filter genres",
"General": "General", "General": "General",
"Genre": "Genre", "Genre": "Genre",
"Genres": "Genres", "Genres": "Genres",
"Home Page": "Home Page",
"hr": "hr",
"hrs": "hrs",
"Internet Radio Stations": "Internet Radio Stations", "Internet Radio Stations": "Internet Radio Stations",
"Interview": "Interview",
"Is favorite": "Is favorite",
"Is not favorite": "Is not favorite",
"Last played": "Last played", "Last played": "Last played",
"Live": "Live",
"Login to Server": "Login to Server", "Login to Server": "Login to Server",
"Lyrics": "Lyrics", "Lyrics": "Lyrics",
"Lyrics not available": "Lyrics not available",
"min": "min",
"Mixtape": "Mixtape",
"My Server": "My Server", "My Server": "My Server",
"Name": "Name", "Name": "Name",
"Nickname": "Nickname", "Nickname": "Nickname",
"No radio stations available": "No radio stations available", "No radio stations available": "No radio stations available",
"None": "None",
"none": "none",
"(none)": "(none)",
"none selected": "none selected",
"OK": "OK", "OK": "OK",
"(optional)": "(optional)", "(optional)": "(optional)",
"Password": "Password", "Password": "Password",
@@ -63,22 +102,34 @@
"Private": "Private", "Private": "Private",
"Public": "Public", "Public": "Public",
"Related": "Related", "Related": "Related",
"Remix": "Remix",
"Remove from playlist": "Remove from playlist", "Remove from playlist": "Remove from playlist",
"Restart required": "Restart required", "Restart required": "Restart required",
"Save play queue on exit": "Save play queue on exit", "Save play queue on exit": "Save play queue on exit",
"Saved at": "Saved at",
"Search Everywhere": "Search Everywhere",
"Search page": "Search page", "Search page": "Search page",
"Search playlists or new playlist name": "Search playlists or new playlist name", "Search playlists or new playlist name": "Search playlists or new playlist name",
"sec": "sec",
"selected": "selected",
"Send playback statistics to server": "Send playback statistics to server", "Send playback statistics to server": "Send playback statistics to server",
"Server": "Server", "Server": "Server",
"Server Type": "Server Type", "Server Type": "Server Type",
"Server unreachable": "Server unreachable",
"Set rating": "Set rating",
"Share": "Share", "Share": "Share",
"Share content": "Share content",
"Show info": "Show info", "Show info": "Show info",
"Show notification on track change": "Show notification on track change", "Show notification on track change": "Show notification on track change",
"Show year in album grid cards": "Show year in album grid cards", "Show year in album grid cards": "Show year in album grid cards",
"Shuffle": "Shuffle", "Shuffle": "Shuffle",
"Similar artists": "Similar artists", "Similar artists": "Similar artists",
"Single": "Single",
"Skip duplicate tracks": "Skip duplicate tracks", "Skip duplicate tracks": "Skip duplicate tracks",
"Soundtrack": "Soundtrack",
"Spoken Word": "Spoken Word",
"Startup page": "Startup page", "Startup page": "Startup page",
"Testing connection": "Testing connection",
"Theme": "Theme", "Theme": "Theme",
"Title": "Title", "Title": "Title",
"Top Tracks": "Top Tracks", "Top Tracks": "Top Tracks",
@@ -93,5 +144,8 @@
"URL": "URL", "URL": "URL",
"Use legacy authentication": "Use legacy authentication", "Use legacy authentication": "Use legacy authentication",
"Username": "Username", "Username": "Username",
"Year": "Year" "wrong URL": "wrong URL",
"wrong username/password": "wrong username/password",
"Year": "Year",
"Year from": "Year from"
} }
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"github.com/dweymouth/supersonic/ui/widgets" "github.com/dweymouth/supersonic/ui/widgets"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
) )
@@ -58,7 +59,7 @@ func (g *genrePageAdapter) Route() controller.Route {
func (g *genrePageAdapter) ActionButton() *widget.Button { func (g *genrePageAdapter) ActionButton() *widget.Button {
fn := func() { go g.pm.PlayRandomSongs(g.genre) } fn := func() { go g.pm.PlayRandomSongs(g.genre) }
return widget.NewButtonWithIcon("Play random", myTheme.ShuffleIcon, fn) return widget.NewButtonWithIcon(lang.L("Play random"), myTheme.ShuffleIcon, fn)
} }
func (a *genrePageAdapter) Iter(sortOrder string, filter mediaprovider.AlbumFilter) widgets.GridViewIterator { func (a *genrePageAdapter) Iter(sortOrder string, filter mediaprovider.AlbumFilter) widgets.GridViewIterator {
+2 -2
View File
@@ -249,8 +249,8 @@ func NewRadioList(nowPlayingIDPtr *string) *RadioList {
a.playingIcon = container.NewCenter(widget.NewIcon(playIcon)) a.playingIcon = container.NewCenter(widget.NewIcon(playIcon))
a.ExtendBaseWidget(a) a.ExtendBaseWidget(a)
a.hdr = widgets.NewListHeader([]widgets.ListColumn{ a.hdr = widgets.NewListHeader([]widgets.ListColumn{
{Text: "Name", Alignment: fyne.TextAlignLeading, CanToggleVisible: false}, {Text: lang.L("Name"), Alignment: fyne.TextAlignLeading, CanToggleVisible: false},
{Text: "Home Page", Alignment: fyne.TextAlignLeading, CanToggleVisible: false}}, {Text: lang.L("Home Page"), Alignment: fyne.TextAlignLeading, CanToggleVisible: false}},
a.columnsLayout) a.columnsLayout)
a.hdr.DisableSorting = true a.hdr.DisableSorting = true
a.list = widgets.NewFocusList( a.list = widgets.NewFocusList(
+19 -18
View File
@@ -25,6 +25,7 @@ import (
"fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/dialog"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
@@ -246,7 +247,7 @@ func (m *Controller) GetArtistTracks(artistID string) []*mediaprovider.Track {
} }
func (m *Controller) PromptForFirstServer() { func (m *Controller) PromptForFirstServer() {
d := dialogs.NewAddEditServerDialog("Connect to Server", false, nil, m.MainWindow.Canvas().Focus) d := dialogs.NewAddEditServerDialog(lang.L("Connect to Server"), false, nil, m.MainWindow.Canvas().Focus)
pop := widget.NewModalPopUp(d, m.MainWindow.Canvas()) pop := widget.NewModalPopUp(d, m.MainWindow.Canvas())
d.OnSubmit = func() { d.OnSubmit = func() {
d.DisableSubmit() d.DisableSubmit()
@@ -333,7 +334,7 @@ func (m *Controller) DoEditPlaylistWorkflow(playlist *mediaprovider.Playlist) {
} }
dlg.OnDeletePlaylist = func() { dlg.OnDeletePlaylist = func() {
pop.Hide() pop.Hide()
dialog.ShowCustomConfirm("Confirm Delete Playlist", "OK", "Cancel", layout.NewSpacer(), /*custom content*/ dialog.ShowCustomConfirm(lang.L("Confirm Delete Playlist"), lang.L("OK"), lang.L("Cancel"), layout.NewSpacer(), /*custom content*/
func(ok bool) { func(ok bool) {
if !ok { if !ok {
pop.Show() pop.Show()
@@ -380,8 +381,8 @@ func (c *Controller) DoConnectToServerWorkflow(server *backend.ServerConfig) {
canceled := false canceled := false
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
dlg := dialog.NewCustom("Connecting", "Cancel", dlg := dialog.NewCustom(lang.L("Connecting"), lang.L("Cancel"),
widget.NewLabel(fmt.Sprintf("Connecting to %s", server.Nickname)), c.MainWindow) widget.NewLabel(fmt.Sprintf(lang.L("Connecting to")+" %s", server.Nickname)), c.MainWindow)
dlg.SetOnClosed(func() { dlg.SetOnClosed(func() {
canceled = true canceled = true
cancel() cancel()
@@ -414,16 +415,16 @@ func (m *Controller) PromptForLoginAndConnect() {
pop := widget.NewModalPopUp(d, m.MainWindow.Canvas()) pop := widget.NewModalPopUp(d, m.MainWindow.Canvas())
d.OnSubmit = func(server *backend.ServerConfig, password string) { d.OnSubmit = func(server *backend.ServerConfig, password string) {
d.DisableSubmit() d.DisableSubmit()
d.SetInfoText("Testing connection...") d.SetInfoText(lang.L("Testing connection") + "...")
go func() { go func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
err := m.App.ServerManager.TestConnectionAndAuth(ctx, server.ServerConnection, password) err := m.App.ServerManager.TestConnectionAndAuth(ctx, server.ServerConnection, password)
if err == backend.ErrUnreachable { if err == backend.ErrUnreachable {
d.SetErrorText("Server unreachable") d.SetErrorText(lang.L("Server unreachable"))
} else if err != nil { } else if err != nil {
d.SetErrorText("Authentication failed") d.SetErrorText(lang.L("Authentication failed"))
} else { } else {
pop.Hide() pop.Hide()
m.trySetPasswordAndConnectToServer(server, password) m.trySetPasswordAndConnectToServer(server, password)
@@ -434,7 +435,7 @@ func (m *Controller) PromptForLoginAndConnect() {
} }
d.OnEditServer = func(server *backend.ServerConfig) { d.OnEditServer = func(server *backend.ServerConfig) {
pop.Hide() pop.Hide()
editD := dialogs.NewAddEditServerDialog("Edit server", true, server, m.MainWindow.Canvas().Focus) editD := dialogs.NewAddEditServerDialog(lang.L("Edit server"), true, server, m.MainWindow.Canvas().Focus)
editPop := widget.NewModalPopUp(editD, m.MainWindow.Canvas()) editPop := widget.NewModalPopUp(editD, m.MainWindow.Canvas())
editD.OnSubmit = func() { editD.OnSubmit = func() {
d.DisableSubmit() d.DisableSubmit()
@@ -461,7 +462,7 @@ func (m *Controller) PromptForLoginAndConnect() {
} }
d.OnNewServer = func() { d.OnNewServer = func() {
pop.Hide() pop.Hide()
newD := dialogs.NewAddEditServerDialog("Add server", true, nil, m.MainWindow.Canvas().Focus) newD := dialogs.NewAddEditServerDialog(lang.L("Add Server"), true, nil, m.MainWindow.Canvas().Focus)
newPop := widget.NewModalPopUp(newD, m.MainWindow.Canvas()) newPop := widget.NewModalPopUp(newD, m.MainWindow.Canvas())
newD.OnSubmit = func() { newD.OnSubmit = func() {
d.DisableSubmit() d.DisableSubmit()
@@ -491,8 +492,8 @@ func (m *Controller) PromptForLoginAndConnect() {
} }
d.OnDeleteServer = func(server *backend.ServerConfig) { d.OnDeleteServer = func(server *backend.ServerConfig) {
pop.Hide() pop.Hide()
dialog.ShowConfirm("Confirm delete server", dialog.ShowConfirm(lang.L("Confirm Delete Server"),
fmt.Sprintf("Are you sure you want to delete the server %q?", server.Nickname), fmt.Sprintf(lang.L("Are you sure you want to delete the server")+" %q?", server.Nickname),
func(ok bool) { func(ok bool) {
if ok { if ok {
m.App.ServerManager.DeleteServer(server.ID) m.App.ServerManager.DeleteServer(server.ID)
@@ -527,7 +528,7 @@ func (c *Controller) ShowSettingsDialog(themeUpdateCallbk func(), themeFiles map
devs, err := c.App.LocalPlayer.ListAudioDevices() devs, err := c.App.LocalPlayer.ListAudioDevices()
if err != nil { if err != nil {
log.Printf("error listing audio devices: %v", err) log.Printf("error listing audio devices: %v", err)
devs = []mpv.AudioDevice{{Name: "auto", Description: "Autoselect device"}} devs = []mpv.AudioDevice{{Name: "auto", Description: lang.L("Autoselect device")}}
} }
curPlayer := c.App.PlaybackManager.CurrentPlayer() curPlayer := c.App.PlaybackManager.CurrentPlayer()
@@ -634,7 +635,7 @@ func (c *Controller) tryConnectToServer(ctx context.Context, server *backend.Ser
} }
func (c *Controller) testConnectionAndUpdateDialogText(dlg *dialogs.AddEditServerDialog) bool { func (c *Controller) testConnectionAndUpdateDialogText(dlg *dialogs.AddEditServerDialog) bool {
dlg.SetInfoText("Testing connection...") dlg.SetInfoText(lang.L("Testing connection") + "...")
conn := backend.ServerConnection{ conn := backend.ServerConnection{
ServerType: dlg.ServerType, ServerType: dlg.ServerType,
Hostname: dlg.Host, Hostname: dlg.Host,
@@ -646,10 +647,10 @@ func (c *Controller) testConnectionAndUpdateDialogText(dlg *dialogs.AddEditServe
defer cancel() defer cancel()
err := c.App.ServerManager.TestConnectionAndAuth(ctx, conn, dlg.Password) err := c.App.ServerManager.TestConnectionAndAuth(ctx, conn, dlg.Password)
if err == backend.ErrUnreachable { if err == backend.ErrUnreachable {
dlg.SetErrorText("Could not reach server (wrong hostname?)") dlg.SetErrorText(lang.L("Could not reach server") + fmt.Sprintf(" (%s?)", lang.L("wrong URL")))
return false return false
} else if err != nil { } else if err != nil {
dlg.SetErrorText("Authentication failed (wrong username/password)") dlg.SetErrorText(lang.L("Authentication failed") + fmt.Sprintf(" (%s)", lang.L("wrong username/password")))
return false return false
} }
return true return true
@@ -697,7 +698,7 @@ func (c *Controller) ShowShareDialog(id string) {
} }
hyperlink := widget.NewHyperlink(shareUrl.String(), shareUrl) hyperlink := widget.NewHyperlink(shareUrl.String(), shareUrl)
dlg := dialog.NewCustom("Share content", "OK", dlg := dialog.NewCustom(lang.L("Share content"), lang.L("OK"),
container.NewHBox( container.NewHBox(
hyperlink, hyperlink,
widget.NewButtonWithIcon("", theme.ContentCopyIcon(), func() { widget.NewButtonWithIcon("", theme.ContentCopyIcon(), func() {
@@ -787,7 +788,7 @@ func (c *Controller) downloadTrack(track *mediaprovider.Track, filePath string)
} }
log.Printf("Saved song %s to: %s\n", track.Title, filePath) log.Printf("Saved song %s to: %s\n", track.Title, filePath)
c.sendNotification(fmt.Sprintf("Download completed: %s", track.Title), fmt.Sprintf("Saved at: %s", filePath)) c.sendNotification(fmt.Sprintf(lang.L("Download completed")+": %s", track.Title), fmt.Sprintf(lang.L("Saved at")+": %s", filePath))
} }
func (c *Controller) downloadTracks(tracks []*mediaprovider.Track, filePath, downloadName string) { func (c *Controller) downloadTracks(tracks []*mediaprovider.Track, filePath, downloadName string) {
@@ -825,7 +826,7 @@ func (c *Controller) downloadTracks(tracks []*mediaprovider.Track, filePath, dow
log.Printf("Saved song %s to: %s\n", track.Title, filePath) log.Printf("Saved song %s to: %s\n", track.Title, filePath)
} }
c.sendNotification(fmt.Sprintf("Download completed: %s", downloadName), fmt.Sprintf("Saved at: %s", filePath)) c.sendNotification(fmt.Sprintf(lang.L("Download completed")+": %s", downloadName), fmt.Sprintf("Saved at: %s", filePath))
} }
func (c *Controller) sendNotification(title, content string) { func (c *Controller) sendNotification(title, content string) {
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"log" "log"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/lang"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
"github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/util"
) )
@@ -15,7 +16,7 @@ type QuickSearch struct {
func NewQuickSearch(mp mediaprovider.MediaProvider, im util.ImageFetcher) *QuickSearch { func NewQuickSearch(mp mediaprovider.MediaProvider, im util.ImageFetcher) *QuickSearch {
q := &QuickSearch{mp: mp} q := &QuickSearch{mp: mp}
q.SearchDialog = NewSearchDialog(im, "Quick Search", "Close", q.onSearched) q.SearchDialog = NewSearchDialog(im, lang.L("Search Everywhere"), lang.L("Close"), q.onSearched)
return q return q
} }
+25 -24
View File
@@ -12,6 +12,7 @@ import (
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
@@ -56,24 +57,24 @@ func SecondsToTimeString(s float64) string {
var str string var str string
if days > 0 { if days > 0 {
daysStr := "days" daysStr := lang.L("days")
if days == 1 { if days == 1 {
daysStr = "day" daysStr = lang.L("day")
} }
str = fmt.Sprintf("%d %s ", days, daysStr) str = fmt.Sprintf("%d %s ", days, daysStr)
} }
if hr > 0 { if hr > 0 {
hrStr := "hrs" hrStr := lang.L("hrs")
if hr == 1 { if hr == 1 {
hrStr = "hr" hrStr = lang.L("hr")
} }
str += fmt.Sprintf("%d %s ", hr, hrStr) str += fmt.Sprintf("%d %s ", hr, hrStr)
} }
if min > 0 { if min > 0 {
str += fmt.Sprintf("%d min ", min) str += fmt.Sprintf("%d %s ", min, lang.L("min"))
} }
if sec > 0 { if sec > 0 {
str += fmt.Sprintf("%d sec ", sec) str += fmt.Sprintf("%d %s ", sec, lang.L("sec"))
} }
return str[:len(str)-1] return str[:len(str)-1]
} }
@@ -158,45 +159,45 @@ func PlaintextFromHTMLString(s string) string {
} }
func DisplayReleaseType(releaseTypes mediaprovider.ReleaseTypes) string { func DisplayReleaseType(releaseTypes mediaprovider.ReleaseTypes) string {
baseType := "Album" baseType := lang.L("Album")
switch { switch {
case releaseTypes&mediaprovider.ReleaseTypeAudiobook > 0: case releaseTypes&mediaprovider.ReleaseTypeAudiobook > 0:
baseType = "Audiobook" baseType = lang.L("Audiobook")
case releaseTypes&mediaprovider.ReleaseTypeAudioDrama > 0: case releaseTypes&mediaprovider.ReleaseTypeAudioDrama > 0:
baseType = "Audio Drama" baseType = lang.L("Audio Drama")
case releaseTypes&mediaprovider.ReleaseTypeBroadcast > 0: case releaseTypes&mediaprovider.ReleaseTypeBroadcast > 0:
baseType = "Broadcast" baseType = lang.L("Broadcast")
case releaseTypes&mediaprovider.ReleaseTypeDJMix > 0: case releaseTypes&mediaprovider.ReleaseTypeDJMix > 0:
baseType = "DJ-Mix" baseType = lang.L("DJ-Mix")
case releaseTypes&mediaprovider.ReleaseTypeEP > 0: case releaseTypes&mediaprovider.ReleaseTypeEP > 0:
baseType = "EP" baseType = lang.L("EP")
case releaseTypes&mediaprovider.ReleaseTypeFieldRecording > 0: case releaseTypes&mediaprovider.ReleaseTypeFieldRecording > 0:
baseType = "Field Recording" baseType = lang.L("Field Recording")
case releaseTypes&mediaprovider.ReleaseTypeInterview > 0: case releaseTypes&mediaprovider.ReleaseTypeInterview > 0:
baseType = "Interview" baseType = lang.L("Interview")
case releaseTypes&mediaprovider.ReleaseTypeMixtape > 0: case releaseTypes&mediaprovider.ReleaseTypeMixtape > 0:
baseType = "Mixtape" baseType = lang.L("Mixtape")
case releaseTypes&mediaprovider.ReleaseTypeSingle > 0: case releaseTypes&mediaprovider.ReleaseTypeSingle > 0:
baseType = "Single" baseType = lang.L("Single")
case releaseTypes&mediaprovider.ReleaseTypeSoundtrack > 0: case releaseTypes&mediaprovider.ReleaseTypeSoundtrack > 0:
baseType = "Soundtrack" baseType = lang.L("Soundtrack")
} }
var modifiers []string var modifiers []string
if releaseTypes&mediaprovider.ReleaseTypeLive > 0 { if releaseTypes&mediaprovider.ReleaseTypeLive > 0 {
modifiers = append(modifiers, "Live") modifiers = append(modifiers, lang.L("Live"))
} }
if releaseTypes&mediaprovider.ReleaseTypeDemo > 0 { if releaseTypes&mediaprovider.ReleaseTypeDemo > 0 {
modifiers = append(modifiers, "Demo") modifiers = append(modifiers, lang.L("Demo"))
} }
if releaseTypes&mediaprovider.ReleaseTypeRemix > 0 { if releaseTypes&mediaprovider.ReleaseTypeRemix > 0 {
modifiers = append(modifiers, "Remix") modifiers = append(modifiers, lang.L("Remix"))
} }
if releaseTypes&mediaprovider.ReleaseTypeSpokenWord > 0 { if releaseTypes&mediaprovider.ReleaseTypeSpokenWord > 0 {
modifiers = append(modifiers, "Spoken Word") modifiers = append(modifiers, lang.L("Spoken Word"))
} }
if releaseTypes&mediaprovider.ReleaseTypeCompilation > 0 { if releaseTypes&mediaprovider.ReleaseTypeCompilation > 0 {
modifiers = append(modifiers, "Compilation") modifiers = append(modifiers, lang.L("Compilation"))
} }
modifiers = append(modifiers, baseType) modifiers = append(modifiers, baseType)
@@ -205,7 +206,7 @@ func DisplayReleaseType(releaseTypes mediaprovider.ReleaseTypes) string {
func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem { func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
newRatingMenuItem := func(rating int) *fyne.MenuItem { newRatingMenuItem := func(rating int) *fyne.MenuItem {
label := "(none)" label := lang.L("(none)")
if rating > 0 { if rating > 0 {
label = strconv.Itoa(rating) label = strconv.Itoa(rating)
} }
@@ -213,7 +214,7 @@ func NewRatingSubmenu(onSetRating func(int)) *fyne.MenuItem {
onSetRating(rating) onSetRating(rating)
}) })
} }
ratingMenu := fyne.NewMenuItem("Set rating", nil) ratingMenu := fyne.NewMenuItem(lang.L("Set rating"), nil)
ratingMenu.Icon = theme.NewThemedResource(res.ResStarOutlineSvg) ratingMenu.Icon = theme.NewThemedResource(res.ResStarOutlineSvg)
ratingMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{ ratingMenu.ChildMenu = fyne.NewMenu("", []*fyne.MenuItem{
newRatingMenuItem(0), newRatingMenuItem(0),
+12 -11
View File
@@ -11,6 +11,7 @@ import (
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
@@ -153,7 +154,7 @@ func NewAlbumFilterPopup(filter *AlbumFilterButton) *AlbumFilterPopup {
} }
// setup is favorite/not favorite filters // setup is favorite/not favorite filters
a.isFavorite = widget.NewCheck("Is favorite", func(fav bool) { a.isFavorite = widget.NewCheck(lang.L("Is favorite"), func(fav bool) {
filterOptions := a.filterBtn.filter.Options() filterOptions := a.filterBtn.filter.Options()
if fav { if fav {
a.isNotFavorite.SetChecked(false) a.isNotFavorite.SetChecked(false)
@@ -163,7 +164,7 @@ func NewAlbumFilterPopup(filter *AlbumFilterButton) *AlbumFilterPopup {
debounceOnChanged() debounceOnChanged()
}) })
a.isFavorite.Hidden = a.filterBtn.FavoriteDisabled a.isFavorite.Hidden = a.filterBtn.FavoriteDisabled
a.isNotFavorite = widget.NewCheck("Is not favorite", func(fav bool) { a.isNotFavorite = widget.NewCheck(lang.L("Is not favorite"), func(fav bool) {
filterOptions := a.filterBtn.filter.Options() filterOptions := a.filterBtn.filter.Options()
if fav { if fav {
a.isFavorite.SetChecked(false) a.isFavorite.SetChecked(false)
@@ -184,11 +185,11 @@ func NewAlbumFilterPopup(filter *AlbumFilterButton) *AlbumFilterPopup {
a.genreFilter.Hidden = a.filterBtn.GenreDisabled a.genreFilter.Hidden = a.filterBtn.GenreDisabled
// setup container // setup container
title := widget.NewLabel("Album filters") title := widget.NewLabel(lang.L("Album filters"))
title.TextStyle.Bold = true title.TextStyle.Bold = true
a.container = container.NewVBox( a.container = container.NewVBox(
container.NewHBox(layout.NewSpacer(), title, layout.NewSpacer()), container.NewHBox(layout.NewSpacer(), title, layout.NewSpacer()),
container.NewHBox(widget.NewLabel("Year from"), minYear, widget.NewLabel("to"), maxYear), container.NewHBox(widget.NewLabel(lang.L("Year from")), minYear, widget.NewLabel("to"), maxYear),
container.NewHBox(a.isFavorite, a.isNotFavorite), container.NewHBox(a.isFavorite, a.isNotFavorite),
a.genreFilter, a.genreFilter,
) )
@@ -281,7 +282,7 @@ func NewGenreFilterSubsection(onChanged func([]string), initialSelectedGenres []
}, },
) )
g.filterText = widget.NewEntry() g.filterText = widget.NewEntry()
g.filterText.SetPlaceHolder("Filter genres") g.filterText.SetPlaceHolder(lang.L("Filter genres"))
i := NewTappableIcon(theme.ContentClearIcon()) i := NewTappableIcon(theme.ContentClearIcon())
i.NoPointerCursor = true i.NoPointerCursor = true
i.OnTapped = func() { g.filterText.SetText("") } i.OnTapped = func() { g.filterText.SetText("") }
@@ -290,18 +291,18 @@ func NewGenreFilterSubsection(onChanged func([]string), initialSelectedGenres []
g.filterText.OnChanged = func(_ string) { g.filterText.OnChanged = func(_ string) {
debouncer() debouncer()
} }
g.allBtn = widget.NewButton("All", func() { g.selectAllOrNoneInView(false) }) g.allBtn = widget.NewButton(lang.L("All"), func() { g.selectAllOrNoneInView(false) })
g.noneBtn = widget.NewButton("None", func() { g.selectAllOrNoneInView(true) }) g.noneBtn = widget.NewButton(lang.L("None"), func() { g.selectAllOrNoneInView(true) })
g.genresTitleLine = widget.NewRichText( g.genresTitleLine = widget.NewRichText(
&widget.TextSegment{ &widget.TextSegment{
Text: "Genres ", Text: lang.L("Genres") + " ",
Style: widget.RichTextStyle{ Style: widget.RichTextStyle{
Inline: true, Inline: true,
TextStyle: fyne.TextStyle{Bold: true}, TextStyle: fyne.TextStyle{Bold: true},
}, },
}, },
&widget.TextSegment{Text: "(none selected)"}, &widget.TextSegment{Text: fmt.Sprintf("(%s)", lang.L("none selected"))},
) )
g.updateNumSelectedText() g.updateNumSelectedText()
@@ -378,11 +379,11 @@ func (g *GenreFilterSubsection) invokeOnChanged() {
} }
func (g *GenreFilterSubsection) updateNumSelectedText() { func (g *GenreFilterSubsection) updateNumSelectedText() {
numText := "none" numText := lang.L("none")
if l := len(g.selectedGenres); l > 0 { if l := len(g.selectedGenres); l > 0 {
numText = strconv.Itoa(l) numText = strconv.Itoa(l)
} }
t := fmt.Sprintf("(%s selected)", numText) t := fmt.Sprintf("(%s %s)", numText, lang.L("selected"))
g.genresTitleLine.Segments[1].(*widget.TextSegment).Text = t g.genresTitleLine.Segments[1].(*widget.TextSegment).Text = t
g.genresTitleLine.Refresh() g.genresTitleLine.Refresh()
} }
+2 -1
View File
@@ -3,6 +3,7 @@ package widgets
import ( import (
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/container" "fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
fynelyrics "github.com/dweymouth/fyne-lyrics" fynelyrics "github.com/dweymouth/fyne-lyrics"
"github.com/dweymouth/supersonic/backend/mediaprovider" "github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -29,7 +30,7 @@ type LyricsViewer struct {
func NewLyricsViewer() *LyricsViewer { func NewLyricsViewer() *LyricsViewer {
l := &LyricsViewer{ l := &LyricsViewer{
noLyricsMsg: container.NewCenter(NewInfoMessage( noLyricsMsg: container.NewCenter(NewInfoMessage(
"Lyrics not available", "")), lang.L("Lyrics not available"), "")),
isEmpty: true, isEmpty: true,
} }
l.ExtendBaseWidget(l) l.ExtendBaseWidget(l)
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"time" "time"
"fyne.io/fyne/v2" "fyne.io/fyne/v2"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget" "fyne.io/fyne/v2/widget"
"github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/util"
@@ -27,7 +28,7 @@ func NewSearchEntry() *SearchEntry {
// For use only by extending widgets // For use only by extending widgets
func (sf *SearchEntry) Init() { func (sf *SearchEntry) Init() {
sf.PlaceHolder = "Search" sf.PlaceHolder = lang.L("Search")
sf.ActionItem = NewClearTextButton(func() { sf.ActionItem = NewClearTextButton(func() {
sf.SetText("") sf.SetText("")
}) })