aboutsummaryrefslogtreecommitdiffstats
path: root/internal/web/templates/partials
diff options
context:
space:
mode:
authorgrm <grm@eyesin.space>2026-09-14 01:32:25 +0300
committergrm <grm@eyesin.space>2026-09-14 01:32:25 +0300
commite14a4250efb828262347f5a4bbc4067cd71d885f (patch)
tree3fcf6512f3b030b06c818ff4a224677a026d3b1b /internal/web/templates/partials
parent282d2ab3e0fb3a74f32160a231225773001acd14 (diff)
downloadblogspace-e14a4250efb828262347f5a4bbc4067cd71d885f.tar.gz
blogspace-e14a4250efb828262347f5a4bbc4067cd71d885f.tar.bz2
blogspace-e14a4250efb828262347f5a4bbc4067cd71d885f.zip
Add languages: English and Greek, chosen per blog on the Settings tab
Every blog and its dashboard were hard-wired to English. A blogger can now pick the language of their blog; it switches the whole dashboard and the blog's fixed text — post dates, archive months, the RSS link, the pager, the 404 page — while what the blogger wrote is left alone. The new internal/i18n package keys translations by the English string, so an untranslated key renders as English rather than blank, and TestGreekCatalogComplete scans the templates and handlers to fail when the Greek catalog misses a key or keeps a stale one. Templates are compiled once per language with t/tf/date/postdate/month closed over the language, so they need no data plumbing. The language lives in settings.language (blog migration 00002), not in the theme, so "Reset design" does not touch it. Public pages use the blog's language; management pages use the logged-in user's own blog's, so a superadmin editing someone else's blog keeps theirs; the login page follows Accept-Language. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'internal/web/templates/partials')
-rw-r--r--internal/web/templates/partials/dashnav.html26
-rw-r--r--internal/web/templates/partials/editor.html14
-rw-r--r--internal/web/templates/partials/imagepick.html4
-rw-r--r--internal/web/templates/partials/mdhelp.html10
4 files changed, 27 insertions, 27 deletions
diff --git a/internal/web/templates/partials/dashnav.html b/internal/web/templates/partials/dashnav.html
index 0966f7b..65b0ed5 100644
--- a/internal/web/templates/partials/dashnav.html
+++ b/internal/web/templates/partials/dashnav.html
@@ -2,11 +2,11 @@
<div class="topbar-inner">
<a class="brand" href="{{if .User}}/dashboard{{else}}/{{end}}">Blogspace</a>
{{if .User}}
- <span class="who">{{.User.Username}}{{if .User.IsSuperadmin}} (superadmin){{end}}</span>
+ <span class="who">{{.User.Username}}{{if .User.IsSuperadmin}} ({{t "superadmin"}}){{end}}</span>
<span class="links">
- {{if .User.IsSuperadmin}}<a href="/admin/"{{if hasPrefix .Path "/admin/"}} class="active"{{end}}>Admin</a>{{end}}
- <a href="/account/password"{{if eq .Path "/account/password"}} class="active"{{end}}>Password</a>
- <form method="post" action="/logout" class="inline"><input type="hidden" name="_csrf" value="{{.CSRF}}"><button type="submit" class="linkbtn">Log out</button></form>
+ {{if .User.IsSuperadmin}}<a href="/admin/"{{if hasPrefix .Path "/admin/"}} class="active"{{end}}>{{t "Admin"}}</a>{{end}}
+ <a href="/account/password"{{if eq .Path "/account/password"}} class="active"{{end}}>{{t "Password"}}</a>
+ <form method="post" action="/logout" class="inline"><input type="hidden" name="_csrf" value="{{.CSRF}}"><button type="submit" class="linkbtn">{{t "Log out"}}</button></form>
</span>
{{end}}
</div>
@@ -17,16 +17,16 @@
<div class="topbar-inner">
<strong class="blogname">{{.Blog.Title}}</strong>
<span class="tabs">
- <a href="{{$b}}"{{if eq .Path $b}} class="active"{{end}}>Overview</a>
- <a href="{{$b}}posts"{{if hasPrefix .Path (print $b "posts")}} class="active"{{end}}>Posts</a>
- <a href="{{$b}}pages"{{if hasPrefix .Path (print $b "pages")}} class="active"{{end}}>Pages</a>
- <a href="{{$b}}announcements"{{if hasPrefix .Path (print $b "announcements")}} class="active"{{end}}>Announcements</a>
- <a href="{{$b}}layout"{{if hasPrefix .Path (print $b "layout")}} class="active"{{end}}>Layout</a>
- <a href="{{$b}}design"{{if hasPrefix .Path (print $b "design")}} class="active"{{end}}>Design</a>
- <a href="{{$b}}images"{{if hasPrefix .Path (print $b "images")}} class="active"{{end}}>Images</a>
- <a href="{{$b}}settings"{{if hasPrefix .Path (print $b "settings")}} class="active"{{end}}>Settings</a>
+ <a href="{{$b}}"{{if eq .Path $b}} class="active"{{end}}>{{t "Overview"}}</a>
+ <a href="{{$b}}posts"{{if hasPrefix .Path (print $b "posts")}} class="active"{{end}}>{{t "Posts"}}</a>
+ <a href="{{$b}}pages"{{if hasPrefix .Path (print $b "pages")}} class="active"{{end}}>{{t "Pages"}}</a>
+ <a href="{{$b}}announcements"{{if hasPrefix .Path (print $b "announcements")}} class="active"{{end}}>{{t "Announcements"}}</a>
+ <a href="{{$b}}layout"{{if hasPrefix .Path (print $b "layout")}} class="active"{{end}}>{{t "Layout"}}</a>
+ <a href="{{$b}}design"{{if hasPrefix .Path (print $b "design")}} class="active"{{end}}>{{t "Design"}}</a>
+ <a href="{{$b}}images"{{if hasPrefix .Path (print $b "images")}} class="active"{{end}}>{{t "Images"}}</a>
+ <a href="{{$b}}settings"{{if hasPrefix .Path (print $b "settings")}} class="active"{{end}}>{{t "Settings"}}</a>
</span>
- <a class="view" href="{{.BlogURL}}" target="_blank">View blog &#8599;</a>
+ <a class="view" href="{{.BlogURL}}" target="_blank">{{t "View blog"}} &#8599;</a>
</div>
</div>
{{end}}{{end}}
diff --git a/internal/web/templates/partials/editor.html b/internal/web/templates/partials/editor.html
index 8e0acaf..eb2e315 100644
--- a/internal/web/templates/partials/editor.html
+++ b/internal/web/templates/partials/editor.html
@@ -1,9 +1,9 @@
{{define "editor"}}<textarea name="{{.name}}" id="ed-{{.name}}" rows="{{.rows}}"{{if .tall}} class="editor"{{end}}>{{.value}}</textarea>
<div class="editor-tools">
- <label class="upload">Insert image <input type="file" name="inline_image" id="ed-{{.name}}-file" accept="image/*"></label>
+ <label class="upload">{{t "Insert image"}} <input type="file" name="inline_image" id="ed-{{.name}}-file" accept="image/*"></label>
<span class="upload-status" id="ed-{{.name}}-status"></span>
- <span class="muted small">…or paste / drop an image into the text.</span>
- <noscript><span class="muted small">The image is added at the end of the text when you save.</span></noscript>
+ <span class="muted small">{{t "…or paste / drop an image into the text."}}</span>
+ <noscript><span class="muted small">{{t "The image is added at the end of the text when you save."}}</span></noscript>
</div>
{{template "mdhelp"}}
<script>
@@ -18,14 +18,14 @@
ta.focus();
}
function upload(file) {
- st.textContent = "Uploading " + file.name + "…";
+ st.textContent = {{t "Uploading"}} + " " + file.name + "…";
var fd = new FormData();
fd.append("_csrf", {{.csrf}});
fd.append("file", file);
fetch({{.upload}}, { method: "POST", body: fd, credentials: "same-origin", headers: { Accept: "application/json" } })
- .then(function (r) { return r.json().then(function (j) { if (!r.ok || j.error) throw new Error(j.error || "upload failed"); return j; }); })
- .then(function (j) { insert(j.markdown); st.textContent = "Inserted " + j.filename + "."; inp.value = ""; })
- .catch(function (err) { st.textContent = "Could not upload: " + err.message; });
+ .then(function (r) { return r.json().then(function (j) { if (!r.ok || j.error) throw new Error(j.error || {{t "upload failed"}}); return j; }); })
+ .then(function (j) { insert(j.markdown); st.textContent = {{t "Inserted"}} + " " + j.filename + "."; inp.value = ""; })
+ .catch(function (err) { st.textContent = {{t "Could not upload:"}} + " " + err.message; });
}
inp.addEventListener("change", function () { if (inp.files && inp.files[0]) upload(inp.files[0]); });
ta.addEventListener("paste", function (ev) {
diff --git a/internal/web/templates/partials/imagepick.html b/internal/web/templates/partials/imagepick.html
index 4431d02..911b355 100644
--- a/internal/web/templates/partials/imagepick.html
+++ b/internal/web/templates/partials/imagepick.html
@@ -2,8 +2,8 @@
<label>{{.label}}</label>
{{if .hint}}<p class="muted small">{{.hint}}</p>{{end}}
<div class="picks">
- <label class="pick none"><input type="radio" name="{{.name}}" value="none"{{if not .current}} checked{{end}}><span class="swatch">&times;</span><span class="name">None</span></label>
+ <label class="pick none"><input type="radio" name="{{.name}}" value="none"{{if not .current}} checked{{end}}><span class="swatch">&times;</span><span class="name">{{t "None"}}</span></label>
{{range .images}}<label class="pick"><input type="radio" name="{{$.name}}" value="{{.ID}}"{{if eq .ID.String $.current}} checked{{end}}><img src="/b/{{$.sub}}/media/{{.ID}}" alt=""><span class="name">{{.Filename}}</span></label>{{end}}
</div>
- <label>…or upload a new one<br><input type="file" name="{{.name}}_file" accept="{{if .accept}}{{.accept}}{{else}}image/*{{end}}"></label>
+ <label>{{t "…or upload a new one"}}<br><input type="file" name="{{.name}}_file" accept="{{if .accept}}{{.accept}}{{else}}image/*{{end}}"></label>
</div>{{end}}
diff --git a/internal/web/templates/partials/mdhelp.html b/internal/web/templates/partials/mdhelp.html
index 3584025..748452e 100644
--- a/internal/web/templates/partials/mdhelp.html
+++ b/internal/web/templates/partials/mdhelp.html
@@ -1,9 +1,9 @@
{{define "mdhelp"}}<details class="help">
- <summary>Formatting cheat-sheet</summary>
+ <summary>{{t "Formatting cheat-sheet"}}</summary>
<table class="cheat">
- <tr><td><code># Heading</code>, <code>## Smaller heading</code></td><td><code>**bold**</code>, <code>*italic*</code></td></tr>
- <tr><td><code>[link text](https://example.org)</code></td><td><code>![description](/media/…)</code> — <em>Insert image</em> writes this for you</td></tr>
- <tr><td><code>- list item</code> / <code>1. numbered</code></td><td><code>&gt; quote</code>, <code>`code`</code>, <code>---</code> for a line</td></tr>
+ <tr><td><code># {{t "Heading"}}</code>, <code>## {{t "Smaller heading"}}</code></td><td><code>**{{t "bold"}}**</code>, <code>*{{t "italic"}}*</code></td></tr>
+ <tr><td><code>[{{t "link text"}}](https://example.org)</code></td><td><code>![{{t "description"}}](/media/…)</code> — <em>{{t "Insert image"}}</em> {{t "writes this for you"}}</td></tr>
+ <tr><td><code>- {{t "list item"}}</code> / <code>1. {{t "numbered"}}</code></td><td><code>&gt; {{t "quote"}}</code>, <code>`{{t "code"}}`</code>, <code>---</code> {{t "for a line"}}</td></tr>
</table>
- <p class="muted small">Blank line = new paragraph. Press Enter once for a line break.</p>
+ <p class="muted small">{{t "Blank line = new paragraph. Press Enter once for a line break."}}</p>
</details>{{end}}