1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-10-18 09:00:11 +00:00

Compare commits

...

6 Commits

Author SHA1 Message Date
d51a6abb02
remove cl.md 2021-04-07 17:45:31 +01:00
374ffbf01f
fix incomplete lang patching, add en-gb stub
en-gb is empty, so it's patched with en-us strings. Added so DD/MM/YY
date formatting was possible in the ui.
2021-04-07 17:42:15 +01:00
871bc9f396
use proper date formatting on form for expiry 2021-04-07 15:17:15 +01:00
66b7df7cde
use selected language for time format, add manual selector
You can now choose between 12h and 24h time in the top left language
menu. Your preference is stored by the browser for future visits.
2021-04-07 15:09:44 +01:00
bc76770ca4
move 12h/24h time strings to common 2021-04-07 15:09:25 +01:00
7196361cf6
(hopefully) get proper locale from browser 2021-04-07 14:05:17 +01:00
33 changed files with 128 additions and 45 deletions

1
.gitignore vendored
View File

@ -13,3 +13,4 @@ server.key
server.pem server.pem
server.crt server.crt
instructions-debian.txt instructions-debian.txt
cl.md

View File

@ -276,7 +276,16 @@
<span class="ml-1 chev"></span> <span class="ml-1 chev"></span>
</span> </span>
<div class="dropdown-display"> <div class="dropdown-display">
<div class="card ~neutral !low" id="lang-list"> <div class="card ~neutral !low">
<label class="switch pb-1">
<input type="radio" name="lang-time" id="lang-12h">
<span>{{ .strings.time12h }}</span>
</label>
<label class="switch pb-1">
<input type="radio" name="lang-time" id="lang-24h">
<span>{{ .strings.time24h }}</span>
</label>
<div id="lang-list"></div>
</div> </div>
</div> </div>
</span> </span>

View File

@ -5,6 +5,7 @@
window.invalidPassword = "{{ .strings.reEnterPasswordInvalid }}"; window.invalidPassword = "{{ .strings.reEnterPasswordInvalid }}";
window.URLBase = "{{ .urlBase }}"; window.URLBase = "{{ .urlBase }}";
window.code = "{{ .code }}"; window.code = "{{ .code }}";
window.language = "{{ .langName }}";
window.messages = JSON.parse({{ .notifications }}); window.messages = JSON.parse({{ .notifications }});
window.confirmation = {{ .confirmation }}; window.confirmation = {{ .confirmation }};
window.userExpiryEnabled = {{ .userExpiry }}; window.userExpiryEnabled = {{ .userExpiry }};

View File

@ -266,10 +266,10 @@
</label> </label>
<div> <div>
<label class="row switch pb-1"> <label class="row switch pb-1">
<input type="radio" name="email-24h" value="true" checked><span>{{ .lang.Email.time24h }}</span> <input type="radio" name="email-24h" value="true" checked><span>{{ .lang.Strings.time24h }}</span>
</label> </label>
<label class="row switch pb-1"> <label class="row switch pb-1">
<input type="radio" name="email-24h" value="false"><span>{{ .lang.Email.time12h }}</span> <input type="radio" name="email-24h" value="false"><span>{{ .lang.Strings.time12h }}</span>
</label> </label>
</div> </div>
</div> </div>

5
lang/admin/en-gb.json Normal file
View File

@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@ -12,6 +12,8 @@
"error": "Fehler", "error": "Fehler",
"copy": "Kopieren", "copy": "Kopieren",
"theme": "Thema", "theme": "Thema",
"time24h": "24h-Format",
"time12h": "12h-Format",
"copied": "Kopiert" "copied": "Kopiert"
} }
} }

View File

@ -12,6 +12,8 @@
"error": "Σφάλμα", "error": "Σφάλμα",
"copy": "Αντιγραφή", "copy": "Αντιγραφή",
"theme": "Θέμα", "theme": "Θέμα",
"time24h": "24 Ώρες",
"time12h": "12 Ώρες",
"copied": "Αντιγράφηκε" "copied": "Αντιγράφηκε"
} }
} }

5
lang/common/en-gb.json Normal file
View File

@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@ -12,6 +12,8 @@
"error": "Error", "error": "Error",
"copy": "Copy", "copy": "Copy",
"copied": "Copied", "copied": "Copied",
"time24h": "24h Time",
"time12h": "12h Time",
"theme": "Theme" "theme": "Theme"
} }
} }

View File

@ -12,6 +12,8 @@
"success": "Succès", "success": "Succès",
"error": "Erreur", "error": "Erreur",
"copy": "Copier", "copy": "Copier",
"time24h": "Temps 24h",
"time12h": "Temps 12h",
"theme": "Thème" "theme": "Thème"
} }
} }

View File

@ -11,6 +11,8 @@
"success": "Sukses", "success": "Sukses",
"error": "Error", "error": "Error",
"copy": "Salin", "copy": "Salin",
"time24h": "Waktu 24 jam",
"time12h": "Waktu 12 jam",
"theme": "Tema" "theme": "Tema"
} }
} }

View File

@ -12,6 +12,8 @@
"error": "Fout", "error": "Fout",
"copy": "Kopiëer", "copy": "Kopiëer",
"theme": "Thema", "theme": "Thema",
"time24h": "24u-formaat",
"time12h": "12u-formaat",
"copied": "Gekopieerd" "copied": "Gekopieerd"
} }
} }

View File

@ -12,6 +12,8 @@
"error": "Erro", "error": "Erro",
"copy": "Copiar", "copy": "Copiar",
"theme": "Tema", "theme": "Tema",
"time24h": "Horário 24h",
"time12h": "Horário 12h",
"copied": "Copiado" "copied": "Copiado"
} }
} }

View File

@ -11,6 +11,8 @@
"success": "Lyckades", "success": "Lyckades",
"error": "Fel", "error": "Fel",
"copy": "Kopiera", "copy": "Kopiera",
"time24h": "24 timmarsklocka",
"time12h": "12 timmarsklocka",
"theme": "Tema" "theme": "Tema"
} }
} }

5
lang/email/en-gb.json Normal file
View File

@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

5
lang/form/en-gb.json Normal file
View File

@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@ -82,8 +82,6 @@
"senderName": "Absendername", "senderName": "Absendername",
"dateFormat": "Datumsformat", "dateFormat": "Datumsformat",
"dateFormatNotice": "Datum folgt dem strftime-Format. Für weitere Informationen, besuche {n}.", "dateFormatNotice": "Datum folgt dem strftime-Format. Für weitere Informationen, besuche {n}.",
"time24h": "24h-Format",
"time12h": "12h-Format",
"encryption": "Verschlüsselung", "encryption": "Verschlüsselung",
"mailgunApiURL": "API-URL" "mailgunApiURL": "API-URL"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Ονομα αποστολέα", "senderName": "Ονομα αποστολέα",
"dateFormat": "Μορφή ημερομηνίας", "dateFormat": "Μορφή ημερομηνίας",
"dateFormatNotice": "Η ημερομηνία ακολουθεί τη μορφή strftime. Για περισσότερες πληροφορίες, επισκεφτείτε το {n}.", "dateFormatNotice": "Η ημερομηνία ακολουθεί τη μορφή strftime. Για περισσότερες πληροφορίες, επισκεφτείτε το {n}.",
"time24h": "24 Ώρες",
"time12h": "12 Ώρες",
"encryption": "Κρυπτογράφηση", "encryption": "Κρυπτογράφηση",
"mailgunApiURL": "Διεύθυνση API" "mailgunApiURL": "Διεύθυνση API"
}, },

5
lang/setup/en-gb.json Normal file
View File

@ -0,0 +1,5 @@
{
"meta": {
"name": "English (GB)"
}
}

View File

