Translate error pages

This commit is contained in:
Andrew-71 2024-10-07 16:04:39 +03:00
parent 8ae76cc8e8
commit 6d37c363bb
10 changed files with 90 additions and 30 deletions

View file

@ -1,30 +1,45 @@
# Changelog # Changelog
This file keeps track of changes in a human-readable fashion This file keeps track of changes in a human-readable fashion
## Upcoming
These changes were not yet released
* Brought default CSS up to date with my personal website
* Error pages are now translated
## v1.1.4 ## v1.1.4
* Fixed HTML `lang` tag * Fixed HTML `lang` tag
* Theme CSS link is now only present if non-default is set * Theme CSS link is now only present if non-default is set
* Improved template consistency (backend) * Improved template consistency (backend)
## v1.1.3 ## v1.1.3
This release mostly consists of backend improvements This release mostly consists of backend improvements
* List items no longer replace hyphens with spaces for consistency * List items no longer replace hyphens with spaces for consistency
* Telegram message for SCRAM is now translatable * Telegram message for SCRAM is now translatable
* Ensured HTML escape in list descriptions * Ensured HTML escape in list descriptions
* Refactored many methods, improved comments * Refactored many methods, improved comments
## v1.1.2 ## v1.1.2
This release contains a few bug fixes This release contains a few bug fixes
* Real IPs are now logged (By Rithas K.) * Real IPs are now logged (By Rithas K.)
* CSS now has `box-sizing: border-box` to fix textarea in some cases (By Rithas K.) * CSS now has `box-sizing: border-box` to fix textarea in some cases (By Rithas K.)
* Done some minor code housekeeping * Done some minor code housekeeping
## v1.1.1 ## v1.1.1
This release is mostly a technicality, with a move over to GitHub (`ghcr.io/andrew-71/hibiscus`) for packages due to DockerHub's prior anti-Russian actions making old "CI/CD" unsustainable. This release is mostly a technicality, with a move over to GitHub (`ghcr.io/andrew-71/hibiscus`) for packages due to DockerHub's prior anti-Russian actions making old "CI/CD" unsustainable.
## v1.1.0 ## v1.1.0
* You can now specify the Telegram *topic* to send notification to via `tg_topic` config key (By Rithas K.) * You can now specify the Telegram *topic* to send notification to via `tg_topic` config key (By Rithas K.)
* The Telegram message is now partially translated * The Telegram message is now partially translated
* Fixed CSS `margin` and `text-align` inherited from my website * Fixed CSS `margin` and `text-align` inherited from my website
## v1.0.0 ## v1.0.0
This release includes several **breaking** changes This release includes several **breaking** changes
* Made a new favicon * Made a new favicon
* English is now used as a fallback language, making incomplete translations somewhat usable * English is now used as a fallback language, making incomplete translations somewhat usable
@ -38,16 +53,20 @@ This release includes several **breaking** changes
* Comic Sans MS for *everything* * Comic Sans MS for *everything*
* sorry * sorry
## v0.6.1
* Fixed date display when using `Local` timezone
## v0.6.0 ## v0.6.0
* Replaced config reload with edit in info (api method still available, config reloads on save) * Replaced config reload with edit in info (api method still available, config reloads on save)
* Bug fixes * Bug fixes
* Filenames are now sanitized when writing files * Filenames are now sanitized when writing files
* "Tomorrow" in days list is now also displayed if Timezone is changed and grace period is off * "Tomorrow" in days list is now also displayed if Timezone is changed and grace period is off
* Frontend date display now uses configured timezone * Frontend date display now uses configured timezone
### v0.6.1
* Fixed date display when using `Local` timezone
## v0.5.0 ## v0.5.0
* Added a JS prompt to create new note * Added a JS prompt to create new note
* "Sanitization" for this method is basic and assumes a well-meaning user * "Sanitization" for this method is basic and assumes a well-meaning user
* Old instructions appear if JS is disabled * Old instructions appear if JS is disabled
@ -56,6 +75,7 @@ This release includes several **breaking** changes
* Config reload now sets removed values to defaults * Config reload now sets removed values to defaults
## v0.4.0 ## v0.4.0
* Customisation changes * Customisation changes
* Added `title` option to config * Added `title` option to config
* Controls the text in the header, "🌺 Hibiscus.txt" by default * Controls the text in the header, "🌺 Hibiscus.txt" by default
@ -66,17 +86,20 @@ This release includes several **breaking** changes
* Spaces in config options are now supported (basically just for `title`) * Spaces in config options are now supported (basically just for `title`)
## v0.3.0 ## v0.3.0
* Added themes * Added themes
* Picked theme is set by `theme` key in config. Default is ...`default` * Picked theme is set by `theme` key in config. Default is ...`default`
* Themes are defined in `/public/themes/<name>.css` and modify colours (or, theoretically, do more) * Themes are defined in `/public/themes/<name>.css` and modify colours (or, theoretically, do more)
* Current pre-made themes are `default`, `gruvbox` and `high-contrast` * Current pre-made themes are `default`, `gruvbox` and `high-contrast`
## v0.2.0 ## v0.2.0
* Added config reload * Added config reload
* Can be reloaded in info page * Can be reloaded in info page
* Can be reloaded with new `reload` api method (be aware of the redirect if referer is present) * Can be reloaded with new `reload` api method (be aware of the redirect if referer is present)
## 7 May 2024 - v0.1.0 ## 7 May 2024 - v0.1.0
* Began move towards [semantic versioning](https://semver.org/) * Began move towards [semantic versioning](https://semver.org/)
* Current version is now 0.1.0 * Current version is now 0.1.0
* Added `version` api method * Added `version` api method
@ -91,6 +114,7 @@ This release includes several **breaking** changes
* Fixed export function failing * Fixed export function failing
## 6 May 2024 ## 6 May 2024
* Grace period is now non-inclusive (so `4h` means the switch will happen right at `4:00`, not `4:01`) * Grace period is now non-inclusive (so `4h` means the switch will happen right at `4:00`, not `4:01`)
* Added API method to check if grace period is active * Added API method to check if grace period is active
* Made changes to date display on frontend * Made changes to date display on frontend
@ -100,6 +124,7 @@ This release includes several **breaking** changes
But I think it's fine. But I think it's fine.
## 5 May 2024 ## 5 May 2024
* Added this changelog * Added this changelog
* Added grace period (as per suggestions) * Added grace period (as per suggestions)
* Set in config like `grace_period=3h26m` (via Go's `time.ParseDuration`) * Set in config like `grace_period=3h26m` (via Go's `time.ParseDuration`)

View file

@ -1,8 +1,15 @@
# TODO # TODO
List of things to add to this project List of things to add to this project
## Urgent (1.1.5-2.0.0)
* `style.css` in config instead of theme (provide themes as examples in repo)
* man page, maybe try packaging for fun
* Auth improvement so it DOESN'T ASK ME FOR PASSWORD EVERY DAY UGH XD * Auth improvement so it DOESN'T ASK ME FOR PASSWORD EVERY DAY UGH XD
## Nice to have
* Forward/backward buttons for days * Forward/backward buttons for days
* Changelog included
* Refactor code
## Brainstorming ## Brainstorming
Don't expect any of this, these are ideas floating inside my head Don't expect any of this, these are ideas floating inside my head
@ -17,4 +24,4 @@ Don't expect any of this, these are ideas floating inside my head
Is this even a feature that fits the vision? Is this even a feature that fits the vision?
* Better, *multi-page* docs in case others want to use this for some reason * Better, *multi-page* docs in case others want to use this for some reason
* Check export function for improvements * Check export function for improvements
* *Go* dependency-less? <-- this is a terrible idea * *Go* dependency-less? <-- this is a terrible idea

View file

@ -120,13 +120,7 @@ func (c *Config) Reload() error {
} }
} }
case "bool": case "bool":
{ fieldElem.SetBool(v == "true")
if v == "true" {
fieldElem.SetBool(true)
} else {
fieldElem.SetBool(false)
}
}
case "location": case "location":
timezone = v timezone = v
case "duration": case "duration":
@ -179,7 +173,7 @@ func ConfigReloadApi(w http.ResponseWriter, r *http.Request) {
HandleWrite(w.Write([]byte(err.Error()))) HandleWrite(w.Write([]byte(err.Error())))
} }
if r.Referer() != "" { if r.Referer() != "" {
http.Redirect(w, r, r.Header.Get("Referer"), 302) http.Redirect(w, r, r.Header.Get("Referer"), http.StatusFound)
return return
} }
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)

