diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index d825e47a76..451742ac06 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1,10 +1,10 @@ -; This file lists the default values used by Gitea +; This file lists the default values used by Forgejo ;; Copy required sections to your own app.ini (default is custom/conf/app.ini) ;; and modify as needed. ;; Do not copy the whole file as-is, as it contains some invalid sections for illustrative purposes. ;; If you don't know what a setting is you should not set it. ;; -;; see https://docs.gitea.com/administration/config-cheat-sheet for additional documentation. +;; see https://forgejo.org/docs/next/admin/config-cheat-sheet for additional documentation. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -41,7 +41,14 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; App name that shows in every page title -APP_NAME = ; Gitea: Git with a cup of tea +APP_NAME = ; Forgejo: Beyond coding. We Forge. +;; +;; APP_SLOGAN shows a slogan near the App name in every page title. +;APP_SLOGAN = +;; +;; APP_DISPLAY_NAME_FORMAT defines how the AppDisplayName should be presented +;; It is used only if APP_SLOGAN is set. +;APP_DISPLAY_NAME_FORMAT = {APP_NAME}: {APP_SLOGAN} ;; ;; RUN_USER will automatically detect the current user - but you can set it here change it if you run locally RUN_USER = ; git diff --git a/modules/setting/server.go b/modules/setting/server.go index c20dd1949d..5cc33f6fc4 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -45,6 +45,14 @@ var ( // AppName is the Application name, used in the page title. // It maps to ini:"APP_NAME" AppName string + // AppSlogan is the Application slogan. + // It maps to ini:"APP_SLOGAN" + AppSlogan string + // AppDisplayNameFormat defines how the AppDisplayName should be presented + // It maps to ini:"APP_DISPLAY_NAME_FORMAT" + AppDisplayNameFormat string + // AppDisplayName is the display name for the application, defined following AppDisplayNameFormat + AppDisplayName string // AppURL is the Application ROOT_URL. It always has a '/' suffix // It maps to ini:"ROOT_URL" AppURL string @@ -164,10 +172,21 @@ func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string { return strings.TrimSuffix(staticURLPrefix, "/") } +func generateDisplayName() string { + appDisplayName := AppName + if AppSlogan != "" { + appDisplayName = strings.Replace(AppDisplayNameFormat, "{APP_NAME}", AppName, 1) + appDisplayName = strings.Replace(appDisplayName, "{APP_SLOGAN}", AppSlogan, 1) + } + return appDisplayName +} + func loadServerFrom(rootCfg ConfigProvider) { sec := rootCfg.Section("server") AppName = rootCfg.Section("").Key("APP_NAME").MustString("Forgejo: Beyond coding. We Forge.") - + AppSlogan = rootCfg.Section("").Key("APP_SLOGAN").MustString("") + AppDisplayNameFormat = rootCfg.Section("").Key("APP_DISPLAY_NAME_FORMAT").MustString("{APP_NAME}: {APP_SLOGAN}") + AppDisplayName = generateDisplayName() Domain = sec.Key("DOMAIN").MustString("localhost") HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") HTTPPort = sec.Key("HTTP_PORT").MustString("3000") diff --git a/modules/setting/server_test.go b/modules/setting/server_test.go new file mode 100644 index 0000000000..8db8168854 --- /dev/null +++ b/modules/setting/server_test.go @@ -0,0 +1,36 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package setting + +import ( + "testing" + + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestDisplayNameDefault(t *testing.T) { + defer test.MockVariableValue(&AppName, "Forgejo")() + defer test.MockVariableValue(&AppSlogan, "Beyond coding. We Forge.")() + defer test.MockVariableValue(&AppDisplayNameFormat, "{APP_NAME}: {APP_SLOGAN}")() + displayName := generateDisplayName() + assert.Equal(t, "Forgejo: Beyond coding. We Forge.", displayName) +} + +func TestDisplayNameEmptySlogan(t *testing.T) { + defer test.MockVariableValue(&AppName, "Forgejo")() + defer test.MockVariableValue(&AppSlogan, "")() + defer test.MockVariableValue(&AppDisplayNameFormat, "{APP_NAME}: {APP_SLOGAN}")() + displayName := generateDisplayName() + assert.Equal(t, "Forgejo", displayName) +} + +func TestDisplayNameCustomFormat(t *testing.T) { + defer test.MockVariableValue(&AppName, "Forgejo")() + defer test.MockVariableValue(&AppSlogan, "Beyond coding. We Forge.")() + defer test.MockVariableValue(&AppDisplayNameFormat, "{APP_NAME} - {APP_SLOGAN}")() + displayName := generateDisplayName() + assert.Equal(t, "Forgejo - Beyond coding. We Forge.", displayName) +} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 4dc1f1938c..f1ae1c8bb1 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -79,6 +79,12 @@ func NewFuncMap() template.FuncMap { "AppName": func() string { return setting.AppName }, + "AppSlogan": func() string { + return setting.AppSlogan + }, + "AppDisplayName": func() string { + return setting.AppDisplayName + }, "AppSubUrl": func() string { return setting.AppSubURL }, diff --git a/modules/templates/mailer.go b/modules/templates/mailer.go index 7c97e1ea89..ee79755dbb 100644 --- a/modules/templates/mailer.go +++ b/modules/templates/mailer.go @@ -28,6 +28,12 @@ func mailSubjectTextFuncMap() texttmpl.FuncMap { "AppName": func() string { return setting.AppName }, + "AppSlogan": func() string { + return setting.AppSlogan + }, + "AppDisplayName": func() string { + return setting.AppDisplayName + }, "AppDomain": func() string { // documented in mail-templates.md return setting.Domain }, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 13adb33a55..39f7886c54 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -267,6 +267,8 @@ err_admin_name_is_invalid = Administrator Username is invalid general_title = General settings app_name = Instance title app_name_helper = You can enter your company name here. +app_slogan = Instance slogan +app_slogan_helper = Enter your instance slogan here. Leave empty to disable. repo_path = Repository root path repo_path_helper = Remote Git repositories will be saved to this directory. lfs_path = Git LFS root path @@ -3207,6 +3209,7 @@ auths.invalid_openIdConnectAutoDiscoveryURL = Invalid Auto Discovery URL (this m config.server_config = Server configuration config.app_name = Instance title +config.app_slogan = Instance slogan config.app_ver = Forgejo version config.app_url = Base URL config.custom_conf = Configuration file path diff --git a/release-notes/8.0.0/3616.md b/release-notes/8.0.0/3616.md new file mode 100644 index 0000000000..fdeb470cf0 --- /dev/null +++ b/release-notes/8.0.0/3616.md @@ -0,0 +1,10 @@ +There are a couple of new configs to define the name of the instance. +The more important is `APP_SLOGAN`. It permits to configure a slogan for the site and it is optional. +The other is `APP_DISPLAY_NAME_FORMAT` and permits to customize the aspect of the full display name for the instance used in some parts of the UI as: + +- Title page. +- Homepage head title. +- Open Graph site and title meta tags. + +Its default value is `APP_NAME: APP_SLOGAN`. +The config `APP_DISPLAY_NAME_FORMAT` is used only if `APP_SLOGAN` is set otherwise the full display name shows only `APP_NAME` value. diff --git a/routers/install/install.go b/routers/install/install.go index 8f4fafa6f5..dfd8047d04 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -115,7 +115,8 @@ func Install(ctx *context.Context) { ctx.Data["CurDbType"] = curDBType // Application general settings - form.AppName = setting.AppName + form.AppName = "Forgejo" + form.AppSlogan = "Beyond coding. We Forge." form.RepoRootPath = setting.RepoRootPath form.LFSRootPath = setting.LFS.Storage.Path @@ -383,6 +384,7 @@ func SubmitInstall(ctx *context.Context) { } cfg.Section("").Key("APP_NAME").SetValue(form.AppName) + cfg.Section("").Key("APP_SLOGAN").SetValue(form.AppSlogan) cfg.Section("").Key("RUN_USER").SetValue(form.RunUser) cfg.Section("").Key("WORK_PATH").SetValue(setting.AppWorkPath) cfg.Section("").Key("RUN_MODE").SetValue("prod") diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 0b7bea4638..cc93b27e2a 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -31,6 +31,7 @@ type InstallForm struct { DbSchema string AppName string `binding:"Required" locale:"install.app_name"` + AppSlogan string RepoRootPath string `binding:"Required"` LFSRootPath string RunUser string `binding:"Required"` diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 1e94935a16..d4e5b326fd 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -7,6 +7,8 @@
{{ctx.Locale.Tr "admin.config.app_name"}}
{{AppName}}
+
{{ctx.Locale.Tr "admin.config.app_slogan"}}
+
{{AppSlogan}}
{{ctx.Locale.Tr "admin.config.app_ver"}}
{{AppVer}}{{.AppBuiltWith}}
{{ctx.Locale.Tr "admin.config.custom_conf"}}
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index c0caf34d53..7753f49243 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -3,7 +3,7 @@ {{/* Display `- .Repository.FullName` only if `.Title` does not already start with that. */}} - {{if .Title}}{{.Title}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppName}} + {{if .Title}}{{.Title}} - {{end}}{{if and (.Repository.Name) (not (StringUtils.HasPrefix .Title .Repository.FullName))}}{{.Repository.FullName}} - {{end}}{{AppDisplayName}} {{if .ManifestData}}{{end}} diff --git a/templates/base/head_opengraph.tmpl b/templates/base/head_opengraph.tmpl index f1f38999d2..c02adabaab 100644 --- a/templates/base/head_opengraph.tmpl +++ b/templates/base/head_opengraph.tmpl @@ -38,10 +38,10 @@ {{end}} {{else}} - + {{end}} - + diff --git a/templates/home.tmpl b/templates/home.tmpl index e6fd4ef020..23b1feae21 100644 --- a/templates/home.tmpl +++ b/templates/home.tmpl @@ -5,7 +5,7 @@