@ -89,8 +89,6 @@
"senderName": "Sender Name", "senderName": "Sender Name",
"dateFormat": "Date Format", "dateFormat": "Date Format",
"dateFormatNotice": "Date follows the strftime format. For more info, visit {n}.", "dateFormatNotice": "Date follows the strftime format. For more info, visit {n}.",
"time24h": "24h Time",
"time12h": "12h Time",
"encryption": "Encryption", "encryption": "Encryption",
"mailgunApiURL": "API URL" "mailgunApiURL": "API URL"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Nom de l'envoyeur", "senderName": "Nom de l'envoyeur",
"dateFormat": "Format de la date", "dateFormat": "Format de la date",
"dateFormatNotice": "La date suis le format srtftime. Pour plus d'informations, consultez {n}.", "dateFormatNotice": "La date suis le format srtftime. Pour plus d'informations, consultez {n}.",
"time24h": "Temps 24h",
"time12h": "Temps 12h",
"encryption": "Chiffrement", "encryption": "Chiffrement",
"mailgunApiURL": "URL de l'API" "mailgunApiURL": "URL de l'API"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Nama Pengirim", "senderName": "Nama Pengirim",
"dateFormat": "Format Tanggal", "dateFormat": "Format Tanggal",
"dateFormatNotice": "Tanggal mengikuti format strftime. Untuk info lebih lanjut, kunjungi {n}.", "dateFormatNotice": "Tanggal mengikuti format strftime. Untuk info lebih lanjut, kunjungi {n}.",
"time24h": "Waktu 24 jam",
"time12h": "Waktu 12 jam",
"encryption": "Enkripsi", "encryption": "Enkripsi",
"mailgunApiURL": "URL API" "mailgunApiURL": "URL API"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Naam afzender", "senderName": "Naam afzender",
"dateFormat": "Datumformaat", "dateFormat": "Datumformaat",
"dateFormatNotice": "Datum volgend het strftime formaat. Meer info op {n}.", "dateFormatNotice": "Datum volgend het strftime formaat. Meer info op {n}.",
"time24h": "24u-formaat",
"time12h": "12u-formaat",
"encryption": "Versleuteling", "encryption": "Versleuteling",
"mailgunApiURL": "API-URL" "mailgunApiURL": "API-URL"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Nome do remetente", "senderName": "Nome do remetente",
"dateFormat": "Formato da Data", "dateFormat": "Formato da Data",
"dateFormatNotice": "A data segue o formato strftime. Para obter mais informações, visite {n}.", "dateFormatNotice": "A data segue o formato strftime. Para obter mais informações, visite {n}.",
"time24h": "Horário 24h",
"time12h": "Horário 12h",
"encryption": "Encriptação", "encryption": "Encriptação",
"mailgunApiURL": "API URL" "mailgunApiURL": "API URL"
}, },

View File

@ -82,8 +82,6 @@
"senderName": "Avsändarens namn", "senderName": "Avsändarens namn",
"dateFormat": "Datumformat", "dateFormat": "Datumformat",
"dateFormatNotice": "Datum följer strftime-formatet. Mer information finns på {n}.", "dateFormatNotice": "Datum följer strftime-formatet. Mer information finns på {n}.",
"time24h": "24 timmarsklocka",
"time12h": "12 timmarsklocka",
"encryption": "Kryptering", "encryption": "Kryptering",
"mailgunApiURL": "API URL" "mailgunApiURL": "API URL"
}, },

View File

