style(aurora): CSS class-based refactor, full i18n, and locale alignment

themes/aurora/ (all 11 tmpl templates):
- Extract all reusable inline styles to CSS classes in <style> blocks
- Organize CSS with /* Section */ comment headers (Base, Header, Card, etc.)
- Clean HTML structure: <tr>/<td> on separate lines, consistent 2-space indent
- Replace all hardcoded English button text with locale.Tr keys
- Add mail.team_invite.text_3 disclaimer notice to team_invite
- Go variable assignments on dedicated lines with proper indentation
- Section comments in Title Case

tools/preview/locale.go:
- Replace LocaleEN with full 60-key official Gitea mail locale
- Add positional format specifier support (%[1]s, %[2]d) in Tr()
- All keys verified against official Gitea locale_en-US.json (100% match)

.gitignore:
- Add preview/rendered.js entry

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
KenanZhuandClaude Opus 4.8 committed 2026-06-04 18:51:56 +08:00
1 parent a97a9bea1d
commit 6ae9c97be8
13 files changed
+1561 -507

No files matched your search

+80 -46
View File
@@ -9,22 +9,38 @@ import (
// Locale provides English fallback translations, matching Gitea's locale.Tr interface.
type Locale struct{}
// Tr translates a key and substitutes positional %s/%d arguments.
// Tr translates a key and substitutes %s / %d / %[N]s / %[N]d arguments.
// HTML arguments are preserved; plain strings are HTML-escaped.
func (l Locale) Tr(key string, args ...any) template.HTML {
s := LocaleEN[key]
if s == "" {
s = key
}
for _, arg := range args {
for i, arg := range args {
var val string
if h, ok := arg.(template.HTML); ok {
val = string(h) // already safe HTML — don't double-escape
val = string(h) // already safe HTML
} else {
val = template.HTMLEscapeString(fmt.Sprint(arg))
}
// Handle positional format specifiers: %[1]s, %[2]d, etc.
pos := fmt.Sprintf("%%[%d]", i+1)
s = strings.Replace(s, pos+"s", val, 1)
s = strings.Replace(s, pos+"d", val, 1)
}
// Fallback for non-positional %s / %d (sequential replacement)
for _, arg := range args {
var val string
if h, ok := arg.(template.HTML); ok {
val = string(h)
} else {
val = template.HTMLEscapeString(fmt.Sprint(arg))
}
if !strings.Contains(s, "%s") && !strings.Contains(s, "%d") {
break
}
s = strings.Replace(s, "%s", val, 1)
s = strings.Replace(s, "%d", fmt.Sprint(arg), 1)
s = strings.Replace(s, "%d", val, 1)
}
return template.HTML(s)
}
@@ -51,46 +67,64 @@ func (l Locale) TrN(count any, singular, plural string, args ...any) template.HT
// LocaleEN holds all English translation strings used by Gitea mail templates.
var LocaleEN = map[string]string{
"mail.activate_account.title": "Activate your %s account",
"mail.hi_user_x": "Hi %s,",
"mail.activate_account.text_1": "Welcome to %s! Please activate your account by clicking the button below.",
"mail.activate_account.text_2": "This activation link will expire in %s.",
"mail.activate_email.title": "Verify your email address for %s",
"mail.activate_email.text": "Please verify your email address. The link will expire in %s.",
"mail.register_notify.title": "Welcome to %s, %s",
"mail.register_notify.text_1": "Your account on %s has been created successfully.",
"mail.register_notify.text_2": "Your username is: %s",
"mail.register_notify.text_3": "If you need to set a password, visit %s.",
"mail.reset_password.title": "Reset your %s password",
"mail.reset_password.text": "Click the link below to reset your password. It will expire in %s.",
"mail.link_not_working_do_paste": "If the button doesn't work, copy and paste this link into your browser:",
"mail.team_invite.text_1": "%s has invited you to join the team %s in the organization %s.",
"mail.team_invite.text_2": "Click the button below to accept the invitation.",
"mail.team_invite.text_3": "This invitation was sent to %s.",
"mail.repo.collaborator.added.text": "You have been added as a collaborator on the repository",
"mail.view_it_on": "View it on %s",
"mail.repo.transfer.body": "The repository %s has been transferred to you.",
"mail.release.new.text": "%s published a new release %s in the repository %s.",
"mail.release.title": "Release: %s",
"mail.release.note": "Release Notes:",
"mail.release.downloads": "Downloads",
"mail.release.download.zip": "Source Code (ZIP)",
"mail.release.download.targz": "Source Code (TAR.GZ)",
"mail.issue_assigned.pull": "%s assigned pull request %s to you in the repository %s.",
"mail.issue_assigned.issue": "%s assigned issue %s to you in the repository %s.",
"mail.issue.x_mentioned_you": "%s mentioned you.",
"mail.issue.action.close": "%s closed issue #%d.",
"mail.issue.action.reopen": "%s reopened issue #%d.",
"mail.issue.action.merge": "%s merged pull request #%d into %s.",
"mail.issue.action.approve": "%s approved this change.",
"mail.issue.action.reject": "%s requested changes.",
"mail.issue.action.review": "%s reviewed this change.",
"mail.issue.action.review_dismissed": "%s dismissed the review from %s.",
"mail.issue.action.ready_for_review": "%s marked this as ready for review.",
"mail.issue.action.new": "%s created issue #%d.",
"mail.issue.action.force_push": "%s force-pushed the %s branch from %s to %s.",
"mail.issue.action.push_1": "%s pushed %d commit to %s.",
"mail.issue.action.push_n": "%s pushed %d commits to %s.",
"mail.issue.in_tree_path": "In %s:",
"mail.reply": "Reply to this email",
"mail.hi_user_x": "Hi <b>%s</b>,",
"mail.activate_account": "Please activate your account",
"mail.activate_account.title": "%s, please activate your account",
"mail.activate_account.text_1": "Hi <b>%[1]s</b>, thanks for registering at %[2]s!",
"mail.activate_account.text_2": "Please click the following link to activate your account within <b>%s</b>:",
"mail.activate_email": "Verify your email address",
"mail.activate_email.title": "%s, please verify your email address",
"mail.activate_email.text": "Please click the following link to verify your email address within <b>%s</b>:",
"mail.register_success": "Registration successful",
"mail.register_notify": "Welcome to %s",
"mail.register_notify.title": "%[1]s, welcome to %[2]s",
"mail.register_notify.text_1": "This is your registration confirmation email for %s!",
"mail.register_notify.text_2": "You can now log in via username: %s.",
"mail.register_notify.text_3": "If this account has been created for you, please <a href=\"%s\">set your password</a> first.",
"mail.reset_password": "Recover your account",
"mail.reset_password.title": "%s, you have requested to recover your account",
"mail.reset_password.text": "Please click the following link to recover your account within <b>%s</b>:",
"mail.team_invite.subject": "%[1]s has invited you to join the %[2]s organization",
"mail.team_invite.text_1": "%[1]s has invited you to join team %[2]s in organization %[3]s.",
"mail.team_invite.text_2": "Please click the following link to join the team:",
"mail.team_invite.text_3": "Note: This invitation was intended for %[1]s. If you were not expecting this invitation, you can ignore this email.",
"mail.repo.collaborator.added.subject": "%s added you to %s",
"mail.repo.collaborator.added.text": "You have been added as a collaborator of repository:",
"mail.repo.transfer.subject_to": "%s would like to transfer \"%s\" to %s",
"mail.repo.transfer.subject_to_you": "%s would like to transfer \"%s\" to you",
"mail.repo.transfer.to_you": "you",
"mail.repo.transfer.body": "To accept or reject it, visit %s or just ignore it.",
"mail.release.new.subject": "%s in %s released",
"mail.release.new.text": "<b>@%[1]s</b> released %[2]s in %[3]s",
"mail.release.title": "Title: %s",
"mail.release.note": "Note:",
"mail.release.downloads": "Downloads:",
"mail.release.download.zip": "Source Code (ZIP)",
"mail.release.download.targz": "Source Code (TAR.GZ)",
"mail.repo.actions.run.failed": "Run failed",
"mail.repo.actions.run.succeeded": "Run succeeded",
"mail.repo.actions.run.cancelled": "Run cancelled",
"mail.repo.actions.jobs.all_succeeded": "All jobs have succeeded",
"mail.repo.actions.jobs.all_failed": "All jobs have failed",
"mail.repo.actions.jobs.some_not_successful": "Some jobs were not successful",
"mail.repo.actions.jobs.all_cancelled": "All jobs have been cancelled",
"mail.issue_assigned.pull": "@%[1]s assigned you to pull request %[2]s in repository %[3]s.",
"mail.issue_assigned.issue": "@%[1]s assigned you to issue %[2]s in repository %[3]s.",
"mail.issue.x_mentioned_you": "<b>@%s</b> mentioned you:",
"mail.issue.action.close": "<b>@%[1]s</b> closed #%[2]d.",
"mail.issue.action.reopen": "<b>@%[1]s</b> reopened #%[2]d.",
"mail.issue.action.merge": "<b>@%[1]s</b> merged #%[2]d into %[3]s.",
"mail.issue.action.approve": "<b>@%[1]s</b> approved this pull request.",
"mail.issue.action.reject": "<b>@%[1]s</b> requested changes on this pull request.",
"mail.issue.action.review": "<b>@%[1]s</b> commented on this pull request.",
"mail.issue.action.review_dismissed": "<b>@%[1]s</b> dismissed last review from %[2]s for this pull request.",
"mail.issue.action.ready_for_review": "<b>@%[1]s</b> marked this pull request ready for review.",
"mail.issue.action.new": "<b>@%[1]s</b> created #%[2]d.",
"mail.issue.action.force_push": "<b>%[1]s</b> force-pushed the <b>%[2]s</b> from %[3]s to %[4]s.",
"mail.issue.action.push_1": "<b>@%[1]s</b> pushed %[3]d commit to %[2]s",
"mail.issue.action.push_n": "<b>@%[1]s</b> pushed %[3]d commits to %[2]s",
"mail.issue.in_tree_path": "In %s:",
"mail.view_it_on": "View it on %s",
"mail.reply": "or reply to this email directly",
"mail.link_not_working_do_paste": "Not working? Try copying and pasting it to your browser.",
}