and some more

This commit is contained in:
Drew Weymouth
2024-07-21 11:13:27 -07:00
parent 9910d54f8e
commit d48337c83b
12 changed files with 87 additions and 48 deletions
+31 -1
View File
@@ -3,12 +3,14 @@
"Add to playlist": "Add to playlist",
"Add to queue": "Add to queue",
"Album": "Album",
"album": "album",
"Album count": "Album count",
"Album filters": "Album filters",
"Album gain": "Album gain",
"Album info not available": "Album info not available",
"Album peak": "Album peak",
"Albums": "Albums",
"albums": "albums",
"All": "All",
"All Tracks": "All Tracks",
"Alt. URL": "Alt. URL",
@@ -16,9 +18,11 @@
"Artist": "Artist",
"Artists": "Artists",
"Artist biography not available.": "Artist biography not available.",
"Audio device": "Audio device",
"Audio Drama": "Audio Drama",
"Audiobook": "Audiobook",
"Authentication failed": "Authentication failed",
"Auto": "Auto",
"Autoselect device": "Autoselect device",
"Bit rate": "Bit rate",
"BPM": "BPM",
@@ -46,6 +50,7 @@
"Disable server transcoding": "Disable server transcoding",
"Disc number": "Disc number",
"Discography": "Discography",
"discs": "discs",
"DJ-Mix": "DJ-Mix",
"Download": "Download",
"Download completed": "Download completed",
@@ -58,6 +63,7 @@
"Enter": "Enter",
"EP": "EP",
"Equalizer": "Equalizer",
"Exclusive mode": "Exclusive mode",
"Favorites": "Favorites",
"Field Recording": "Field Recording",
"File path": "File path",
@@ -66,6 +72,7 @@
"General": "General",
"Genre": "Genre",
"Genres": "Genres",
"Github page": "Github page",
"Home Page": "Home Page",
"hr": "hr",
"hrs": "hrs",
@@ -75,10 +82,12 @@
"Is not favorite": "Is not favorite",
"Last played": "Last played",
"Live": "Live",
"Locally": "Locally",
"Login to Server": "Login to Server",
"Lyrics": "Lyrics",
"Lyrics not available": "Lyrics not available",
"min": "min",
"minutes of track have been played": "minutes of track have been played",
"Mixtape": "Mixtape",
"My Server": "My Server",
"Name": "Name",
@@ -89,24 +98,38 @@
"(none)": "(none)",
"none selected": "none selected",
"OK": "OK",
"(optional)": "(optional)",
"optional": "optional",
"or when": "or when",
"Password": "Password",
"Paused": "Paused",
"percent of track is played": "percent of track is played",
"Play": "Play",
"Play Artist Radio": "Play Artist Radio",
"Play count": "Play count",
"Play Discography": "Play Discography",
"Play next": "Play next",
"Play Queue": "Play Queue",
"Play random": "Play random",
"Playback": "Playback",
"Playing": "Playing",
"Playlist": "Playlist",
"Playlists": "Playlists",
"playlist by": "playlist by",
"Plays": "Plays",
"Prevent clipping": "Prevent clipping",
"Private": "Private",
"Public": "Public",
"Rating": "Rating",
"reissued": "reissued",
"Related": "Related",
"Remix": "Remix",
"Remove from playlist": "Remove from playlist",
"ReplayGain mode": "ReplayGain mode",
"ReplayGain preamp": "ReplayGain preamp",
"Restart required": "Restart required",
"Save play queue on exit": "Save play queue on exit",
"Saved at": "Saved at",
"Scrobble when": "Scrobble when",
"Search Everywhere": "Search Everywhere",
"Search page": "Search page",
"Search playlists or new playlist name": "Search playlists or new playlist name",
@@ -123,16 +146,21 @@
"Show notification on track change": "Show notification on track change",
"Show year in album grid cards": "Show year in album grid cards",
"Shuffle": "Shuffle",
"Shuffle albums": "Shuffle albums",
"Shuffle tracks": "Shuffle tracks",
"Similar artists": "Similar artists",
"Single": "Single",
"Skip duplicate tracks": "Skip duplicate tracks",
"Soundtrack": "Soundtrack",
"Spoken Word": "Spoken Word",
"Startup page": "Startup page",
"Stopped": "Stopped",
"Support the project": "Support the project",
"Testing connection": "Testing connection",
"Theme": "Theme",
"Title": "Title",
"Top Tracks": "Top Tracks",
"Total time": "Total time",
"Track": "Track",
"track": "track",
"Track count": "Track count",
@@ -141,9 +169,11 @@
"Track number": "Track number",
"Track peak": "Track peak",
"tracks": "tracks",
"UI Scaling": "UI Scaling",
"URL": "URL",
"Use legacy authentication": "Use legacy authentication",
"Username": "Username",
"version": "version",
"wrong URL": "wrong URL",
"wrong username/password": "wrong username/password",
"Year": "Year",
+5 -5
View File
@@ -212,7 +212,7 @@ func NewAlbumPageHeader(page *AlbumPage) *AlbumPageHeader {
SizeName: theme.SizeNameHeadingText,
}
a.releaseTypeLabel = widget.NewRichText(
&widget.TextSegment{Text: "Album", Style: util.BoldRichTextStyle},
&widget.TextSegment{Text: lang.L("Album"), Style: util.BoldRichTextStyle},
&widget.TextSegment{Text: " by", Style: widget.RichTextStyle{Inline: true}},
)
a.artistLabel = widgets.NewMultiHyperlink()
@@ -361,16 +361,16 @@ func formatMiscLabelStr(a *mediaprovider.AlbumWithTracks) string {
var discs string
if len(a.Tracks) > 0 {
if discCount := a.Tracks[len(a.Tracks)-1].DiscNumber; discCount > 1 {
discs = fmt.Sprintf("%d discs · ", discCount)
discs = fmt.Sprintf("%d %s · ", discCount, lang.L("discs"))
}
}
tracks := "tracks"
tracks := lang.L("tracks")
if a.TrackCount == 1 {
tracks = "track"
tracks = lang.L("track")
}
yearStr := strconv.Itoa(a.Year)
if a.ReissueYear > a.Year {
yearStr += fmt.Sprintf(" (reissued %d)", a.ReissueYear)
yearStr += fmt.Sprintf(" (%s %d)", lang.L("reissued"), a.ReissueYear)
}
return fmt.Sprintf("%s · %d %s · %s%s", yearStr, a.TrackCount, tracks, discs, util.SecondsToTimeString(float64(a.Duration)))
}
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"slices"
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/widget"
"github.com/dweymouth/supersonic/backend"
"github.com/dweymouth/supersonic/backend/mediaprovider"
@@ -27,7 +28,7 @@ func NewAlbumsPage(cfg *backend.AlbumsPageConfig, pool *util.WidgetPool, contr *
return NewGridViewPage(adapter, pool, mp, im)
}
func (a *albumsPageAdapter) Title() string { return "Albums" }
func (a *albumsPageAdapter) Title() string { return lang.L("Albums") }
func (a *albumsPageAdapter) Filter() mediaprovider.AlbumFilter {
if a.filter == nil {
+5 -5
View File
@@ -329,10 +329,10 @@ func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader {
}
}
a.favoriteBtn = widgets.NewFavoriteButton(func() { go a.toggleFavorited() })
a.playBtn = widget.NewButtonWithIcon("Play Discography", theme.MediaPlayIcon(), func() {
a.playBtn = widget.NewButtonWithIcon(lang.L("Play Discography"), theme.MediaPlayIcon(), func() {
go a.artistPage.pm.PlayArtistDiscography(a.artistID, false /*shuffle*/)
})
a.playRadioBtn = widget.NewButtonWithIcon("Play Artist Radio", myTheme.ShuffleIcon, func() {
a.playRadioBtn = widget.NewButtonWithIcon(lang.L("Play Artist Radio"), myTheme.ShuffleIcon, func() {
// must not pass playArtistRadio func directly to NewButton
// because the artistPage bound to this header can change when reused
a.artistPage.playArtistRadio()
@@ -342,11 +342,11 @@ func NewArtistPageHeader(page *ArtistPage) *ArtistPageHeader {
a.menuBtn = widget.NewButtonWithIcon("", theme.MoreHorizontalIcon(), nil)
a.menuBtn.OnTapped = func() {
if pop == nil {
shuffleTracks := fyne.NewMenuItem("Shuffle tracks", func() {
shuffleTracks := fyne.NewMenuItem(lang.L("Shuffle tracks"), func() {
go a.artistPage.pm.PlayArtistDiscography(a.artistID, true /*shuffle*/)
})
shuffleTracks.Icon = myTheme.TracksIcon
shuffleAlbums := fyne.NewMenuItem("Shuffle albums", func() {
shuffleAlbums := fyne.NewMenuItem(lang.L("Shuffle albums"), func() {
go a.artistPage.pm.ShuffleArtistAlbums(a.artistID)
})
shuffleAlbums.Icon = myTheme.AlbumIcon
@@ -416,7 +416,7 @@ func (a *ArtistPageHeader) UpdateInfo(info *mediaprovider.ArtistInfo) {
}
if len(a.similarArtists.Objects) == 0 {
a.similarArtists.Add(widget.NewLabel("Similar Artists:"))
a.similarArtists.Add(widget.NewLabel(lang.L("Similar artists") + ":"))
}
for _, obj := range a.similarArtists.Objects {
obj.Hide()
+2 -2
View File
@@ -365,9 +365,9 @@ func (a *FavoritesPage) onShowFavoriteArtists() {
func buildArtistGridViewModel(artists []*mediaprovider.Artist) []widgets.GridViewItemModel {
model := make([]widgets.GridViewItemModel, 0)
for _, ar := range artists {
albums := "albums"
albums := lang.L("albums")
if ar.AlbumCount == 1 {
albums = "album"
albums = lang.L("album")
}
model = append(model, widgets.GridViewItemModel{
ID: ar.ID,
+2 -1
View File
@@ -9,6 +9,7 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
@@ -149,7 +150,7 @@ func (g *GridViewPage[M, F]) createTitleAndSort() {
func (g *GridViewPage[M, F]) createSearchAndFilter() {
g.searcher = widgets.NewSearchEntry()
g.searcher.PlaceHolder = "Search page"
g.searcher.PlaceHolder = lang.L("Search page")
g.searcher.Text = g.searchText
g.searcher.OnSearched = g.OnSearched
g.filterBtn = g.adapter.FilterButton()
+8 -7
View File
@@ -182,7 +182,7 @@ func NewNowPlayingPage(
a.pm.LoadItems(items, backend.InsertNext, false)
}
a.lyricsViewer = widgets.NewLyricsViewer()
a.statusLabel = widget.NewLabel("Stopped")
a.statusLabel = widget.NewLabel(lang.L("Stopped"))
a.Reload()
return a
@@ -538,12 +538,13 @@ func (a *NowPlayingPage) formatStatusLine() {
curPlayer := a.pm.CurrentPlayer()
playerStats := curPlayer.GetStatus()
lastStatus := a.statusLabel.Text
state := "Stopped"
stopped := lang.L("Stopped")
state := stopped
switch playerStats.State {
case player.Paused:
state = "Paused"
state = lang.L("Paused")
case player.Playing:
state = "Playing"
state = lang.L("Playing")
}
dur := 0.0
@@ -552,7 +553,7 @@ func (a *NowPlayingPage) formatStatusLine() {
}
statusSuffix := ""
trackNum := 0
if state != "Stopped" {
if state != stopped {
trackNum = a.pm.NowPlayingIndex() + 1
statusSuffix = fmt.Sprintf(" %s/%s",
util.SecondsToMMSS(playerStats.TimePos),
@@ -562,14 +563,14 @@ func (a *NowPlayingPage) formatStatusLine() {
len(a.queue), statusSuffix)
mediaInfo := ""
if state != "Stopped" {
if state != stopped {
mediaInfo = a.formatMediaInfoStr(curPlayer)
}
if mediaInfo != "" {
mediaInfo = " · " + mediaInfo
}
a.statusLabel.Text = fmt.Sprintf("%s%s | Total time: %s", status, mediaInfo, util.SecondsToTimeString(a.totalTime))
a.statusLabel.Text = fmt.Sprintf("%s%s | %s: %s", status, mediaInfo, lang.L("Total time"), util.SecondsToTimeString(a.totalTime))
if lastStatus != a.statusLabel.Text {
a.statusLabel.Refresh()
}
+5 -4
View File
@@ -9,6 +9,7 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/canvas"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
"fyne.io/fyne/v2/widget"
@@ -37,7 +38,7 @@ func NewAboutDialog(version string) *AboutDialog {
widget.NewSeparator(),
container.NewHBox(
layout.NewSpacer(),
widget.NewButton("Close", func() {
widget.NewButton(lang.L("Close"), func() {
if a.OnDismiss != nil {
a.OnDismiss()
}
@@ -59,7 +60,7 @@ func (a *AboutDialog) buildMainTabContainer(version string) *fyne.Container {
title.Segments[0].(*widget.TextSegment).Style.TextStyle.Bold = true
title.Segments[0].(*widget.TextSegment).Style.SizeName = theme.SizeNameSubHeadingText
title.Segments[0].(*widget.TextSegment).Style.Alignment = fyne.TextAlignCenter
versionLbl := newCenterAlignLabel(fmt.Sprintf("version %s", version))
versionLbl := newCenterAlignLabel(fmt.Sprintf("%s %s", lang.L("version"), version))
copyright := newCenterAlignLabel(res.Copyright)
license := widget.NewRichTextWithText("GNU General Public License version 3 (GPL v3)")
ts := license.Segments[0].(*widget.TextSegment)
@@ -69,9 +70,9 @@ func (a *AboutDialog) buildMainTabContainer(version string) *fyne.Container {
kofiUrl, _ := url.Parse(res.KofiURL)
githubKofi := container.NewCenter(
container.New(layout.NewCustomPaddedHBoxLayout(-10),
widget.NewHyperlink("Github page", ghUrl),
widget.NewHyperlink(lang.L("Github page"), ghUrl),
widget.NewLabel("·"),
widget.NewHyperlink("Support the project", kofiUrl)),
widget.NewHyperlink(lang.L("Support the project"), kofiUrl)),
)
return container.New(&layout.CustomPaddedLayout{TopPadding: 10, BottomPadding: 10},
+3 -1
View File
@@ -1,6 +1,8 @@
package dialogs
import (
"fmt"
"github.com/dweymouth/supersonic/backend"
"fyne.io/fyne/v2"
@@ -68,7 +70,7 @@ func NewAddEditServerDialog(title string, cancelable bool, prefillServer *backen
userField := widget.NewEntryWithData(binding.BindString(&a.Username))
userField.OnSubmitted = func(_ string) { focusHandler(a.passField) }
altHostField := widget.NewEntryWithData(binding.BindString(&a.AltHost))
altHostField.SetPlaceHolder(lang.L("(optional)") + " https://my-external-domain.net/music")
altHostField.SetPlaceHolder(fmt.Sprintf("(%s)", lang.L("optional")) + " https://my-external-domain.net/music")
altHostField.OnSubmitted = func(_ string) { focusHandler(userField) }
hostField := widget.NewEntryWithData(binding.BindString(&a.Host))
hostField.SetPlaceHolder("http://localhost:4533")
+4 -3
View File
@@ -8,6 +8,7 @@ import (
"fyne.io/fyne/v2"
"fyne.io/fyne/v2/container"
"fyne.io/fyne/v2/lang"
"fyne.io/fyne/v2/layout"
"fyne.io/fyne/v2/theme"
@@ -270,11 +271,11 @@ func (s *searchResult) Update(result *mediaprovider.SearchResult) {
s.imageLoader.Load(result.CoverID)
s.title.SetText(result.Name)
maybePluralize := func(s string, size int) string {
maybePluralize := func(key string, size int) string {
if size != 1 {
return s + "s"
return lang.L(key + "s")
}
return s
return lang.L(key)
}
var secondaryText string
switch result.Type {
+18 -16
View File
@@ -160,16 +160,18 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container.
systemTrayEnable.Checked = s.config.Application.EnableSystemTray
// save play queue settings
saveToServer := widget.NewRadioGroup([]string{"Locally", "To server"}, func(choice string) {
s.config.Application.SaveQueueToServer = choice == "To server"
locally := lang.L("Locally")
toServer := lang.L("To server")
saveToServer := widget.NewRadioGroup([]string{locally, toServer}, func(choice string) {
s.config.Application.SaveQueueToServer = choice == toServer
})
saveToServer.Horizontal = true
if !s.config.Application.SavePlayQueue {
saveToServer.Disable()
}
saveToServer.Selected = "Locally"
saveToServer.Selected = locally
if s.config.Application.SaveQueueToServer {
saveToServer.Selected = "To server"
saveToServer.Selected = toServer
}
saveQueue := widget.NewCheck(lang.L("Save play queue on exit"), func(save bool) {
s.config.Application.SavePlayQueue = save
@@ -233,7 +235,7 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container.
if lastScrobbleText == "" {
lastScrobbleText = "4" // default scrobble minutes
}
durationEnabled := widget.NewCheck("or when", func(checked bool) {
durationEnabled := widget.NewCheck(lang.L("or when"), func(checked bool) {
if !checked {
s.config.Scrobbling.ThresholdTimeSeconds = -1
lastScrobbleText = durationEntry.Text
@@ -292,14 +294,14 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container.
widget.NewRichText(&widget.TextSegment{Text: "Scrobbling", Style: util.BoldRichTextStyle}),
scrobbleEnabled,
container.NewHBox(
widget.NewLabel("Scrobble when"),
widget.NewLabel(lang.L("Scrobble when")),
percentEntry,
widget.NewLabel("percent of track is played"),
widget.NewLabel(lang.L("percent of track is played")),
),
container.NewHBox(
durationEnabled,
durationEntry,
widget.NewLabel("minutes of track have been played"),
widget.NewLabel(lang.L("minutes of track have been played")),
),
))
}
@@ -324,7 +326,7 @@ func (s *SettingsDialog) createPlaybackTab(isLocalPlayer, isReplayGainPlayer boo
}
}
replayGainSelect := widget.NewSelect([]string{"None", "Album", "Track", "Auto"}, nil)
replayGainSelect := widget.NewSelect([]string{lang.L("None"), lang.L("Album"), lang.L("Track"), lang.L("Auto")}, nil)
replayGainSelect.OnChanged = func(_ string) {
switch replayGainSelect.SelectedIndex() {
case 0:
@@ -377,7 +379,7 @@ func (s *SettingsDialog) createPlaybackTab(isLocalPlayer, isReplayGainPlayer boo
})
preventClipping.Checked = s.config.ReplayGain.PreventClipping
audioExclusive := widget.NewCheck("Audio exclusive mode", func(checked bool) {
audioExclusive := widget.NewCheck(lang.L("Exclusive mode"), func(checked bool) {
s.config.LocalPlayback.AudioExclusive = checked
s.onAudioExclusiveSettingsChanged()
})
@@ -393,20 +395,20 @@ func (s *SettingsDialog) createPlaybackTab(isLocalPlayer, isReplayGainPlayer boo
preampGain.Disable()
}
return container.NewTabItem("Playback", container.NewVBox(
return container.NewTabItem(lang.L("Playback"), container.NewVBox(
disableTranscode,
container.New(&layout.CustomPaddedLayout{TopPadding: 5},
container.New(layout.NewFormLayout(),
widget.NewLabel("Audio device"), container.NewBorder(nil, nil, nil, util.NewHSpace(70), deviceSelect),
widget.NewLabel(lang.L("Audio device")), container.NewBorder(nil, nil, nil, util.NewHSpace(70), deviceSelect),
layout.NewSpacer(), audioExclusive,
)),
s.newSectionSeparator(),
widget.NewRichText(&widget.TextSegment{Text: "ReplayGain", Style: util.BoldRichTextStyle}),
container.New(layout.NewFormLayout(),
widget.NewLabel("ReplayGain mode"), container.NewGridWithColumns(2, replayGainSelect),
widget.NewLabel("ReplayGain preamp"), container.NewHBox(preampGain, widget.NewLabel("dB")),
widget.NewLabel("Prevent clipping"), preventClipping,
widget.NewLabel(lang.L("ReplayGain mode")), container.NewGridWithColumns(2, replayGainSelect),
widget.NewLabel(lang.L("ReplayGain preamp")), container.NewHBox(preampGain, widget.NewLabel("dB")),
widget.NewLabel(lang.L("Prevent clipping")), preventClipping,
),
))
}
@@ -487,7 +489,7 @@ func (s *SettingsDialog) createExperimentalTab(window fyne.Window) *container.Ta
return container.NewTabItem("Experimental", container.NewVBox(
warningLabel,
s.newSectionSeparator(),
widget.NewRichText(&widget.TextSegment{Text: "UI Scaling", Style: util.BoldRichTextStyle}),
widget.NewRichText(&widget.TextSegment{Text: lang.L("UI Scaling"), Style: util.BoldRichTextStyle}),
uiScaleRadio,
s.newSectionSeparator(),
widget.NewRichText(&widget.TextSegment{Text: "Application Font", Style: util.BoldRichTextStyle}),
+2 -2
View File
@@ -63,9 +63,9 @@ var (
rating := lang.L("Rating")
plays := lang.L("Plays")
comment := lang.L("Comment")
bitrate := lang.L("Bitrate")
bitrate := lang.L("Bit rate")
size := lang.L("Size")
filepath := lang.L("File Path")
filepath := lang.L("File path")
CompactTracklistRowColumns = []TracklistColumn{
{Name: ColumnNum, Col: ListColumn{Text: "#", Alignment: fyne.TextAlignTrailing, CanToggleVisible: false}},