@ -144,11 +144,14 @@ func patchLang(english, other *langSection) {
} }
func patchQuantityStrings(english, other *map[string]quantityString) { func patchQuantityStrings(english, other *map[string]quantityString) {
if *other == nil {
*other = map[string]quantityString{}
}
for n, ev := range *english { for n, ev := range *english {
qs, ok := (*other)[n] qs, ok := (*other)[n]
if !ok { if !ok {
(*other)[n] = ev (*other)[n] = ev
return continue
} else if qs.Singular == "" { } else if qs.Singular == "" {
qs.Singular = ev.Singular qs.Singular = ev.Singular
} else if (*other)[n].Plural == "" { } else if (*other)[n].Plural == "" {
@ -429,6 +432,8 @@ func (st *Storage) loadLangEmail(filesystems ...fs.FS) error {
patchLang(&english.UserDeleted, &lang.UserDeleted) patchLang(&english.UserDeleted, &lang.UserDeleted)
patchLang(&english.InviteEmail, &lang.InviteEmail) patchLang(&english.InviteEmail, &lang.InviteEmail)
patchLang(&english.WelcomeEmail, &lang.WelcomeEmail) patchLang(&english.WelcomeEmail, &lang.WelcomeEmail)
patchLang(&english.EmailConfirmation, &lang.EmailConfirmation)
patchLang(&english.UserExpired, &lang.UserExpired)
} }
st.lang.Email[index] = lang st.lang.Email[index] = lang
return nil return nil

View File

@ -1,5 +1,5 @@
import { Modal } from "./modules/modal.js"; import { Modal } from "./modules/modal.js";
import { _get, _post, toggleLoader } from "./modules/common.js"; import { _get, _post, toggleLoader, toDateString } from "./modules/common.js";
import { loadLangSelector } from "./modules/lang.js"; import { loadLangSelector } from "./modules/lang.js";
interface formWindow extends Window { interface formWindow extends Window {
@ -46,7 +46,7 @@ if (window.userExpiryEnabled) {
time.setDate(time.getDate() + window.userExpiryDays); time.setDate(time.getDate() + window.userExpiryDays);
time.setHours(time.getHours() + window.userExpiryHours); time.setHours(time.getHours() + window.userExpiryHours);
time.setMinutes(time.getMinutes() + window.userExpiryMinutes); time.setMinutes(time.getMinutes() + window.userExpiryMinutes);
messageEl.textContent = window.userExpiryMessage.replace("{date}", time.toDateString() + " " + time.toLocaleTimeString()); messageEl.textContent = window.userExpiryMessage.replace("{date}", toDateString(time));
setTimeout(calculateTime, 1000); setTimeout(calculateTime, 1000);
}; };
calculateTime(); calculateTime();

View File

@ -83,7 +83,7 @@ class user implements User {
set last_active(unix: number) { set last_active(unix: number) {
this._lastActiveUnix = unix; this._lastActiveUnix = unix;
if (unix == 0) { if (unix == 0) {
this._lastActive.textContent == ""; this._lastActive.textContent == "n/a";
} else { } else {
this._lastActive.textContent = toDateString(new Date(unix*1000)); this._lastActive.textContent = toDateString(new Date(unix*1000));
} }
@ -142,6 +142,11 @@ class user implements User {
}; };
this.update(user); this.update(user);
document.addEventListener("timefmt-change", () => {
this.expiry = this.expiry;
this.last_active = this.last_active;
});
} }
private _updateEmail = () => { private _updateEmail = () => {

View File

@ -7,10 +7,24 @@ export function createEl(html: string): HTMLElement {
} }
export function toDateString(date: Date): string { export function toDateString(date: Date): string {
return date.toLocaleDateString() + " " + date.toLocaleString([], { const locale = window.language || (window as any).navigator.userLanguage || window.navigator.language;
const t12 = document.getElementById("lang-12h") as HTMLInputElement;
const t24 = document.getElementById("lang-24h") as HTMLInputElement;
let args1 = {};
let args2 = {
hour: "2-digit", hour: "2-digit",
minute: "2-digit" minute: "2-digit"
}) };
if (t12 && t24) {
if (t12.checked) {
args1["hour12"] = true;
args2["hour12"] = true;
} else if (t24.checked) {
args1["hour12"] = false;
args2["hour12"] = false;
}
}
return date.toLocaleDateString(locale, args1) + " " + date.toLocaleString(locale, args2);
} }
export function serializeForm(id: string): Object { export function serializeForm(id: string): Object {

View File

@ -363,6 +363,10 @@ export class DOMInvite implements Invite {
this.update(invite); this.update(invite);
document.addEventListener("profileLoadEvent", () => { this.loadProfiles(); }, false); document.addEventListener("profileLoadEvent", () => { this.loadProfiles(); }, false);
document.addEventListener("timefmt-change", () => {
this.created = this.created;
this.usedBy = this.usedBy;
});
} }
update = (invite: Invite) => { update = (invite: Invite) => {

View File

@ -47,21 +47,39 @@ export class lang implements Lang {
} }
} }
export const loadLangSelector = (page: string) => _get("/lang/" + page, null, (req: XMLHttpRequest) => { export const loadLangSelector = (page: string) => {
if (req.readyState == 4) { if (page == "admin") {
if (req.status != 200) { const ev = new CustomEvent("timefmt-change");
document.getElementById("lang-dropdown").remove(); const setTimefmt = (fmt: string) => {
return; document.dispatchEvent(ev);
localStorage.setItem("timefmt", fmt);
};
const t12 = document.getElementById("lang-12h") as HTMLInputElement;
t12.onchange = () => setTimefmt("12h");
const t24 = document.getElementById("lang-24h") as HTMLInputElement;
t24.onchange = () => setTimefmt("24h");
const preference = localStorage.getItem("timefmt");
if (preference == "12h") {
t12.checked = true;
t24.checked = false;
} else if (preference == "24h") {
t24.checked = true;
t12.checked = false;
} }
const list = document.getElementById("lang-list") as HTMLDivElement;
let innerHTML = '';
for (let code in req.response) {
innerHTML += `<a href="?lang=${code}" class="button input ~neutral field mb-half lang-link">${req.response[code]}</a>`;
}
list.innerHTML = innerHTML;
} }
}); _get("/lang/" + page, null, (req: XMLHttpRequest) => {
if (req.readyState == 4) {
if (req.status != 200) {
document.getElementById("lang-dropdown").remove();
return;
}
const list = document.getElementById("lang-list") as HTMLDivElement;
let innerHTML = '';
for (let code in req.response) {
innerHTML += `<a href="?lang=${code}" class="button input ~neutral field mb-half lang-link">${req.response[code]}</a>`;
}
list.innerHTML = innerHTML;
}
});
};

View File

@ -8,7 +8,7 @@ interface updateDTO {
export class Updater implements updater { export class Updater implements updater {
private _update: Update; private _update: Update;
private _date: Date; private _date: number;
updateAvailable = false; updateAvailable = false;
checkForUpdates = (run?: (req: XMLHttpRequest) => void) => _get("/config/update", null, (req: XMLHttpRequest) => { checkForUpdates = (run?: (req: XMLHttpRequest) => void) => _get("/config/update", null, (req: XMLHttpRequest) => {
@ -26,10 +26,10 @@ export class Updater implements updater {
} }
} }
}); });
get date(): number { return Math.floor(this._date.getTime() / 1000); } get date(): number { return this._date; }
set date(unix: number) { set date(unix: number) {
this._date = new Date(unix * 1000); this._date = unix;
document.getElementById("update-date").textContent = toDateString(this._date); document.getElementById("update-date").textContent = toDateString(new Date(this._date * 1000));
} }
get description(): string { return this._update.description; } get description(): string { return this._update.description; }

View File

@ -221,6 +221,7 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
"userExpiryHours": inv.UserHours, "userExpiryHours": inv.UserHours,
"userExpiryMinutes": inv.UserMinutes, "userExpiryMinutes": inv.UserMinutes,
"userExpiryMessage": app.storage.lang.Form[lang].Strings.get("yourAccountIsValidUntil"), "userExpiryMessage": app.storage.lang.Form[lang].Strings.get("yourAccountIsValidUntil"),
"langName": lang,
}) })
} }