Skip to content

feat(i18n): externalize email templates + lang-aware send chain (#221)#5

Closed
an9xyz wants to merge 1 commit into
mainfrom
feat/i18n-email-templates
Closed

feat(i18n): externalize email templates + lang-aware send chain (#221)#5
an9xyz wants to merge 1 commit into
mainfrom
feat/i18n-email-templates

Conversation

@an9xyz
Copy link
Copy Markdown
Collaborator

@an9xyz an9xyz commented Jun 2, 2026

Summary

Implements issue Mininglamp-OSS#221 (Part of Mininglamp-OSS#170, backend i18n): externalize the hardcoded
Chinese email templates into per-language assets and thread a lang through the
email send chain.

  • New modules/base/common/emailtmpl — per-language (zh-CN/en-US)
    subject/html/text templates embedded via go:embed, rendered through a
    text/template + html/template split: Subject headers are not HTML-escaped,
    while bodies keep XSS-safe escaping of user-controlled fields (inviter name,
    space name, …). Templates are precompiled once; an incomplete set fails loud
    at startup.
  • Verify-code emailSendVerifyCode gains a lang arg, renders from
    emailtmpl, and is upgraded to SendTransactionalHTML (plaintext fallback +
    transactional headers reduce silent spam-filter drops).
  • Space invite emails — owner/member templates moved to emailtmpl; the
    role label and the anonymous-inviter fallback are localized in-template
    instead of hardcoded in Go. Invite links now carry &lang=<recipient language>.
  • i18n.OutboundLanguage(ctx) — negotiated language with
    OCTO_DEFAULT_LANGUAGE fallback. Per feat(i18n): email templates + lang-aware send chain (Part of #170) Mininglamp-OSS/octo-server#221 the value resolves to the default
    for now (verify-code requester == recipient; invites are async with no
    recipient uid); the lang param is threaded end-to-end so a future
    per-recipient resolver plugs in without touching the send or template layers.

Client-visible verify-code/login API errors are already localized via
ResponseErrorL; this change only English-cleans the now-invisible
service-layer error sentinels.

Test plan

  • go build ./... / go vet ./...
  • emailtmpl + pkg/i18n unit tests, incl. -race (render, language
    fallback, XSS escaping boundary, URL not mangled, localized role label,
    template completeness)
  • space invite tests (template + dispatch + e2e)
  • user email/i18n tests, modules/base/common, modules/common
  • make i18n-extract-check + make i18n-lint green
  • gofmt clean

Acceptance (Mininglamp-OSS#221)

  • Verify-code + space-invite emails render per language; fall back to
    OCTO_DEFAULT_LANGUAGE
  • make i18n-extract-check + make i18n-lint green

…nglamp-OSS#221)

Add modules/base/common/emailtmpl: per-language (zh-CN/en-US) subject/HTML/
plaintext email templates embedded via go:embed and rendered through a
text/template + html/template split, so Subject headers are not HTML-escaped
while bodies keep XSS-safe escaping of user-controlled fields.

Thread a lang parameter through the email send chain:
- SendVerifyCode takes a lang arg, renders from emailtmpl, and is upgraded to
  SendTransactionalHTML (plaintext fallback + transactional headers reduce
  silent spam-filter drops).
- Space owner/member invite emails render via emailtmpl; the role label and the
  anonymous-inviter fallback are localized in-template instead of hardcoded in
  Go, and invite links now carry &lang=<recipient language>.
- Add i18n.OutboundLanguage(ctx): negotiated language with OCTO_DEFAULT_LANGUAGE
  fallback. Per Mininglamp-OSS#221 it resolves to the default for now (verify-code requester
  == recipient; invites are async with no recipient uid); the lang param is
  threaded end-to-end so a future per-recipient resolver plugs in without
  touching the send or template layers.

Client-visible verify-code/login API errors are already localized via
ResponseErrorL (Mininglamp-OSS#188/Mininglamp-OSS#197); this only English-cleans the now-invisible
service-layer error sentinels.
@github-actions github-actions Bot added the size/XL PR size: XL label Jun 2, 2026
@an9xyz
Copy link
Copy Markdown
Collaborator Author

an9xyz commented Jun 2, 2026

Superseded by upstream PR Mininglamp-OSS#224 (same branch). Closing this fork-internal PR to avoid duplication.

@an9xyz an9xyz closed this Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/XL PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant