From 584c504e25272c34de70aaeadf15ec7471d969de Mon Sep 17 00:00:00 2001 From: 0ko <0ko@noreply.codeberg.org> Date: Sun, 9 Mar 2025 15:12:30 +0000 Subject: [PATCH] feat(ui): localize theme names (#7168) Allow translating theme names. Not even for i18n reasons but because this way the menu is clearer and cleaner. The number of translated entries is kept minimal for now. It is easy to pollute locales with these names otherwise. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7168 Reviewed-by: Gusted --- .deadcode-out | 1 + modules/translation/mock.go | 4 ++++ modules/translation/translation.go | 2 ++ options/locale_next/locale_en-US.json | 5 ++++- routers/web/user/setting/profile.go | 7 +++++++ templates/user/settings/appearance.tmpl | 8 ++++---- tests/integration/appearance_settings_test.go | 17 +++++++++++++---- 7 files changed, 35 insertions(+), 9 deletions(-) diff --git a/.deadcode-out b/.deadcode-out index b17d738bd6..338d22e258 100644 --- a/.deadcode-out +++ b/.deadcode-out @@ -189,6 +189,7 @@ code.gitea.io/gitea/modules/translation MockLocale.TrN MockLocale.TrPluralString MockLocale.TrSize + MockLocale.HasKey MockLocale.PrettyNumber code.gitea.io/gitea/modules/util diff --git a/modules/translation/mock.go b/modules/translation/mock.go index 4d9acce26f..72a15b7438 100644 --- a/modules/translation/mock.go +++ b/modules/translation/mock.go @@ -39,6 +39,10 @@ func (l MockLocale) TrSize(s int64) ReadableSize { return ReadableSize{fmt.Sprint(s), ""} } +func (l MockLocale) HasKey(key string) bool { + return true +} + func (l MockLocale) PrettyNumber(v any) string { return fmt.Sprint(v) } diff --git a/modules/translation/translation.go b/modules/translation/translation.go index 7d1c627c84..7be77536ca 100644 --- a/modules/translation/translation.go +++ b/modules/translation/translation.go @@ -39,6 +39,8 @@ type Locale interface { TrSize(size int64) ReadableSize + HasKey(trKey string) bool + PrettyNumber(v any) string } diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index adf0938d40..0d47b351f5 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -13,5 +13,8 @@ "other": "wants to merge %[1]d commits from %[2]s into %[3]s" }, "search.milestone_kind": "Search milestones…", - "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini." + "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini.", + "themes.names.forgejo-auto": "Forgejo (follow system theme)", + "themes.names.forgejo-light": "Forgejo light", + "themes.names.forgejo-dark": "Forgejo dark" } diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index eb32774971..271621872f 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -330,6 +330,13 @@ func Appearance(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings.appearance") ctx.Data["PageIsSettingsAppearance"] = true ctx.Data["AllThemes"] = setting.UI.Themes + ctx.Data["ThemeName"] = func(themeName string) string { + fullThemeName := "themes.names." + themeName + if ctx.Locale.HasKey(fullThemeName) { + return ctx.Locale.TrString(fullThemeName) + } + return themeName + } var hiddenCommentTypes *big.Int val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) diff --git a/templates/user/settings/appearance.tmpl b/templates/user/settings/appearance.tmpl index 2aaf24adca..df4d6f3999 100644 --- a/templates/user/settings/appearance.tmpl +++ b/templates/user/settings/appearance.tmpl @@ -19,15 +19,15 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}
- {{range $i,$a := .AllThemes}} - {{if eq $.SignedUser.Theme $a}}{{$a}}{{end}} - {{end}} + {{- range $i,$a := .AllThemes -}} + {{if eq $.SignedUser.Theme $a}}{{call $.ThemeName $a}}{{end}} + {{- end -}}
diff --git a/tests/integration/appearance_settings_test.go b/tests/integration/appearance_settings_test.go index b19771a39e..ad87887331 100644 --- a/tests/integration/appearance_settings_test.go +++ b/tests/integration/appearance_settings_test.go @@ -5,6 +5,7 @@ package integration import ( "net/http" + "strings" "testing" "code.gitea.io/gitea/tests" @@ -16,15 +17,21 @@ func TestThemeChange(t *testing.T) { defer tests.PrepareTestEnv(t)() user := loginUser(t, "user2") - testSelectedTheme(t, user, "forgejo-auto") + // Verify default theme + testSelectedTheme(t, user, "forgejo-auto", "Forgejo (follow system theme)") + // Change theme to forgejo-dark and verify it works fine testChangeTheme(t, user, "forgejo-dark") - testSelectedTheme(t, user, "forgejo-dark") + testSelectedTheme(t, user, "forgejo-dark", "Forgejo dark") + + // Change theme to gitea-dark and also verify that it's name is not translated + testChangeTheme(t, user, "gitea-dark") + testSelectedTheme(t, user, "gitea-dark", "gitea-dark") } // testSelectedTheme checks that the expected theme is used in html[data-theme] // and is default on appearance page -func testSelectedTheme(t *testing.T, session *TestSession, expectedTheme string) { +func testSelectedTheme(t *testing.T, session *TestSession, expectedTheme, expectedName string) { t.Helper() response := session.MakeRequest(t, NewRequest(t, "GET", "/user/settings/appearance"), http.StatusOK) page := NewHTMLParser(t, response.Body) @@ -33,9 +40,11 @@ func testSelectedTheme(t *testing.T, session *TestSession, expectedTheme string) assert.True(t, dataThemeExists) assert.EqualValues(t, expectedTheme, dataTheme) - selectorTheme, selectorThemeExists := page.Find("form[action='/user/settings/appearance/theme'] input[name='theme']").Attr("value") + selectedTheme := page.Find("form[action='/user/settings/appearance/theme'] .menu .item.selected") + selectorTheme, selectorThemeExists := selectedTheme.Attr("data-value") assert.True(t, selectorThemeExists) assert.EqualValues(t, expectedTheme, selectorTheme) + assert.EqualValues(t, expectedName, strings.TrimSpace(selectedTheme.Text())) } // testSelectedTheme changes user's theme