Refactor i18n name and fix the L() function in public HTML templates

This commit is contained in:
Kailash Nadh 2021-01-23 19:34:30 +05:30
parent 4cd5e6ebeb
commit ee4fb7182f
14 changed files with 111 additions and 71 deletions

View File

@ -258,13 +258,13 @@ func initConstants() *constants {
// initI18n initializes a new i18n instance with the selected language map // initI18n initializes a new i18n instance with the selected language map
// loaded from the filesystem. // loaded from the filesystem.
func initI18n(lang string, fs stuffbin.FileSystem) *i18n.I18nLang { func initI18n(lang string, fs stuffbin.FileSystem) *i18n.I18n {
b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", lang)) b, err := fs.Read(fmt.Sprintf("/i18n/%s.json", lang))
if err != nil { if err != nil {
lo.Fatalf("error loading i18n language file: %v", err) lo.Fatalf("error loading i18n language file: %v", err)
} }
i, err := i18n.New(lang, b) i, err := i18n.New(b)
if err != nil { if err != nil {
lo.Fatalf("error unmarshalling i18n language: %v", err) lo.Fatalf("error unmarshalling i18n language: %v", err)
} }
@ -298,7 +298,7 @@ func initCampaignManager(q *Queries, cs *constants, app *App) *manager.Manager {
ViewTrackURL: cs.ViewTrackURL, ViewTrackURL: cs.ViewTrackURL,
MessageURL: cs.MessageURL, MessageURL: cs.MessageURL,
UnsubHeader: ko.Bool("privacy.unsubscribe_header"), UnsubHeader: ko.Bool("privacy.unsubscribe_header"),
}, newManagerDB(q), campNotifCB, lo) }, newManagerDB(q), campNotifCB, app.i18n, lo)
} }
@ -428,7 +428,7 @@ func initMediaStore() media.Store {
// initNotifTemplates compiles and returns e-mail notification templates that are // initNotifTemplates compiles and returns e-mail notification templates that are
// used for sending ad-hoc notifications to admins and subscribers. // used for sending ad-hoc notifications to admins and subscribers.
func initNotifTemplates(path string, fs stuffbin.FileSystem, i *i18n.I18nLang, cs *constants) *template.Template { func initNotifTemplates(path string, fs stuffbin.FileSystem, i *i18n.I18n, cs *constants) *template.Template {
// Register utility functions that the e-mail templates can use. // Register utility functions that the e-mail templates can use.
funcs := template.FuncMap{ funcs := template.FuncMap{
"RootURL": func() string { "RootURL": func() string {
@ -437,7 +437,7 @@ func initNotifTemplates(path string, fs stuffbin.FileSystem, i *i18n.I18nLang, c
"LogoURL": func() string { "LogoURL": func() string {
return cs.LogoURL return cs.LogoURL
}, },
"L": func() *i18n.I18nLang { "L": func() *i18n.I18n {
return i return i
}, },
} }
@ -464,7 +464,10 @@ func initHTTPServer(app *App) *echo.Echo {
}) })
// Parse and load user facing templates. // Parse and load user facing templates.
tpl, err := stuffbin.ParseTemplatesGlob(nil, app.fs, "/public/templates/*.html") tpl, err := stuffbin.ParseTemplatesGlob(template.FuncMap{
"L": func() *i18n.I18n {
return app.i18n
}}, app.fs, "/public/templates/*.html")
if err != nil { if err != nil {
lo.Fatalf("error parsing public templates: %v", err) lo.Fatalf("error parsing public templates: %v", err)
} }

View File

@ -40,7 +40,7 @@ type App struct {
importer *subimporter.Importer importer *subimporter.Importer
messengers map[string]messenger.Messenger messengers map[string]messenger.Messenger
media media.Store media media.Store
i18n *i18n.I18nLang i18n *i18n.I18n
notifTpls *template.Template notifTpls *template.Template
log *log.Logger log *log.Logger
bufLog *buflog.BufLog bufLog *buflog.BufLog

View File

@ -39,7 +39,7 @@ type tplData struct {
LogoURL string LogoURL string
FaviconURL string FaviconURL string
Data interface{} Data interface{}
L *i18n.I18nLang L *i18n.I18n
} }
type publicTpl struct { type publicTpl struct {

View File

@ -83,6 +83,7 @@
"globals.buttons.cancel": "Cancel", "globals.buttons.cancel": "Cancel",
"globals.buttons.clone": "Clone", "globals.buttons.clone": "Clone",
"globals.buttons.close": "Close", "globals.buttons.close": "Close",
"globals.buttons.continue": "Continue",
"globals.buttons.delete": "Delete", "globals.buttons.delete": "Delete",
"globals.buttons.edit": "Edit", "globals.buttons.edit": "Edit",
"globals.buttons.enabled": "Enabled", "globals.buttons.enabled": "Enabled",
@ -188,14 +189,25 @@
"menu.media": "Media", "menu.media": "Media",
"menu.newCampaign": "Create new", "menu.newCampaign": "Create new",
"menu.settings": "Settings", "menu.settings": "Settings",
"public.subNotFound": "Subscription not found.",
"public.campaignNotFound": "The e-mail message was not found.", "public.campaignNotFound": "The e-mail message was not found.",
"public.unsubTitle": "Unsubscribe",
"public.unsubHelp": "Do you want to unsubscribe from this mailing list?",
"public.unsubFull": "Also unsubscribe from all future e-mails.",
"public.unsub": "Unsubscribe",
"public.privacyTitle": "Privacy and data",
"public.privacyExport": "Export your data",
"public.privacyExportHelp": "A copy of your data will be e-mailed to you.",
"public.privacyWipe": "Wipe your data",
"public.privacyWipeHelp": "Delete all your subscriptions and related data from the database permanently.",
"public.privacyConfirmWipe": "Are you sure you want to delete all your subscription data permanently?",
"public.confirmOptinSubTitle": "Confirm subscription", "public.confirmOptinSubTitle": "Confirm subscription",
"public.confirmSub": "Confirm subscription", "public.confirmSub": "Confirm subscription",
"public.confirmSubInfo": "You have been added to the following lists:", "public.confirmSubInfo": "You have been added to the following lists:",
"public.confirmSubTitle": "Confirm", "public.confirmSubTitle": "Confirm",
"public.dataRemoved": "Your subscriptions and all associated data has been removed.", "public.dataRemoved": "Your subscriptions and all associated data has been removed.",
"public.dataRemovedTitle": "Data removed", "public.dataRemovedTitle": "Data removed",
"public.dataSent": "Your data has been e-mailed to you as an attachment", "public.dataSent": "Your data has been e-mailed to you as an attachment.",
"public.dataSentTitle": "Data e-mailed", "public.dataSentTitle": "Data e-mailed",
"public.errorFetchingCampaign": "Error fetching e-mail message", "public.errorFetchingCampaign": "Error fetching e-mail message",
"public.errorFetchingEmail": "E-mail message not found", "public.errorFetchingEmail": "E-mail message not found",

View File

@ -1,48 +1,66 @@
// i18n is a simple package that translates strings using a language map.
// It mimicks some functionality of the vue-i18n library so that the same JSON
// language map may be used in the JS frontent and the Go backend.
package i18n package i18n
import ( import (
"encoding/json" "encoding/json"
"errors"
"regexp" "regexp"
"strings" "strings"
) )
// Lang represents a loaded language. // I18n offers translation functions over a language map.
type Lang struct { type I18n struct {
Code string `json:"code"` code string `json:"code"`
Name string `json:"name"` name string `json:"name"`
langMap map[string]string
}
// I18nLang is a simple i18n library that translates strings using a language map.
// It mimicks some functionality of the vue-i18n library so that the same JSON
// language map may be used in the JS frontent and the Go backend.
type I18nLang struct {
Code string `json:"code"`
Name string `json:"name"`
langMap map[string]string langMap map[string]string
} }
var reParam = regexp.MustCompile(`(?i)\{([a-z0-9-.]+)\}`) var reParam = regexp.MustCompile(`(?i)\{([a-z0-9-.]+)\}`)
// New returns an I18n instance. // New returns an I18n instance.
func New(code string, b []byte) (*I18nLang, error) { func New(b []byte) (*I18n, error) {
var l map[string]string var l map[string]string
if err := json.Unmarshal(b, &l); err != nil { if err := json.Unmarshal(b, &l); err != nil {
return nil, err return nil, err
} }
return &I18nLang{
code, ok := l["_.code"]
if !ok {
return nil, errors.New("missing _.code field in language file")
}
name, ok := l["_.name"]
if !ok {
return nil, errors.New("missing _.name field in language file")
}
return &I18n{
langMap: l, langMap: l,
code: code,
name: name,
}, nil }, nil
} }
// Name returns the canonical name of the language.
func (i *I18n) Name() string {
return i.name
}
// Code returns the ISO code of the language.
func (i *I18n) Code() string {
return i.code
}
// JSON returns the languagemap as raw JSON. // JSON returns the languagemap as raw JSON.
func (i *I18nLang) JSON() []byte { func (i *I18n) JSON() []byte {
b, _ := json.Marshal(i.langMap) b, _ := json.Marshal(i.langMap)
return b return b
} }
// T returns the translation for the given key similar to vue i18n's t(). // T returns the translation for the given key similar to vue i18n's t().
func (i *I18nLang) T(key string) string { func (i *I18n) T(key string) string {
s, ok := i.langMap[key] s, ok := i.langMap[key]
if !ok { if !ok {
return key return key
@ -59,7 +77,7 @@ func (i *I18nLang) T(key string) string {
// eg: Ts("globals.message.notFound", // eg: Ts("globals.message.notFound",
// "name", "campaigns", // "name", "campaigns",
// "error", err) // "error", err)
func (i *I18nLang) Ts(key string, params ...string) string { func (i *I18n) Ts(key string, params ...string) string {
if len(params)%2 != 0 { if len(params)%2 != 0 {
return key + `: Invalid arguments` return key + `: Invalid arguments`
} }
@ -82,7 +100,7 @@ func (i *I18nLang) Ts(key string, params ...string) string {
// Tc returns the translation for the given key similar to vue i18n's tc(). // Tc returns the translation for the given key similar to vue i18n's tc().
// It expects the language string in the map to be of the form `Singular | Plural` and // It expects the language string in the map to be of the form `Singular | Plural` and
// returns `Plural` if n > 1, or `Singular` otherwise. // returns `Plural` if n > 1, or `Singular` otherwise.
func (i *I18nLang) Tc(key string, n int) string { func (i *I18n) Tc(key string, n int) string {
s, ok := i.langMap[key] s, ok := i.langMap[key]
if !ok { if !ok {
return key return key
@ -98,7 +116,7 @@ func (i *I18nLang) Tc(key string, n int) string {
// getSingular returns the singular term from the vuei18n pipe separated value. // getSingular returns the singular term from the vuei18n pipe separated value.
// singular term | plural term // singular term | plural term
func (i *I18nLang) getSingular(s string) string { func (i *I18n) getSingular(s string) string {
if !strings.Contains(s, "|") { if !strings.Contains(s, "|") {
return s return s
} }
@ -108,7 +126,7 @@ func (i *I18nLang) getSingular(s string) string {
// getSingular returns the plural term from the vuei18n pipe separated value. // getSingular returns the plural term from the vuei18n pipe separated value.
// singular term | plural term // singular term | plural term
func (i *I18nLang) getPlural(s string) string { func (i *I18n) getPlural(s string) string {
if !strings.Contains(s, "|") { if !strings.Contains(s, "|") {
return s return s
} }
@ -122,7 +140,7 @@ func (i *I18nLang) getPlural(s string) string {
} }
// subAllParams recursively resolves and replaces all {params} in a string. // subAllParams recursively resolves and replaces all {params} in a string.
func (i *I18nLang) subAllParams(s string) string { func (i *I18n) subAllParams(s string) string {
if !strings.Contains(s, `{`) { if !strings.Contains(s, `{`) {
return s return s
} }

View File

@ -11,6 +11,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/knadh/listmonk/internal/i18n"
"github.com/knadh/listmonk/internal/messenger" "github.com/knadh/listmonk/internal/messenger"
"github.com/knadh/listmonk/models" "github.com/knadh/listmonk/models"
) )
@ -40,6 +41,7 @@ type DataSource interface {
type Manager struct { type Manager struct {
cfg Config cfg Config
src DataSource src DataSource
i18n *i18n.I18n
messengers map[string]messenger.Messenger messengers map[string]messenger.Messenger
notifCB models.AdminNotifCallback notifCB models.AdminNotifCallback
logger *log.Logger logger *log.Logger
@ -108,7 +110,7 @@ type msgError struct {
} }
// New returns a new instance of Mailer. // New returns a new instance of Mailer.
func New(cfg Config, src DataSource, notifCB models.AdminNotifCallback, l *log.Logger) *Manager { func New(cfg Config, src DataSource, notifCB models.AdminNotifCallback, i *i18n.I18n, l *log.Logger) *Manager {
if cfg.BatchSize < 1 { if cfg.BatchSize < 1 {
cfg.BatchSize = 1000 cfg.BatchSize = 1000
} }
@ -122,6 +124,7 @@ func New(cfg Config, src DataSource, notifCB models.AdminNotifCallback, l *log.L
return &Manager{ return &Manager{
cfg: cfg, cfg: cfg,
src: src, src: src,
i18n: i,
notifCB: notifCB, notifCB: notifCB,
logger: l, logger: l,
messengers: make(map[string]messenger.Messenger), messengers: make(map[string]messenger.Messenger),
@ -334,6 +337,9 @@ func (m *Manager) TemplateFuncs(c *models.Campaign) template.FuncMap {
} }
return time.Now().Format(layout) return time.Now().Format(layout)
}, },
"L": func() *i18n.I18n {
return m.i18n
},
} }
} }

View File

@ -1,22 +1,22 @@
{{ define "campaign-status" }} {{ define "campaign-status" }}
{{ template "header" . }} {{ template "header" . }}
<h2>{{ .L.T "email.status.campaignUpdate" }}</h2> <h2>{{ L.Ts "email.status.campaignUpdate" }}</h2>
<table width="100%"> <table width="100%">
<tr> <tr>
<td width="30%"><strong>{{ .L.T "globa.L.Terms.campaign" }}</strong></td> <td width="30%"><strong>{{ L.Ts "globa.L.Terms.campaign" }}</strong></td>
<td><a href="{{ index . "RootURL" }}/campaigns/{{ index . "ID" }}">{{ index . "Name" }}</a></td> <td><a href="{{ index . "RootURL" }}/campaigns/{{ index . "ID" }}">{{ index . "Name" }}</a></td>
</tr> </tr>
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.status" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.status" }}</strong></td>
<td>{{ index . "Status" }}</td> <td>{{ index . "Status" }}</td>
</tr> </tr>
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.campaignSent" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.campaignSent" }}</strong></td>
<td>{{ index . "Sent" }} / {{ index . "ToSend" }}</td> <td>{{ index . "Sent" }} / {{ index . "ToSend" }}</td>
</tr> </tr>
{{ if ne (index . "Reason") "" }} {{ if ne (index . "Reason") "" }}
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.campaignReason" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.campaignReason" }}</strong></td>
<td>{{ index . "Reason" }}</td> <td>{{ index . "Reason" }}</td>
</tr> </tr>
{{ end }} {{ end }}

View File

@ -77,8 +77,8 @@
<div class="footer" style="text-align: center;font-size: 12px;color: #888;"> <div class="footer" style="text-align: center;font-size: 12px;color: #888;">
<p> <p>
{{ I18n.T "email.unsubHelp" }} {{ L.T "email.unsubHelp" }}
<a href="{{ UnsubscribeURL }}" style="color: #888;">{{ I18n.T "email.unsub" }}</a> <a href="{{ UnsubscribeURL }}" style="color: #888;">{{ L.T "email.unsub" }}</a>
</p> </p>
<p>Powered by <a href="https://listmonk.app" target="_blank" style="color: #888;">listmonk</a></p> <p>Powered by <a href="https://listmonk.app" target="_blank" style="color: #888;">listmonk</a></p>
</div> </div>

View File

@ -1,17 +1,17 @@
{{ define "import-status" }} {{ define "import-status" }}
{{ template "header" . }} {{ template "header" . }}
<h2>{{ .L.T "email.status.importTitle" }}</h2> <h2>{{ L.Ts "email.status.importTitle" }}</h2>
<table width="100%"> <table width="100%">
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.importFile" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.importFile" }}</strong></td>
<td><a href="{{ RootURL }}/subscribers/import">{{ .Name }}</a></td> <td><a href="{{ RootURL }}/subscribers/import">{{ .Name }}</a></td>
</tr> </tr>
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.status" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.status" }}</strong></td>
<td>{{ .Status }}</td> <td>{{ .Status }}</td>
</tr> </tr>
<tr> <tr>
<td width="30%"><strong>{{ .L.T "email.status.importRecords" }}</strong></td> <td width="30%"><strong>{{ L.Ts "email.status.importRecords" }}</strong></td>
<td>{{ .Imported }} / {{ .Total }}</td> <td>{{ .Imported }} / {{ .Total }}</td>
</tr> </tr>
</table> </table>

View File

@ -1,8 +1,8 @@
{{ define "subscriber-data" }} {{ define "subscriber-data" }}
{{ template "header" . }} {{ template "header" . }}
<h2>{{ .L.T "email.data.title" }}</h2> <h2>{{ L.Ts "email.data.title" }}</h2>
<p> <p>
{{ .L.T "email.data.info" }} {{ L.Ts "email.data.info" }}
</p> </p>
{{ template "footer" }} {{ template "footer" }}
{{ end }} {{ end }}

View File

@ -1,17 +1,17 @@
{{ define "optin-campaign" }} {{ define "optin-campaign" }}
<p>{{ .L.Ts "email.optin.confirmSubWelcome" "name" .Subscriber.FirstName }}</p> <p>{{ L.Ts "email.optin.confirmSubWelcome" "name" .Subscriber.FirstName }}</p>
<p>{{ .L.T "email.optin.confirmSubInfo" }}</p> <p>{{ L.Ts "email.optin.confirmSubInfo" }}</p>
<ul> <ul>
{{ range $i, $l := .Lists }} {{ range $i, $l := .Lists }}
{{ if eq .Type "public" }} {{ if eq .Type "public" }}
<li>{{ .Name }}</li> <li>{{ .Name }}</li>
{{ else }} {{ else }}
<li>{{ .L.T "email.optin.privateList" }}</li> <li>{{ L.Ts "email.optin.privateList" }}</li>
{{ end }} {{ end }}
{{ end }} {{ end }}
</ul> </ul>
<p> <p>
<a class="button" {{ .OptinURLAttr }} class="button">{{ .L.T "email.optin.confirmSub" }}</a> <a class="button" {{ .OptinURLAttr }} class="button">{{ L.Ts "email.optin.confirmSub" }}</a>
</p> </p>
{{ end }} {{ end }}

View File

@ -1,20 +1,20 @@
{{ define "subscriber-optin" }} {{ define "subscriber-optin" }}
{{ template "header" . }} {{ template "header" . }}
<h2>{{ .L.T "email.optin.confirmSubTitle" }}</h2> <h2>{{ L.Ts "email.optin.confirmSubTitle" }}</h2>
<p>{{ .L.Ts "email.optin.confirmSubWelcome" "name" .Subscriber.FirstName }}</p> <p>{{ L.Ts "email.optin.confirmSubWelcome" "name" .Subscriber.FirstName }}</p>
<p>{{ .L.T "email.optin.confirmSubInfo" }}</p> <p>{{ L.Ts "email.optin.confirmSubInfo" }}</p>
<ul> <ul>
{{ range $i, $l := .Lists }} {{ range $i, $l := .Lists }}
{{ if eq .Type "public" }} {{ if eq .Type "public" }}
<li>{{ .Name }}</li> <li>{{ .Name }}</li>
{{ else }} {{ else }}
<li>{{ .L.T "email.optin.privateList" }}</li> <li>{{ L.Ts "email.optin.privateList" }}</li>
{{ end }} {{ end }}
{{ end }} {{ end }}
</ul> </ul>
<p>{{ .L.T "email.optin.confirmSubHelp" }}</p> <p>{{ L.Ts "email.optin.confirmSubHelp" }}</p>
<p> <p>
<a href="{{ .OptinURL }}" class="button">{{ .L.T "email.optin.confirmSub" }}</a> <a href="{{ .OptinURL }}" class="button">{{ L.Ts "email.optin.confirmSub" }}</a>
</p> </p>
{{ template "footer" }} {{ template "footer" }}

View File

@ -1,26 +1,26 @@
{{ define "optin" }} {{ define "optin" }}
{{ template "header" .}} {{ template "header" .}}
<section> <section>
<h2>{{ .L.T "public.confirmSubTitle" }}</h2> <h2>{{ L.T "public.confirmSubTitle" }}</h2>
<p> <p>
{{ .L.T "public.confirmSubInfo" }} {{ L.T "public.confirmSubInfo" }}
</p> </p>
<form method="post"> <form method="post">
<ul> <ul>
{{ range $i, $l := .Data.Lists }} {{ range $i, $l := .Data.Lists }}
<input type="hidden" name="l" value="{{ $l.UUID }}" /> <input type="hidden" name="l" value="{{ $l.UUID }}" />
{{ if eq $.L.Type "public" }} {{ if eq $l.Type "public" }}
<li>{{ $l.Name }}</li> <li>{{ $l.Name }}</li>
{{ else }} {{ else }}
<li>{{ .L.T "public.subPrivateList" }}</li> <li>{{ L.Ts "public.subPrivateList" }}</li>
{{ end }} {{ end }}
{{ end }} {{ end }}
</ul> </ul>
<p> <p>
<input type="hidden" name="confirm" value="true" /> <input type="hidden" name="confirm" value="true" />
<button type="submit" class="button" id="btn-unsub"> <button type="submit" class="button" id="btn-unsub">
{{ .L.T "public.confirmSub" }} {{ L.Ts "public.confirmSub" }}
</button> </button>
</p> </p>
</form> </form>

View File

@ -1,18 +1,19 @@
{{ define "subscription" }} {{ define "subscription" }}
{{ template "header" .}} {{ template "header" .}}
<section> <section>
<h2>Unsubscribe</h2> <h2>{{ L.T "public.unsubTitle" }}</h2>
<p>Do you wish to unsubscribe from this mailing list?</p> <p>{{ L.T "public.unsubHelp" }}</p>
<form method="post"> <form method="post">
<div> <div>
{{ if .Data.AllowBlocklist }} {{ if .Data.AllowBlocklist }}
<p> <p>
<input id="privacy-blocklist" type="checkbox" name="blocklist" value="true" /> <label for="privacy-blocklist">Also unsubscribe from all future e-mails.</label> <input id="privacy-blocklist" type="checkbox" name="blocklist" value="true" />
<label for="privacy-blocklist">{{ L.T "public.unsubFull" }}</label>
</p> </p>
{{ end }} {{ end }}
<p> <p>
<button type="submit" class="button" id="btn-unsub">Unsubscribe</button> <button type="submit" class="button" id="btn-unsub">{{ L.T "public.unsub" }}</button>
</p> </p>
</div> </div>
</form> </form>
@ -21,16 +22,16 @@
{{ if or .Data.AllowExport .Data.AllowWipe }} {{ if or .Data.AllowExport .Data.AllowWipe }}
<form id="data-form" method="post" action="" onsubmit="return handleData()"> <form id="data-form" method="post" action="" onsubmit="return handleData()">
<section> <section>
<h2>Privacy and data</h2> <h2>{{ L.T "public.privacyTitle" }}</h2>
{{ if .Data.AllowExport }} {{ if .Data.AllowExport }}
<div class="row"> <div class="row">
<div class="one columns"> <div class="one columns">
<input id="privacy-export" type="radio" name="data-action" value="export" required /> <input id="privacy-export" type="radio" name="data-action" value="export" required />
</div> </div>
<div class="ten columns"> <div class="ten columns">
<label for="privacy-export"><strong>Export your data</strong></label> <label for="privacy-export"><strong>{{ L.T "public.privacyExport" }}</strong></label>
<br /> <br />
A copy of your data will be e-mailed to you. {{ L.T "public.privacyExportHelp" }}
</div> </div>
</div> </div>
{{ end }} {{ end }}
@ -41,14 +42,14 @@
<input id="privacy-wipe" type="radio" name="data-action" value="wipe" required /> <input id="privacy-wipe" type="radio" name="data-action" value="wipe" required />
</div> </div>
<div class="ten columns"> <div class="ten columns">
<label for="privacy-wipe"><strong>Wipe your data</strong></label> <label for="privacy-wipe"><strong>{{ L.T "public.privacyWipe" }}</strong></label>
<br /> <br />
Delete all your subscriptions and related data from our database permanently. {{ L.T "public.privacyWipeHelp" }}
</div> </div>
</div> </div>
{{ end }} {{ end }}
<p> <p>
<input type="submit" value="Continue" class="button button-outline" /> <input type="submit" value="{{ L.T "globals.buttons.continue" }}" class="button button-outline" />
</p> </p>
</section> </section>
</form> </form>
@ -59,7 +60,7 @@
if (a == "export") { if (a == "export") {
f.action = "/subscription/export/{{ .Data.SubUUID }}"; f.action = "/subscription/export/{{ .Data.SubUUID }}";
return true; return true;
} else if (confirm("Are you sure you want to delete all your subscription data permanently?")) { } else if (confirm("{{ L.T "public.privacyConfirmWipe" }}")) {
f.action = "/subscription/wipe/{{ .Data.SubUUID }}"; f.action = "/subscription/wipe/{{ .Data.SubUUID }}";
return true; return true;
} }