2
go.mod
View file

@ -1,4 +1,4 @@
module hibiscus module hibiscus-txt
go 1.22 go 1.22

View file

@ -27,5 +27,9 @@
"info.config": "Edit config", "info.config": "Edit config",
"info.telegram.auth_fail": "Failed auth attempt in Hibiscus.txt", "info.telegram.auth_fail": "Failed auth attempt in Hibiscus.txt",
"info.telegram.scram": "Hibiscus SCRAM triggered, shutting down" "info.telegram.scram": "Hibiscus SCRAM triggered, shutting down",
"error.404": "The page you were looking for doesn't exist",
"error.500": "It's probably not your fault, but something broke",
"error.prompt": "Go home?"
} }

View file

@ -27,5 +27,9 @@
"info.config": "Редактировать конфиг", "info.config": "Редактировать конфиг",
"info.telegram_notification": "Неверная попытка авторизации в Hibiscus.txt", "info.telegram_notification": "Неверная попытка авторизации в Hibiscus.txt",
"info.telegram.scram": "Активирована функция SCRAM в Hibiscus.txt, сервер выключается" "info.telegram.scram": "Активирована функция SCRAM в Hibiscus.txt, сервер выключается",
"error.404": "Страница, которую вы ищете, не существует",
"error.500": "Что-то сломалось",
"error.prompt": "На главную?"
} }

View file

@ -1,3 +1,4 @@
{{- define "404" -}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -10,8 +11,9 @@
<body> <body>
<main> <main>
<h1>Error 404 - Not Found</h1> <h1>Error 404 - Not Found</h1>
<p>The page you were looking for doesn't exist or was moved</p> <p>{{ translatableText "error.404" }}</p>
<h3><a href="/">Go home?</a></h3> <p><a href="/">{{ translatableText "error.prompt" }}</a></p>
</main> </main>
</body> </body>
</html> </html>
{{ end }}

View file

@ -1,3 +1,4 @@
{{- define "500" -}}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -10,8 +11,9 @@
<body> <body>
<main> <main>
<h1>Error 500 - Internal Server Error</h1> <h1>Error 500 - Internal Server Error</h1>
<p>It's probably not your fault, but something broke</p> <p>{{ translatableText "error.500" }}</p>
<h3><a href="/">Go home?</a></h3> <p><a href="/">{{ translatableText "error.prompt" }}</a></p>
</main> </main>
</body> </body>
</html> </html>
{{ end }}

View file

@ -1,12 +1,12 @@
/* Default theme */ /* Default theme */
:root { :root {
/* Light theme */ /* Light theme */
--text-light: #454545; --text-light: #2b2a2a;
--bg-light: #f5f0e1; --bg-light: #f4edd7;
--clickable-light: #f85552; --clickable-light: #f85552;
--clickable-hover-light: #e66868; --clickable-hover-light: #e66868;
--clickable-label-light: #f5f2ee; --clickable-label-light: #f4edd7;
--text-hover-light: #656565; --text-hover-light: #656565;
--textarea-bg-light: #f5f2ee; --textarea-bg-light: #f5f2ee;
@ -14,12 +14,12 @@
/* Dark theme */ /* Dark theme */
--text-dark: #f5f0e1; --text-dark: #f5f0e1;
--bg-dark: #2c2825; --bg-dark: #1b1916;
--clickable-dark: #f85552; --clickable-dark: #f85552;
--clickable-hover-dark: #e66868; --clickable-hover-dark: #e66868;
--clickable-label-dark: #f5f2ee; --clickable-label-dark: #f5f2ee;
--text-hover-dark: #656565; --text-hover-dark: #a9a8a4;
--textarea-bg-dark: #383030; --textarea-bg-dark: #383030;
--textarea-border-dark: #454545; --textarea-border-dark: #454545;
@ -29,21 +29,29 @@
body { body {
color: var(--text-light); color: var(--text-light);
background-color: var(--bg-light); background-color: var(--bg-light);
font-size: 18px;
margin: auto auto; margin: auto auto;
max-width: 640px; max-width: 640px;
padding: 1em; padding: 15px;
line-height: 1.4; line-height: 1.4;
font-family: serif; font-family: serif;
min-height: 85vh; min-height: 85vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
h1,h2,h3,h4,h5,h6 { line-height: 1.2 }
a, a:visited { color: var(--clickable-light); } a, a:visited { color: var(--clickable-light); }
a:hover, a:visited:hover { color: var(--clickable-hover-light); } a:hover, a:visited:hover { color: var(--clickable-hover-light); }
a.no-accent, a.no-accent:visited { color: var(--text-light); } a.no-accent, a.no-accent:visited { color: var(--text-light); }
a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-light); } a.no-accent:hover, a.no-accent:visited:hover { color: var(--text-hover-light); }
h2 { margin-bottom:12px; } ul:not(li ul), ol:not(li ol){
margin-left: 0;
padding-left: 0;
list-style-position: inside;
}
.list-title { margin-bottom: 0} .list-title { margin-bottom: 0}
.list-desc { margin-top: 0 } .list-desc { margin-top: 0 }
@ -55,7 +63,7 @@ textarea, input {
resize: vertical; resize: vertical;
outline: 0; outline: 0;
box-shadow: none; box-shadow: none;
border: 0.0625em solid var(--textarea-border-light); border: 2px solid var(--textarea-border-light);
margin-bottom: 1em; margin-bottom: 1em;
font-size: 18px; font-size: 18px;
} }

View file

@ -55,16 +55,30 @@ var editTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(P
var viewTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/entry.html")) var viewTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/entry.html"))
var listTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/list.html")) var listTemplate = template.Must(template.New("").Funcs(templateFuncs).ParseFS(Pages, "pages/base.html", "pages/list.html"))
var template404 = template.Must(template.New("404").Funcs(templateFuncs).ParseFS(Pages, "pages/error/404.html"))
// NotFound returns a user-friendly 404 error page. // NotFound returns a user-friendly 404 error page.
func NotFound(w http.ResponseWriter, r *http.Request) { func NotFound(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404) w.WriteHeader(404)
HandleWrite(w.Write(EmbeddedPage("pages/error/404.html")))
err := template404.Execute(w, nil)
if err != nil {
slog.Error("error rendering error 404 page", "error", err)
InternalError(w, r)
return
}
} }
var template500 = template.Must(template.New("500").Funcs(templateFuncs).ParseFS(Pages, "pages/error/500.html"))
// InternalError returns a user-friendly 500 error page. // InternalError returns a user-friendly 500 error page.
func InternalError(w http.ResponseWriter, r *http.Request) { func InternalError(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500) w.WriteHeader(500)
HandleWrite(w.Write(EmbeddedPage("pages/error/500.html")))
err := template500.Execute(w, nil)
if err != nil { // Well this is awkward
slog.Error("error rendering error 500 page", "error", err)
HandleWrite(w.Write([]byte("500. Something went *very* wrong.")))
return
}
} }
// GetEntries handles showing a list. // GetEntries handles showing a list.