- {{AppName}} + {{AppDisplayName}}

{{ctx.Locale.Tr "startpage.app_desc"}}

diff --git a/templates/install.tmpl b/templates/install.tmpl index f027b47922..29eb44526a 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -107,6 +107,11 @@ {{ctx.Locale.Tr "install.app_name_helper"}} +
+ + + {{ctx.Locale.Tr "install.app_slogan_helper"}} +
diff --git a/templates/status/500.tmpl b/templates/status/500.tmpl index 8e250abe27..e5fdaec0cf 100644 --- a/templates/status/500.tmpl +++ b/templates/status/500.tmpl @@ -9,7 +9,7 @@ - {{ctx.Locale.Tr "error.server_internal"}} - {{AppName}} + {{ctx.Locale.Tr "error.server_internal"}} - {{AppDisplayName}} {{template "base/head_style" .}} diff --git a/tests/integration/view_test.go b/tests/integration/view_test.go index e77cc382e9..d7225101d7 100644 --- a/tests/integration/view_test.go +++ b/tests/integration/view_test.go @@ -185,3 +185,28 @@ func TestInHistoryButton(t *testing.T) { }) }) } + +func TestTitleDisplayName(t *testing.T) { + session := emptyTestSession(t) + title := GetHTMLTitle(t, session, "/") + assert.Equal(t, "Gitea: Git with a cup of tea", title) +} + +func TestHomeDisplayName(t *testing.T) { + session := emptyTestSession(t) + req := NewRequest(t, "GET", "/") + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + assert.Equal(t, "Gitea: Git with a cup of tea", strings.TrimSpace(htmlDoc.Find("h1.title").Text())) +} + +func TestOpenGraphDisplayName(t *testing.T) { + session := emptyTestSession(t) + req := NewRequest(t, "GET", "/") + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + ogTitle, _ := htmlDoc.Find("meta[property='og:title']").Attr("content") + assert.Equal(t, "Gitea: Git with a cup of tea", ogTitle) + ogSiteName, _ := htmlDoc.Find("meta[property='og:site_name']").Attr("content") + assert.Equal(t, "Gitea: Git with a cup of tea", ogSiteName) +} diff --git a/tests/mysql.ini.tmpl b/tests/mysql.ini.tmpl index ab2e91ebdb..1bfc797ba5 100644 --- a/tests/mysql.ini.tmpl +++ b/tests/mysql.ini.tmpl @@ -1,4 +1,5 @@ -APP_NAME = Gitea: Git with a cup of tea +APP_NAME = Gitea +APP_SLOGAN = Git with a cup of tea RUN_MODE = prod [database] diff --git a/tests/pgsql.ini.tmpl b/tests/pgsql.ini.tmpl index 300d36eb71..760826280b 100644 --- a/tests/pgsql.ini.tmpl +++ b/tests/pgsql.ini.tmpl @@ -1,4 +1,5 @@ -APP_NAME = Gitea: Git with a cup of tea +APP_NAME = Gitea +APP_SLOGAN = Git with a cup of tea RUN_MODE = prod [database] diff --git a/tests/sqlite.ini.tmpl b/tests/sqlite.ini.tmpl index bc7227fcc9..48ee8d4e4a 100644 --- a/tests/sqlite.ini.tmpl +++ b/tests/sqlite.ini.tmpl @@ -1,4 +1,5 @@ -APP_NAME = Gitea: Git with a cup of tea +APP_NAME = Gitea +APP_SLOGAN = Git with a cup of tea RUN_MODE = prod [database]