From dd3f5874c437061a51c2bbd847d916713f115e05 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Tue, 17 Dec 2024 18:07:28 -0800 Subject: [PATCH 1/3] add ability to configure language in config file --- backend/config.go | 6 ++++-- main.go | 22 +++++++++++++++++++++- res/translations.go | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/backend/config.go b/backend/config.go index 4399e222..26263eda 100644 --- a/backend/config.go +++ b/backend/config.go @@ -48,7 +48,8 @@ type AppConfig struct { ShowTrackChangeNotification bool EnableLrcLib bool SkipSSLVerify bool - EnqueueBatchSize int + EnqueueBatchSize int + Language string // Experimental - may be removed in future FontNormalTTF string @@ -174,7 +175,8 @@ func DefaultConfig(appVersionTag string) *Config { ShowTrackChangeNotification: false, EnableLrcLib: true, SkipSSLVerify: false, - EnqueueBatchSize: 100, + EnqueueBatchSize: 100, + Language: "auto", }, AlbumPage: AlbumPageConfig{ TracklistColumns: []string{"Artist", "Time", "Plays", "Favorite", "Rating"}, diff --git a/main.go b/main.go index d9eb4d4c..7da1c446 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "log" "os" "runtime" + "slices" "sync" "time" @@ -46,7 +47,26 @@ func main() { os.Setenv("FYNE_SCALE", "1.1") } - lang.AddTranslationsFS(res.Translations, "translations") + // load configured app language, or all otherwise + lIdx := slices.IndexFunc(res.TranslationsInfo, func(t res.TranslationInfo) bool { + return t.Name == myApp.Config.Application.Language + }) + success := false + if lIdx > 0 { + tr := res.TranslationsInfo[lIdx] + content, err := res.Translations.ReadFile("translations/" + tr.TranslationFileName) + if err == nil { + // "trick" Fyne into loading translations for configured language + // by pretending it's the translation for the system locale + name := lang.SystemLocale().LanguageString() + lang.AddTranslations(fyne.NewStaticResource(name+".json", content)) + success = true + } + } + if !success { + lang.AddTranslationsFS(res.Translations, "translations") + } + fyneApp := app.New() fyneApp.SetIcon(res.ResAppicon256Png) diff --git a/res/translations.go b/res/translations.go index fd6a93fe..a2398e6c 100644 --- a/res/translations.go +++ b/res/translations.go @@ -4,3 +4,23 @@ import "embed" //go:embed translations var Translations embed.FS + +type TranslationInfo struct { + Name string + DisplayName string + TranslationFileName string +} + +var TranslationsInfo = []TranslationInfo{ + {Name: "de", DisplayName: "Deutsch", TranslationFileName: "de.json"}, + {Name: "en", DisplayName: "English", TranslationFileName: "en.json"}, + {Name: "es", DisplayName: "Español", TranslationFileName: "es.json"}, + {Name: "fr", DisplayName: "François", TranslationFileName: "fr.json"}, + {Name: "it", DisplayName: "Italiano", TranslationFileName: "it.json"}, + {Name: "ja", DisplayName: "日本語", TranslationFileName: "de.json"}, + {Name: "pl", DisplayName: "Polski", TranslationFileName: "pl.json"}, + {Name: "pt_BR", DisplayName: "Português (BR)", TranslationFileName: "pt_BR.json"}, + {Name: "ro", DisplayName: "Română", TranslationFileName: "ro"}, + {Name: "zhHans", DisplayName: "中文", TranslationFileName: "zhHans.json"}, + {Name: "zhHant", DisplayName: "中文 (trad.)", TranslationFileName: "zhHant.json"}, +} From 34c04ba9d99625e0e44c649c8379f6b3995237f4 Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Tue, 17 Dec 2024 19:15:16 -0800 Subject: [PATCH 2/3] Expose language setting in settings dialog, fix some bugs --- main.go | 8 ++++++-- res/translations.go | 4 ++-- ui/dialogs/settingsdialog.go | 26 +++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 7da1c446..d41eedfc 100644 --- a/main.go +++ b/main.go @@ -52,7 +52,7 @@ func main() { return t.Name == myApp.Config.Application.Language }) success := false - if lIdx > 0 { + if lIdx >= 0 { tr := res.TranslationsInfo[lIdx] content, err := res.Translations.ReadFile("translations/" + tr.TranslationFileName) if err == nil { @@ -61,10 +61,14 @@ func main() { name := lang.SystemLocale().LanguageString() lang.AddTranslations(fyne.NewStaticResource(name+".json", content)) success = true + } else { + log.Printf("Error loading translation file %s: %s\n", tr.TranslationFileName, err.Error()) } } if !success { - lang.AddTranslationsFS(res.Translations, "translations") + if err := lang.AddTranslationsFS(res.Translations, "translations"); err != nil { + log.Printf("Error loading translations: %s", err.Error()) + } } fyneApp := app.New() diff --git a/res/translations.go b/res/translations.go index a2398e6c..3f9e87d8 100644 --- a/res/translations.go +++ b/res/translations.go @@ -17,10 +17,10 @@ var TranslationsInfo = []TranslationInfo{ {Name: "es", DisplayName: "Español", TranslationFileName: "es.json"}, {Name: "fr", DisplayName: "François", TranslationFileName: "fr.json"}, {Name: "it", DisplayName: "Italiano", TranslationFileName: "it.json"}, - {Name: "ja", DisplayName: "日本語", TranslationFileName: "de.json"}, + {Name: "ja", DisplayName: "日本語", TranslationFileName: "ja.json"}, {Name: "pl", DisplayName: "Polski", TranslationFileName: "pl.json"}, {Name: "pt_BR", DisplayName: "Português (BR)", TranslationFileName: "pt_BR.json"}, - {Name: "ro", DisplayName: "Română", TranslationFileName: "ro"}, + {Name: "ro", DisplayName: "Română", TranslationFileName: "ro.json"}, {Name: "zhHans", DisplayName: "中文", TranslationFileName: "zhHans.json"}, {Name: "zhHant", DisplayName: "中文 (trad.)", TranslationFileName: "zhHant.json"}, } diff --git a/ui/dialogs/settingsdialog.go b/ui/dialogs/settingsdialog.go index 07e7b85e..ee97f97b 100644 --- a/ui/dialogs/settingsdialog.go +++ b/ui/dialogs/settingsdialog.go @@ -12,6 +12,7 @@ import ( "github.com/dweymouth/supersonic/backend" "github.com/dweymouth/supersonic/backend/player/mpv" + "github.com/dweymouth/supersonic/res" myTheme "github.com/dweymouth/supersonic/ui/theme" "github.com/dweymouth/supersonic/ui/util" "github.com/dweymouth/supersonic/ui/widgets" @@ -146,6 +147,28 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container. if startupPage.Selected == "" { startupPage.SetSelectedIndex(0) } + + languageList := make([]string, len(res.TranslationsInfo)+1) + languageList[0] = lang.L("Auto") + var langSelIndex int + for i, tr := range res.TranslationsInfo { + languageList[i+1] = tr.DisplayName + if tr.Name == s.config.Application.Language { + langSelIndex = i + 1 + } + } + + languageSelect := widget.NewSelect(languageList, nil) + languageSelect.SetSelectedIndex(langSelIndex) + languageSelect.OnChanged = func(_ string) { + lang := "auto" + if i := languageSelect.SelectedIndex(); i > 0 { + lang = res.TranslationsInfo[i-1].Name + } + s.config.Application.Language = lang + s.setRestartRequired() + } + closeToTray := widget.NewCheckWithData(lang.L("Close to system tray"), binding.BindBool(&s.config.Application.CloseToSystemTray)) if !s.config.Application.EnableSystemTray { @@ -285,8 +308,9 @@ func (s *SettingsDialog) createGeneralTab(canSaveQueueToServer bool) *container. scrobbleEnabled.Checked = s.config.Scrobbling.Enabled return container.NewTabItem(lang.L("General"), container.NewVBox( + container.NewHBox(widget.NewLabel(lang.L("Language")), languageSelect), container.NewBorder(nil, nil, widget.NewLabel(lang.L("Theme")), /*left*/ - container.NewHBox(widget.NewLabel("Mode"), themeModeSelect, util.NewHSpace(5)), // right + container.NewHBox(widget.NewLabel(lang.L("Mode")), themeModeSelect, util.NewHSpace(5)), // right themeFileSelect, // center ), container.NewHBox( From e9863fa3f5cd623148c0978af665d07f4ebfbcfb Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Tue, 17 Dec 2024 19:27:48 -0800 Subject: [PATCH 3/3] add translations of "Language" --- res/translations/en.json | 1 + res/translations/es.json | 1 + res/translations/fr.json | 1 + res/translations/it.json | 1 + res/translations/ja.json | 1 + res/translations/pl.json | 1 + res/translations/pt_BR.json | 1 + res/translations/ro.json | 1 + res/translations/zh.json | 1 + res/translations/zhHans.json | 1 + res/translations/zhHant.json | 1 + 11 files changed, 11 insertions(+) diff --git a/res/translations/en.json b/res/translations/en.json index e5d7f3bd..3278e9bf 100644 --- a/res/translations/en.json +++ b/res/translations/en.json @@ -92,6 +92,7 @@ "Interview": "Interview", "Is favorite": "Is favorite", "Is not favorite": "Is not favorite", + "Language": "Language", "Last played": "Last played", "Live": "Live", "Locally": "Locally", diff --git a/res/translations/es.json b/res/translations/es.json index 1dd920b2..c90451a6 100644 --- a/res/translations/es.json +++ b/res/translations/es.json @@ -92,6 +92,7 @@ "Interview": "Entrevista", "Is favorite": "Es favorito", "Is not favorite": "No es favorito", + "Language": "Idioma", "Last played": "Última reproducción", "Live": "En vivo", "Locally": "Localmente", diff --git a/res/translations/fr.json b/res/translations/fr.json index 03bb1f9c..6da71faf 100644 --- a/res/translations/fr.json +++ b/res/translations/fr.json @@ -92,6 +92,7 @@ "Interview": "Interview", "Is favorite": "Favoris", "Is not favorite": "Non favoris", + "Language": "Langue", "Last played": "Dernière lecture", "Live": "Live", "Locally": "En local", diff --git a/res/translations/it.json b/res/translations/it.json index 06533b34..3a8beb8d 100644 --- a/res/translations/it.json +++ b/res/translations/it.json @@ -92,6 +92,7 @@ "Interview": "Interview", "Is favorite": "Nei preferiti", "Is not favorite": "Non nei preferiti", + "Language": "Lingua", "Last played": "Ultimo ascolto", "Live": "Live", "Locally": "Localmente", diff --git a/res/translations/ja.json b/res/translations/ja.json index a37e40bc..2898c57a 100644 --- a/res/translations/ja.json +++ b/res/translations/ja.json @@ -92,6 +92,7 @@ "Interview": "インタビュー", "Is favorite": "お気に入り", "Is not favorite": "お気に入りでない", + "Language": "言語", "Last played": "最後の再生", "Live": "ライブ", "Locally": "ローカル", diff --git a/res/translations/pl.json b/res/translations/pl.json index b879915b..a920e603 100644 --- a/res/translations/pl.json +++ b/res/translations/pl.json @@ -92,6 +92,7 @@ "Interview": "Wywiad", "Is favorite": "Jest ulubione", "Is not favorite": "Nie jest ulubione", + "Language": "Język", "Last played": "Ostatnio odtwarzane", "Live": "Live", "Locally": "Lokalnie", diff --git a/res/translations/pt_BR.json b/res/translations/pt_BR.json index 02dfac9b..6555288d 100644 --- a/res/translations/pt_BR.json +++ b/res/translations/pt_BR.json @@ -92,6 +92,7 @@ "Interview": "Entrevista", "Is favorite": "É favorito", "Is not favorite": "Não é favorito", + "Language": "Linguagem", "Last played": "Tocados recentemente", "Live": "Ao Vivo", "Locally": "Localmente", diff --git a/res/translations/ro.json b/res/translations/ro.json index 15c4cc2a..463acaa1 100644 --- a/res/translations/ro.json +++ b/res/translations/ro.json @@ -88,6 +88,7 @@ "Interview": "Interviu", "Is favorite": "Este favorit", "Is not favorite": "Nu este favorit", + "Language": "Limbă", "Last played": "Ultimul redat", "Live": "Live", "Locally": "Local", diff --git a/res/translations/zh.json b/res/translations/zh.json index b7ef9b1d..a71f69b3 100644 --- a/res/translations/zh.json +++ b/res/translations/zh.json @@ -88,6 +88,7 @@ "Interview": "采访", "Is favorite": "已收藏", "Is not favorite": "未收藏", + "Language": "语言", "Last played": "上次播放", "Live": "现场", "To server": "到服务器", diff --git a/res/translations/zhHans.json b/res/translations/zhHans.json index a6f20eb9..cb3e9b02 100644 --- a/res/translations/zhHans.json +++ b/res/translations/zhHans.json @@ -88,6 +88,7 @@ "Interview": "采访", "Is favorite": "已收藏", "Is not favorite": "未收藏", + "Language": "语言", "Last played": "上次播放", "Live": "现场", "Locally": "到本地", diff --git a/res/translations/zhHant.json b/res/translations/zhHant.json index a3a678e7..028cbffe 100644 --- a/res/translations/zhHant.json +++ b/res/translations/zhHant.json @@ -88,6 +88,7 @@ "Interview": "訪談", "Is favorite": "已收藏", "Is not favorite": "未收藏", + "Language": "語言", "Last played": "上次播放", "Live": "現場", "Locally": "到本地",