mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-11-09 20:00:12 +00:00
Compare commits
6 Commits
d3c5feaf1b
...
609039baeb
Author | SHA1 | Date | |
---|---|---|---|
609039baeb | |||
03f1a3dbc0 | |||
75dc9d4d1d | |||
5beeeb958b | |||
a22f032924 | |||
3e034c85d6 |
@ -336,6 +336,10 @@ func (app *appContext) SetContactMethods(gc *gin.Context) {
|
|||||||
respondBool(400, false, gc)
|
respondBool(400, false, gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
app.setContactMethods(req, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *appContext) setContactMethods(req SetContactMethodsDTO, gc *gin.Context) {
|
||||||
if tgUser, ok := app.storage.telegram[req.ID]; ok {
|
if tgUser, ok := app.storage.telegram[req.ID]; ok {
|
||||||
change := tgUser.Contact != req.Telegram
|
change := tgUser.Contact != req.Telegram
|
||||||
tgUser.Contact = req.Telegram
|
tgUser.Contact = req.Telegram
|
||||||
|
238
api-userpage.go
238
api-userpage.go
@ -1,6 +1,14 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/gin-gonic/gin"
|
import (
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt"
|
||||||
|
)
|
||||||
|
|
||||||
// @Summary Returns the logged-in user's Jellyfin ID & Username.
|
// @Summary Returns the logged-in user's Jellyfin ID & Username.
|
||||||
// @Produce json
|
// @Produce json
|
||||||
@ -19,6 +27,234 @@ func (app *appContext) MyDetails(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
resp.Username = user.Name
|
resp.Username = user.Name
|
||||||
|
resp.Admin = user.Policy.IsAdministrator
|
||||||
|
resp.Disabled = user.Policy.IsDisabled
|
||||||
|
|
||||||
|
if exp, ok := app.storage.users[user.ID]; ok {
|
||||||
|
resp.Expiry = exp.Unix()
|
||||||
|
}
|
||||||
|
|
||||||
|
app.storage.loadEmails()
|
||||||
|
app.storage.loadDiscordUsers()
|
||||||
|
app.storage.loadMatrixUsers()
|
||||||
|
app.storage.loadTelegramUsers()
|
||||||
|
|
||||||
|
if emailEnabled {
|
||||||
|
resp.Email = &MyDetailsContactMethodsDTO{}
|
||||||
|
if email, ok := app.storage.emails[user.ID]; ok && email.Addr != "" {
|
||||||
|
resp.Email.Value = email.Addr
|
||||||
|
resp.Email.Enabled = email.Contact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if discordEnabled {
|
||||||
|
resp.Discord = &MyDetailsContactMethodsDTO{}
|
||||||
|
if discord, ok := app.storage.discord[user.ID]; ok {
|
||||||
|
resp.Discord.Value = RenderDiscordUsername(discord)
|
||||||
|
resp.Discord.Enabled = discord.Contact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if telegramEnabled {
|
||||||
|
resp.Telegram = &MyDetailsContactMethodsDTO{}
|
||||||
|
if telegram, ok := app.storage.telegram[user.ID]; ok {
|
||||||
|
resp.Telegram.Value = telegram.Username
|
||||||
|
resp.Telegram.Enabled = telegram.Contact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matrixEnabled {
|
||||||
|
resp.Matrix = &MyDetailsContactMethodsDTO{}
|
||||||
|
if matrix, ok := app.storage.matrix[user.ID]; ok {
|
||||||
|
resp.Matrix.Value = matrix.UserID
|
||||||
|
resp.Matrix.Enabled = matrix.Contact
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gc.JSON(200, resp)
|
gc.JSON(200, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Sets whether to notify yourself through telegram/discord/matrix/email or not.
|
||||||
|
// @Produce json
|
||||||
|
// @Param SetContactMethodsDTO body SetContactMethodsDTO true "User's Jellyfin ID and whether or not to notify then through Telegram."
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Success 400 {object} boolResponse
|
||||||
|
// @Success 500 {object} boolResponse
|
||||||
|
// @Router /my/contact [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags User Page
|
||||||
|
func (app *appContext) SetMyContactMethods(gc *gin.Context) {
|
||||||
|
var req SetContactMethodsDTO
|
||||||
|
gc.BindJSON(&req)
|
||||||
|
req.ID = gc.GetString("jfId")
|
||||||
|
if req.ID == "" {
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.setContactMethods(req, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Logout by deleting refresh token from cookies.
|
||||||
|
// @Produce json
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /my/logout [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags User Page
|
||||||
|
func (app *appContext) LogoutUser(gc *gin.Context) {
|
||||||
|
cookie, err := gc.Cookie("user-refresh")
|
||||||
|
if err != nil {
|
||||||
|
app.debug.Printf("Couldn't get cookies: %s", err)
|
||||||
|
respond(500, "Couldn't fetch cookies", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.invalidTokens = append(app.invalidTokens, cookie)
|
||||||
|
gc.SetCookie("refresh", "invalid", -1, "/my", gc.Request.URL.Hostname(), true, true)
|
||||||
|
respondBool(200, true, gc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary confirm an action (e.g. changing an email address.)
|
||||||
|
// @Produce json
|
||||||
|
// @Param jwt path string true "jwt confirmation code"
|
||||||
|
// @Router /my/confirm/{jwt} [post]
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} stringResponse
|
||||||
|
// @Failure 404
|
||||||
|
// @Success 303
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @tags User Page
|
||||||
|
func (app *appContext) ConfirmMyAction(gc *gin.Context) {
|
||||||
|
app.confirmMyAction(gc, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
|
||||||
|
var claims jwt.MapClaims
|
||||||
|
var target ConfirmationTarget
|
||||||
|
var id string
|
||||||
|
fail := func() {
|
||||||
|
gcHTML(gc, 404, "404.html", gin.H{
|
||||||
|
"cssClass": app.cssClass,
|
||||||
|
"cssVersion": cssVersion,
|
||||||
|
"contactMessage": app.config.Section("ui").Key("contact_message").String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate key
|
||||||
|
if key == "" {
|
||||||
|
key = gc.Param("jwt")
|
||||||
|
}
|
||||||
|
token, err := jwt.Parse(key, checkToken)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to parse key: %s", err)
|
||||||
|
fail()
|
||||||
|
// respond(500, "unknownError", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
claims, ok := token.Claims.(jwt.MapClaims)
|
||||||
|
if !ok {
|
||||||
|
app.err.Printf("Failed to parse key: %s", err)
|
||||||
|
fail()
|
||||||
|
// respond(500, "unknownError", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
expiry := time.Unix(int64(claims["exp"].(float64)), 0)
|
||||||
|
if !(ok && token.Valid && claims["type"].(string) == "confirmation" && expiry.After(time.Now())) {
|
||||||
|
app.err.Printf("Invalid key")
|
||||||
|
fail()
|
||||||
|
// respond(400, "invalidKey", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
target = ConfirmationTarget(int(claims["target"].(float64)))
|
||||||
|
id = claims["id"].(string)
|
||||||
|
|
||||||
|
// Perform an Action
|
||||||
|
if target == NoOp {
|
||||||
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
|
return
|
||||||
|
} else if target == UserEmailChange {
|
||||||
|
emailStore, ok := app.storage.emails[id]
|
||||||
|
if !ok {
|
||||||
|
emailStore = EmailAddress{
|
||||||
|
Contact: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emailStore.Addr = claims["email"].(string)
|
||||||
|
app.storage.emails[id] = emailStore
|
||||||
|
if app.config.Section("ombi").Key("enabled").MustBool(false) {
|
||||||
|
ombiUser, code, err := app.getOmbiUser(id)
|
||||||
|
if code == 200 && err == nil {
|
||||||
|
ombiUser["emailAddress"] = claims["email"].(string)
|
||||||
|
code, err = app.ombi.ModifyUser(ombiUser)
|
||||||
|
if code != 200 || err != nil {
|
||||||
|
app.err.Printf("%s: Failed to change ombi email address (%d): %v", ombiUser["userName"].(string), code, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.storage.storeEmails()
|
||||||
|
app.info.Println("Email list modified")
|
||||||
|
gc.Redirect(http.StatusSeeOther, "/my/account")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Summary Modify your email address.
|
||||||
|
// @Produce json
|
||||||
|
// @Param ModifyMyEmailDTO body ModifyMyEmailDTO true "New email address."
|
||||||
|
// @Success 200 {object} boolResponse
|
||||||
|
// @Failure 400 {object} stringResponse
|
||||||
|
// @Failure 401 {object} stringResponse
|
||||||
|
// @Failure 500 {object} stringResponse
|
||||||
|
// @Router /my/email [post]
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Users
|
||||||
|
func (app *appContext) ModifyMyEmail(gc *gin.Context) {
|
||||||
|
var req ModifyMyEmailDTO
|
||||||
|
gc.BindJSON(&req)
|
||||||
|
app.debug.Println("Email modification requested")
|
||||||
|
if !strings.ContainsRune(req.Email, '@') {
|
||||||
|
respond(400, "Invalid Email Address", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
id := gc.GetString("jfId")
|
||||||
|
|
||||||
|
// We'll use the ConfirmMyAction route to do the work, even if we don't need to confirm the address.
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"valid": true,
|
||||||
|
"id": id,
|
||||||
|
"email": req.Email,
|
||||||
|
"type": "confirmation",
|
||||||
|
"target": UserEmailChange,
|
||||||
|
"exp": time.Now().Add(time.Hour).Unix(),
|
||||||
|
}
|
||||||
|
tk := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
key, err := tk.SignedString([]byte(os.Getenv("JFA_SECRET")))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to generate confirmation token: %v", err)
|
||||||
|
respond(500, "errorUnknown", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if emailEnabled && app.config.Section("email_confirmation").Key("enabled").MustBool(false) {
|
||||||
|
user, status, err := app.jf.UserByID(id, false)
|
||||||
|
name := ""
|
||||||
|
if status == 200 && err == nil {
|
||||||
|
name = user.Name
|
||||||
|
}
|
||||||
|
app.debug.Printf("%s: Email confirmation required", id)
|
||||||
|
respond(401, "confirmEmail", gc)
|
||||||
|
msg, err := app.email.constructConfirmation("", name, key, app, false)
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("%s: Failed to construct confirmation email: %v", name, err)
|
||||||
|
} else if err := app.email.send(msg, req.Email); err != nil {
|
||||||
|
app.err.Printf("%s: Failed to send user confirmation email: %v", name, err)
|
||||||
|
} else {
|
||||||
|
app.info.Printf("%s: Sent user confirmation email to \"%s\"", name, req.Email)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
app.confirmMyAction(gc, key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
11
auth.go
11
auth.go
@ -158,6 +158,11 @@ func (app *appContext) validateJellyfinCredentials(username, password string, gc
|
|||||||
respond(401, "Unauthorized", gc)
|
respond(401, "Unauthorized", gc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if status == 403 {
|
||||||
|
app.info.Println("Auth denied: Jellyfin account disabled")
|
||||||
|
respond(403, "yourAccountWasDisabled", gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
app.err.Printf("Auth failed: Couldn't authenticate with Jellyfin (%d/%s)", status, err)
|
app.err.Printf("Auth failed: Couldn't authenticate with Jellyfin (%d/%s)", status, err)
|
||||||
respond(500, "Jellyfin error", gc)
|
respond(500, "Jellyfin error", gc)
|
||||||
return
|
return
|
||||||
@ -232,9 +237,9 @@ func (app *appContext) getTokenLogin(gc *gin.Context) {
|
|||||||
gc.JSON(200, getTokenDTO{token})
|
gc.JSON(200, getTokenDTO{token})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) decodeValidateRefreshCookie(gc *gin.Context) (claims jwt.MapClaims, ok bool) {
|
func (app *appContext) decodeValidateRefreshCookie(gc *gin.Context, cookieName string) (claims jwt.MapClaims, ok bool) {
|
||||||
ok = false
|
ok = false
|
||||||
cookie, err := gc.Cookie("refresh")
|
cookie, err := gc.Cookie(cookieName)
|
||||||
if err != nil || cookie == "" {
|
if err != nil || cookie == "" {
|
||||||
app.debug.Printf("getTokenRefresh denied: Couldn't get token: %s", err)
|
app.debug.Printf("getTokenRefresh denied: Couldn't get token: %s", err)
|
||||||
respond(400, "Couldn't get token", gc)
|
respond(400, "Couldn't get token", gc)
|
||||||
@ -280,7 +285,7 @@ func (app *appContext) decodeValidateRefreshCookie(gc *gin.Context) (claims jwt.
|
|||||||
// @tags Auth
|
// @tags Auth
|
||||||
func (app *appContext) getTokenRefresh(gc *gin.Context) {
|
func (app *appContext) getTokenRefresh(gc *gin.Context) {
|
||||||
app.debug.Println("Token requested (refresh token)")
|
app.debug.Println("Token requested (refresh token)")
|
||||||
claims, ok := app.decodeValidateRefreshCookie(gc)
|
claims, ok := app.decodeValidateRefreshCookie(gc, "refresh")
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
10
email.go
10
email.go
@ -10,6 +10,7 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -304,10 +305,17 @@ func (emailer *Emailer) confirmationValues(code, username, key string, app *appC
|
|||||||
} else {
|
} else {
|
||||||
message := app.config.Section("messages").Key("message").String()
|
message := app.config.Section("messages").Key("message").String()
|
||||||
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
inviteLink := app.config.Section("invite_emails").Key("url_base").String()
|
||||||
|
if code == "" { // Personal email change
|
||||||
|
if strings.HasSuffix(inviteLink, "/invite") {
|
||||||
|
inviteLink = strings.TrimSuffix(inviteLink, "/invite")
|
||||||
|
}
|
||||||
|
inviteLink = fmt.Sprintf("%s/my/confirm/%s", inviteLink, url.PathEscape(key))
|
||||||
|
} else { // Invite email confirmation
|
||||||
if !strings.HasSuffix(inviteLink, "/invite") {
|
if !strings.HasSuffix(inviteLink, "/invite") {
|
||||||
inviteLink += "/invite"
|
inviteLink += "/invite"
|
||||||
}
|
}
|
||||||
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, key)
|
inviteLink = fmt.Sprintf("%s/%s?key=%s", inviteLink, code, url.PathEscape(key))
|
||||||
|
}
|
||||||
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
template["helloUser"] = emailer.lang.Strings.template("helloUser", tmpl{"username": username})
|
||||||
template["confirmationURL"] = inviteLink
|
template["confirmationURL"] = inviteLink
|
||||||
template["message"] = message
|
template["message"] = message
|
||||||
|
@ -17,6 +17,22 @@
|
|||||||
<title>{{ .lang.Strings.pageTitle }}</title>
|
<title>{{ .lang.Strings.pageTitle }}</title>
|
||||||
</head>
|
</head>
|
||||||
<body class="max-w-full overflow-x-hidden section">
|
<body class="max-w-full overflow-x-hidden section">
|
||||||
|
<div id="modal-email" class="modal">
|
||||||
|
<div class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3">
|
||||||
|
<div class="content">
|
||||||
|
<span class="heading mb-4 my-2"></span>
|
||||||
|
<label class="label supra row m-1" for="modal-email-input">{{ .strings.emailAddress }}</label>
|
||||||
|
<div class="row">
|
||||||
|
<input type="email" class="col sm field ~neutral @low input" id="modal-email-input" placeholder="{{ .strings.emailAddress }}">
|
||||||
|
</div>
|
||||||
|
<button class="button ~urge @low supra full-width center lg my-2 modal-submit">{{ .strings.submit }}</button>
|
||||||
|
</div>
|
||||||
|
<div class="confirmation-required unfocused">
|
||||||
|
<span class="heading mb-4">{{ .strings.confirmationRequired }} <span class="modal-close">×</span></span>
|
||||||
|
<p class="content mb-4">{{ .strings.confirmationRequiredMessage }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div id="notification-box"></div>
|
<div id="notification-box"></div>
|
||||||
<div class="top-4 left-4 absolute">
|
<div class="top-4 left-4 absolute">
|
||||||
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
<span class="dropdown" tabindex="0" id="lang-dropdown">
|
||||||
@ -44,7 +60,18 @@
|
|||||||
{{ template "login-modal.html" . }}
|
{{ template "login-modal.html" . }}
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<div class="card @low dark:~d_neutral mb-4" id="card-user">
|
<div class="card @low dark:~d_neutral mb-4" id="card-user">
|
||||||
<span class="heading"></span>
|
<span class="heading mb-2"></span>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-2 gap-4">
|
||||||
|
<div class="card @low dark:~d_neutral unfocused" id="card-status">
|
||||||
|
<span class="heading mb-2">{{ .strings.expiry }}</span>
|
||||||
|
<aside class="aside ~warning user-expiry my-4"></aside>
|
||||||
|
<div class="user-expiry-countdown"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card @low dark:~d_neutral flex-col" id="card-contact">
|
||||||
|
<span class="heading mb-2">{{ .strings.contactMethods }}</span>
|
||||||
|
<div class="content flex justify-between flex-col h-100"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="{{ .urlBase }}/js/user.js" type="module"></script>
|
<script src="{{ .urlBase }}/js/user.js" type="module"></script>
|
||||||
|
2
lang.go
2
lang.go
@ -29,6 +29,7 @@ type commonLang struct {
|
|||||||
Meta langMeta `json:"meta"`
|
Meta langMeta `json:"meta"`
|
||||||
Strings langSection `json:"strings"`
|
Strings langSection `json:"strings"`
|
||||||
Notifications langSection `json:"notifications"`
|
Notifications langSection `json:"notifications"`
|
||||||
|
QuantityStrings map[string]quantityString `json:"quantityStrings"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type adminLang struct {
|
type adminLang struct {
|
||||||
@ -58,6 +59,7 @@ type userLang struct {
|
|||||||
notificationsJSON string
|
notificationsJSON string
|
||||||
ValidationStrings map[string]quantityString `json:"validationStrings"`
|
ValidationStrings map[string]quantityString `json:"validationStrings"`
|
||||||
validationStringsJSON string
|
validationStringsJSON string
|
||||||
|
QuantityStrings map[string]quantityString `json:"quantityStrings"`
|
||||||
JSON string
|
JSON string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,15 +18,9 @@
|
|||||||
"create": "Opret",
|
"create": "Opret",
|
||||||
"apply": "Anvend",
|
"apply": "Anvend",
|
||||||
"delete": "Slet",
|
"delete": "Slet",
|
||||||
"add": "Tilføj",
|
|
||||||
"select": "Vælg",
|
"select": "Vælg",
|
||||||
"name": "Navn",
|
"name": "Navn",
|
||||||
"date": "Dato",
|
"date": "Dato",
|
||||||
"enabled": "Aktiveret",
|
|
||||||
"disabled": "Deaktiveret",
|
|
||||||
"reEnable": "Genaktiver",
|
|
||||||
"disable": "Deaktiver",
|
|
||||||
"admin": "Administrator",
|
|
||||||
"updates": "Opdateringer",
|
"updates": "Opdateringer",
|
||||||
"update": "Opdatering",
|
"update": "Opdatering",
|
||||||
"download": "Hent",
|
"download": "Hent",
|
||||||
@ -35,7 +29,6 @@
|
|||||||
"lastActiveTime": "Sidst Aktiv",
|
"lastActiveTime": "Sidst Aktiv",
|
||||||
"from": "Fra",
|
"from": "Fra",
|
||||||
"user": "Bruger",
|
"user": "Bruger",
|
||||||
"expiry": "Udløb",
|
|
||||||
"userExpiry": "Brugerens Udløb",
|
"userExpiry": "Brugerens Udløb",
|
||||||
"userExpiryDescription": "En specificeret tid efter hver tilmelding, sletter/deaktiverer jfa-go kontoen. Du kan ændre denne adfærd i indstillingerne.",
|
"userExpiryDescription": "En specificeret tid efter hver tilmelding, sletter/deaktiverer jfa-go kontoen. Du kan ændre denne adfærd i indstillingerne.",
|
||||||
"aboutProgram": "Om",
|
"aboutProgram": "Om",
|
||||||
@ -52,7 +45,6 @@
|
|||||||
"conditionals": "Betingelser",
|
"conditionals": "Betingelser",
|
||||||
"preview": "Eksempel",
|
"preview": "Eksempel",
|
||||||
"reset": "Nulstil",
|
"reset": "Nulstil",
|
||||||
"edit": "Rediger",
|
|
||||||
"donate": "Doner",
|
"donate": "Doner",
|
||||||
"contactThrough": "Kontakt gennem:",
|
"contactThrough": "Kontakt gennem:",
|
||||||
"extendExpiry": "Forlæng udløb",
|
"extendExpiry": "Forlæng udløb",
|
||||||
@ -136,7 +128,6 @@
|
|||||||
"errorCreateProfile": "Kunne ikke oprette profilen {n}",
|
"errorCreateProfile": "Kunne ikke oprette profilen {n}",
|
||||||
"errorSetDefaultProfile": "Standard profilen kunne ikke indstilles.",
|
"errorSetDefaultProfile": "Standard profilen kunne ikke indstilles.",
|
||||||
"errorLoadUsers": "Kunne ikke indlæse brugere.",
|
"errorLoadUsers": "Kunne ikke indlæse brugere.",
|
||||||
"errorSaveSettings": "Kunne ikke gemme indstillingerne.",
|
|
||||||
"errorLoadSettings": "Indstillingerne kunne ikke indlæses.",
|
"errorLoadSettings": "Indstillingerne kunne ikke indlæses.",
|
||||||
"errorSetOmbiDefaults": "Ombi standarderne kunne ikke gemmes.",
|
"errorSetOmbiDefaults": "Ombi standarderne kunne ikke gemmes.",
|
||||||
"errorLoadOmbiUsers": "Kunne ikke indlæse ombi brugere.",
|
"errorLoadOmbiUsers": "Kunne ikke indlæse ombi brugere.",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Variablen",
|
"variables": "Variablen",
|
||||||
"preview": "Vorschau",
|
"preview": "Vorschau",
|
||||||
"reset": "Zurücksetzen",
|
"reset": "Zurücksetzen",
|
||||||
"edit": "Bearbeiten",
|
|
||||||
"customizeMessages": "Benachrichtigungen anpassen",
|
"customizeMessages": "Benachrichtigungen anpassen",
|
||||||
"customizeMessagesDescription": "Wenn du jfa-go's E-Mail-Vorlagen nicht benutzen willst, kannst du deinen eigenen unter Verwendung von Markdown erstellen.",
|
"customizeMessagesDescription": "Wenn du jfa-go's E-Mail-Vorlagen nicht benutzen willst, kannst du deinen eigenen unter Verwendung von Markdown erstellen.",
|
||||||
"announce": "Ankündigen",
|
"announce": "Ankündigen",
|
||||||
@ -77,23 +76,16 @@
|
|||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
"userExpiry": "Benutzer Ablaufdatum",
|
"userExpiry": "Benutzer Ablaufdatum",
|
||||||
"inviteDuration": "Invite Dauer",
|
"inviteDuration": "Invite Dauer",
|
||||||
"enabled": "Aktiviert",
|
|
||||||
"userExpiryDescription": "Eine bestimmte Zeit nach der Anmeldung wird jfa-go das Konto löschen/deaktivieren. Du kannst dieses Verhalten in den Einstellungen ändern.",
|
"userExpiryDescription": "Eine bestimmte Zeit nach der Anmeldung wird jfa-go das Konto löschen/deaktivieren. Du kannst dieses Verhalten in den Einstellungen ändern.",
|
||||||
"disabled": "Deaktiviert",
|
|
||||||
"admin": "Admin",
|
|
||||||
"download": "Herunterladen",
|
"download": "Herunterladen",
|
||||||
"update": "Aktualisieren",
|
"update": "Aktualisieren",
|
||||||
"updates": "Aktualisierungen",
|
"updates": "Aktualisierungen",
|
||||||
"expiry": "Ablaufdatum",
|
|
||||||
"extendExpiry": "Ablaufdatum verlängern",
|
"extendExpiry": "Ablaufdatum verlängern",
|
||||||
"reEnable": "Wieder aktivieren",
|
|
||||||
"disable": "Deaktivieren",
|
|
||||||
"donate": "Spenden",
|
"donate": "Spenden",
|
||||||
"conditionals": "Bedingungen",
|
"conditionals": "Bedingungen",
|
||||||
"contactThrough": "Kontakt über:",
|
"contactThrough": "Kontakt über:",
|
||||||
"sendPIN": "Bitte den Benutzer, die unten stehende PIN an den Bot zu senden.",
|
"sendPIN": "Bitte den Benutzer, die unten stehende PIN an den Bot zu senden.",
|
||||||
"inviteMonths": "Monate",
|
"inviteMonths": "Monate",
|
||||||
"add": "Hinzufügen",
|
|
||||||
"select": "Auswählen",
|
"select": "Auswählen",
|
||||||
"searchDiscordUser": "Gib den Discord-Benutzername ein, um den Benutzer zu finden.",
|
"searchDiscordUser": "Gib den Discord-Benutzername ein, um den Benutzer zu finden.",
|
||||||
"findDiscordUser": "Suche Discord-Benutzer",
|
"findDiscordUser": "Suche Discord-Benutzer",
|
||||||
@ -129,7 +121,6 @@
|
|||||||
"errorCreateProfile": "Fehler beim Erstellen des Profils {n}",
|
"errorCreateProfile": "Fehler beim Erstellen des Profils {n}",
|
||||||
"errorSetDefaultProfile": "Fehler beim Setzen des Standardprofils.",
|
"errorSetDefaultProfile": "Fehler beim Setzen des Standardprofils.",
|
||||||
"errorLoadUsers": "Fehler beim Laden der Benutzer.",
|
"errorLoadUsers": "Fehler beim Laden der Benutzer.",
|
||||||
"errorSaveSettings": "Einstellungen konnten nicht gespeichert werden.",
|
|
||||||
"errorLoadSettings": "Fehler beim Laden der Einstellungen.",
|
"errorLoadSettings": "Fehler beim Laden der Einstellungen.",
|
||||||
"errorSetOmbiDefaults": "Fehler beim Speichern der Ombi-Standardeinstellungen.",
|
"errorSetOmbiDefaults": "Fehler beim Speichern der Ombi-Standardeinstellungen.",
|
||||||
"errorLoadOmbiUsers": "Fehler beim Laden der Ombi-Benutzer.",
|
"errorLoadOmbiUsers": "Fehler beim Laden der Ombi-Benutzer.",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Μεταβλητές",
|
"variables": "Μεταβλητές",
|
||||||
"preview": "Προεπισκόπηση",
|
"preview": "Προεπισκόπηση",
|
||||||
"reset": "Επαναφορά",
|
"reset": "Επαναφορά",
|
||||||
"edit": "Επεξεργασία",
|
|
||||||
"customizeMessages": "Παραμετροποίηση Emails",
|
"customizeMessages": "Παραμετροποίηση Emails",
|
||||||
"advancedSettings": "Προχωρημένες Ρυθμίσεις",
|
"advancedSettings": "Προχωρημένες Ρυθμίσεις",
|
||||||
"customizeMessagesDescription": "Αν δεν θέλετε να ζρησιμοποιήσετε τα πρότυπα email του jfa-go, μπορείτε να δημιουργήσετε τα δικά σας με χρήση Markdown.",
|
"customizeMessagesDescription": "Αν δεν θέλετε να ζρησιμοποιήσετε τα πρότυπα email του jfa-go, μπορείτε να δημιουργήσετε τα δικά σας με χρήση Markdown.",
|
||||||
@ -75,10 +74,6 @@
|
|||||||
"download": "Λήψη",
|
"download": "Λήψη",
|
||||||
"search": "Αναζήτηση",
|
"search": "Αναζήτηση",
|
||||||
"inviteDuration": "Διάρκεια Πρόσκλησης",
|
"inviteDuration": "Διάρκεια Πρόσκλησης",
|
||||||
"enabled": "Ενεργοποιημένο",
|
|
||||||
"disabled": "Απενεργοποιημένο",
|
|
||||||
"admin": "Διαχειριστής",
|
|
||||||
"expiry": "Λήξη",
|
|
||||||
"userExpiry": "Λήξη Χρήστη",
|
"userExpiry": "Λήξη Χρήστη",
|
||||||
"userExpiryDescription": "Μετά απο ένα καθορισμένο χρόνο μετά απο κάθε εγγραφή, το jfa-go θα διαγράφει/απενεργοποιεί τον λογαριασμό. Μπορείτε να αλλάξετε αυτή την συμπεριφορά στις ρυθμίσεις.",
|
"userExpiryDescription": "Μετά απο ένα καθορισμένο χρόνο μετά απο κάθε εγγραφή, το jfa-go θα διαγράφει/απενεργοποιεί τον λογαριασμό. Μπορείτε να αλλάξετε αυτή την συμπεριφορά στις ρυθμίσεις.",
|
||||||
"announce": "Ανακοίνωση",
|
"announce": "Ανακοίνωση",
|
||||||
@ -86,8 +81,6 @@
|
|||||||
"message": "Μήνυμα",
|
"message": "Μήνυμα",
|
||||||
"extendExpiry": "Παράταση λήξης",
|
"extendExpiry": "Παράταση λήξης",
|
||||||
"markdownSupported": "Το Markdown υποστυρίζεται.",
|
"markdownSupported": "Το Markdown υποστυρίζεται.",
|
||||||
"reEnable": "Επανα-ενεργοποίηση",
|
|
||||||
"disable": "Απενεργοποίηση",
|
|
||||||
"inviteMonths": "Μήνες"
|
"inviteMonths": "Μήνες"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
@ -105,7 +98,6 @@
|
|||||||
"errorCreateProfile": "Αποτυχία δημιουργίας του προφίλ {n}",
|
"errorCreateProfile": "Αποτυχία δημιουργίας του προφίλ {n}",
|
||||||
"errorSetDefaultProfile": "Αποτυχία ορισμού του προκαθορισμένου προφίλ.",
|
"errorSetDefaultProfile": "Αποτυχία ορισμού του προκαθορισμένου προφίλ.",
|
||||||
"errorLoadUsers": "Αποτυχία φόρτωσης χρηστών.",
|
"errorLoadUsers": "Αποτυχία φόρτωσης χρηστών.",
|
||||||
"errorSaveSettings": "Αποτυχία αποθήκευσης ρυθμίσεων.",
|
|
||||||
"errorLoadSettings": "Αποτυχία φόρτωσης ρυθμίσεων.",
|
"errorLoadSettings": "Αποτυχία φόρτωσης ρυθμίσεων.",
|
||||||
"errorSetOmbiDefaults": "Αποτυχία αποθήκευσης προκαθορισμένων ρυθμίσεων για το Ombi.",
|
"errorSetOmbiDefaults": "Αποτυχία αποθήκευσης προκαθορισμένων ρυθμίσεων για το Ombi.",
|
||||||
"errorLoadOmbiUsers": "Αποτυχία φόρτωσης χρηστών Ombi.",
|
"errorLoadOmbiUsers": "Αποτυχία φόρτωσης χρηστών Ombi.",
|
||||||
|
@ -71,7 +71,6 @@
|
|||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"updates": "Updates",
|
"updates": "Updates",
|
||||||
"expiry": "Expiry",
|
|
||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"markdownSupported": "Markdown is supported.",
|
"markdownSupported": "Markdown is supported.",
|
||||||
@ -94,16 +93,10 @@
|
|||||||
"contactThrough": "Contact through:",
|
"contactThrough": "Contact through:",
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"enabled": "Enabled",
|
|
||||||
"disabled": "Disabled",
|
|
||||||
"disable": "Disable",
|
|
||||||
"edit": "Edit",
|
|
||||||
"extendExpiry": "Extend expiry",
|
"extendExpiry": "Extend expiry",
|
||||||
"sendPWR": "Send Password Reset",
|
"sendPWR": "Send Password Reset",
|
||||||
"inviteMonths": "Months",
|
"inviteMonths": "Months",
|
||||||
"inviteDuration": "Invite Duration",
|
"inviteDuration": "Invite Duration",
|
||||||
"add": "Add",
|
|
||||||
"reEnable": "Re-enable",
|
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
||||||
@ -148,7 +141,6 @@
|
|||||||
"settingsApplyRestartLater": "Apply, restart later",
|
"settingsApplyRestartLater": "Apply, restart later",
|
||||||
"subject": "Subject",
|
"subject": "Subject",
|
||||||
"setExpiry": "Set expiry",
|
"setExpiry": "Set expiry",
|
||||||
"admin": "Admin",
|
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
"advancedSettings": "Advanced Settings",
|
"advancedSettings": "Advanced Settings",
|
||||||
@ -187,7 +179,6 @@
|
|||||||
"errorLoadProfiles": "Failed to load profiles.",
|
"errorLoadProfiles": "Failed to load profiles.",
|
||||||
"errorCreateProfile": "Failed to create profile {n}",
|
"errorCreateProfile": "Failed to create profile {n}",
|
||||||
"errorLoadUsers": "Failed to load users.",
|
"errorLoadUsers": "Failed to load users.",
|
||||||
"errorSaveSettings": "Couldn't save settings.",
|
|
||||||
"errorSetOmbiProfile": "Failed to store ombi profile.",
|
"errorSetOmbiProfile": "Failed to store ombi profile.",
|
||||||
"errorLoadOmbiUsers": "Failed to load ombi users.",
|
"errorLoadOmbiUsers": "Failed to load ombi users.",
|
||||||
"errorFailureCheckLogs": "Failed (check console/logs)",
|
"errorFailureCheckLogs": "Failed (check console/logs)",
|
||||||
|
@ -18,16 +18,10 @@
|
|||||||
"create": "Create",
|
"create": "Create",
|
||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"add": "Add",
|
|
||||||
"select": "Select",
|
"select": "Select",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"date": "Date",
|
"date": "Date",
|
||||||
"enabled": "Enabled",
|
|
||||||
"disabled": "Disabled",
|
|
||||||
"reEnable": "Re-enable",
|
|
||||||
"setExpiry": "Set expiry",
|
"setExpiry": "Set expiry",
|
||||||
"disable": "Disable",
|
|
||||||
"admin": "Admin",
|
|
||||||
"updates": "Updates",
|
"updates": "Updates",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
@ -38,7 +32,6 @@
|
|||||||
"after": "After",
|
"after": "After",
|
||||||
"before": "Before",
|
"before": "Before",
|
||||||
"user": "User",
|
"user": "User",
|
||||||
"expiry": "Expiry",
|
|
||||||
"userExpiry": "User Expiry",
|
"userExpiry": "User Expiry",
|
||||||
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
"userExpiryDescription": "A specified amount of time after each signup, jfa-go will delete/disable the account. You can change this behaviour in settings.",
|
||||||
"aboutProgram": "About",
|
"aboutProgram": "About",
|
||||||
@ -57,7 +50,6 @@
|
|||||||
"conditionals": "Conditionals",
|
"conditionals": "Conditionals",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"edit": "Edit",
|
|
||||||
"donate": "Donate",
|
"donate": "Donate",
|
||||||
"unlink": "Unlink Account",
|
"unlink": "Unlink Account",
|
||||||
"sendPWR": "Send Password Reset",
|
"sendPWR": "Send Password Reset",
|
||||||
@ -147,7 +139,6 @@
|
|||||||
"errorCreateProfile": "Failed to create profile {n}",
|
"errorCreateProfile": "Failed to create profile {n}",
|
||||||
"errorSetDefaultProfile": "Failed to set default profile.",
|
"errorSetDefaultProfile": "Failed to set default profile.",
|
||||||
"errorLoadUsers": "Failed to load users.",
|
"errorLoadUsers": "Failed to load users.",
|
||||||
"errorSaveSettings": "Couldn't save settings.",
|
|
||||||
"errorLoadSettings": "Failed to load settings.",
|
"errorLoadSettings": "Failed to load settings.",
|
||||||
"errorSetOmbiProfile": "Failed to store ombi profile.",
|
"errorSetOmbiProfile": "Failed to store ombi profile.",
|
||||||
"errorLoadOmbiUsers": "Failed to load ombi users.",
|
"errorLoadOmbiUsers": "Failed to load ombi users.",
|
||||||
|
@ -20,11 +20,6 @@
|
|||||||
"delete": "Eliminar",
|
"delete": "Eliminar",
|
||||||
"name": "Nombre",
|
"name": "Nombre",
|
||||||
"date": "Fecha",
|
"date": "Fecha",
|
||||||
"enabled": "Activado",
|
|
||||||
"disabled": "Desactivado",
|
|
||||||
"reEnable": "Reactivar",
|
|
||||||
"disable": "Desactivar",
|
|
||||||
"admin": "Administrador",
|
|
||||||
"updates": "Actualizaciones",
|
"updates": "Actualizaciones",
|
||||||
"update": "Actualizar",
|
"update": "Actualizar",
|
||||||
"download": "Descargar",
|
"download": "Descargar",
|
||||||
@ -33,7 +28,6 @@
|
|||||||
"lastActiveTime": "Último activo",
|
"lastActiveTime": "Último activo",
|
||||||
"from": "De",
|
"from": "De",
|
||||||
"user": "Usuario",
|
"user": "Usuario",
|
||||||
"expiry": "Expiración",
|
|
||||||
"userExpiry": "Caducidad del usuario",
|
"userExpiry": "Caducidad del usuario",
|
||||||
"userExpiryDescription": "Una cantidad de tiempo específica después de cada registro, jfa-go eliminará / deshabilitará la cuenta. Puede cambiar este comportamiento en la configuración.",
|
"userExpiryDescription": "Una cantidad de tiempo específica después de cada registro, jfa-go eliminará / deshabilitará la cuenta. Puede cambiar este comportamiento en la configuración.",
|
||||||
"aboutProgram": "Acerca de",
|
"aboutProgram": "Acerca de",
|
||||||
@ -49,7 +43,6 @@
|
|||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"preview": "Vista previa",
|
"preview": "Vista previa",
|
||||||
"reset": "Reiniciar",
|
"reset": "Reiniciar",
|
||||||
"edit": "Editar",
|
|
||||||
"extendExpiry": "Extender el vencimiento",
|
"extendExpiry": "Extender el vencimiento",
|
||||||
"customizeMessages": "Personalizar mensajes",
|
"customizeMessages": "Personalizar mensajes",
|
||||||
"customizeMessagesDescription": "Si no desea utilizar las plantillas de mensajes de jfa-go, puede crear las suyas con Markdown.",
|
"customizeMessagesDescription": "Si no desea utilizar las plantillas de mensajes de jfa-go, puede crear las suyas con Markdown.",
|
||||||
@ -91,7 +84,6 @@
|
|||||||
"notifyUserCreation": "Sobre la creación de usuarios",
|
"notifyUserCreation": "Sobre la creación de usuarios",
|
||||||
"conditionals": "Condicionales",
|
"conditionals": "Condicionales",
|
||||||
"donate": "Donar",
|
"donate": "Donar",
|
||||||
"add": "Agregar",
|
|
||||||
"templates": "Plantillas",
|
"templates": "Plantillas",
|
||||||
"contactThrough": "Contactar a través de:",
|
"contactThrough": "Contactar a través de:",
|
||||||
"select": "Seleccionar",
|
"select": "Seleccionar",
|
||||||
@ -133,7 +125,6 @@
|
|||||||
"errorCreateProfile": "No se pudo crear el perfil {n}",
|
"errorCreateProfile": "No se pudo crear el perfil {n}",
|
||||||
"errorSetDefaultProfile": "No se pudo establecer el perfil predeterminado.",
|
"errorSetDefaultProfile": "No se pudo establecer el perfil predeterminado.",
|
||||||
"errorLoadUsers": "No se pudieron cargar los usuarios.",
|
"errorLoadUsers": "No se pudieron cargar los usuarios.",
|
||||||
"errorSaveSettings": "No se pudo guardar la configuración.",
|
|
||||||
"errorLoadSettings": "No se pudo cargar la configuración.",
|
"errorLoadSettings": "No se pudo cargar la configuración.",
|
||||||
"errorSetOmbiDefaults": "No se pudieron almacenar los valores predeterminados de ombi.",
|
"errorSetOmbiDefaults": "No se pudieron almacenar los valores predeterminados de ombi.",
|
||||||
"errorLoadOmbiUsers": "No se pudieron cargar los usuarios de Ombi.",
|
"errorLoadOmbiUsers": "No se pudieron cargar los usuarios de Ombi.",
|
||||||
|
@ -73,15 +73,8 @@
|
|||||||
"variables": "Variables",
|
"variables": "Variables",
|
||||||
"preview": "Aperçu",
|
"preview": "Aperçu",
|
||||||
"reset": "Réinitialisation",
|
"reset": "Réinitialisation",
|
||||||
"edit": "Éditer",
|
|
||||||
"customizeMessages": "Personnaliser les e-mails",
|
"customizeMessages": "Personnaliser les e-mails",
|
||||||
"inviteDuration": "Durée de l'invitation",
|
"inviteDuration": "Durée de l'invitation",
|
||||||
"enabled": "Activé",
|
|
||||||
"disabled": "Désactivé",
|
|
||||||
"reEnable": "Ré-activé",
|
|
||||||
"disable": "Désactivé",
|
|
||||||
"admin": "Administrateur",
|
|
||||||
"expiry": "Expiration",
|
|
||||||
"advancedSettings": "Paramètres avancés",
|
"advancedSettings": "Paramètres avancés",
|
||||||
"userExpiry": "Expiration de l'utilisateur",
|
"userExpiry": "Expiration de l'utilisateur",
|
||||||
"updates": "Mises à jour",
|
"updates": "Mises à jour",
|
||||||
@ -94,7 +87,6 @@
|
|||||||
"extendExpiry": "Prolonger l'expiration",
|
"extendExpiry": "Prolonger l'expiration",
|
||||||
"contactThrough": "Contacté par :",
|
"contactThrough": "Contacté par :",
|
||||||
"sendPIN": "Demandez à l'utilisateur d'envoyer le code PIN ci-dessous au bot.",
|
"sendPIN": "Demandez à l'utilisateur d'envoyer le code PIN ci-dessous au bot.",
|
||||||
"add": "Ajouter",
|
|
||||||
"select": "Sélectionner",
|
"select": "Sélectionner",
|
||||||
"findDiscordUser": "Trouver l'utilisateur Discord",
|
"findDiscordUser": "Trouver l'utilisateur Discord",
|
||||||
"linkMatrixDescription": "Entrez le nom d'utilisateur et le mot de passe de l'utilisateur pour l’utilisateur comme bot. Une fois soumis, l'application va redémarrer.",
|
"linkMatrixDescription": "Entrez le nom d'utilisateur et le mot de passe de l'utilisateur pour l’utilisateur comme bot. Une fois soumis, l'application va redémarrer.",
|
||||||
@ -130,7 +122,6 @@
|
|||||||
"errorCreateProfile": "Échec de la création du profil {n}",
|
"errorCreateProfile": "Échec de la création du profil {n}",
|
||||||
"errorSetDefaultProfile": "Échec de la définition du profil par défaut.",
|
"errorSetDefaultProfile": "Échec de la définition du profil par défaut.",
|
||||||
"errorLoadUsers": "Échec du chargement des utilisateurs.",
|
"errorLoadUsers": "Échec du chargement des utilisateurs.",
|
||||||
"errorSaveSettings": "Impossible d'enregistrer les paramètres.",
|
|
||||||
"errorLoadSettings": "Échec du chargement des paramètres.",
|
"errorLoadSettings": "Échec du chargement des paramètres.",
|
||||||
"errorSetOmbiDefaults": "Impossible de stocker les valeurs par défaut d'Ombi.",
|
"errorSetOmbiDefaults": "Impossible de stocker les valeurs par défaut d'Ombi.",
|
||||||
"errorLoadOmbiUsers": "Échec du chargement des utilisateurs Ombi.",
|
"errorLoadOmbiUsers": "Échec du chargement des utilisateurs Ombi.",
|
||||||
|
@ -18,16 +18,10 @@
|
|||||||
"create": "Létrehozás",
|
"create": "Létrehozás",
|
||||||
"apply": "Alkalmaz",
|
"apply": "Alkalmaz",
|
||||||
"delete": "Törlés",
|
"delete": "Törlés",
|
||||||
"add": "Hozzáadás",
|
|
||||||
"select": "Kiválasztás",
|
"select": "Kiválasztás",
|
||||||
"name": "Név",
|
"name": "Név",
|
||||||
"date": "Dátum",
|
"date": "Dátum",
|
||||||
"enabled": "Engedélyezve",
|
|
||||||
"disabled": "Tiltva",
|
|
||||||
"reEnable": "Újra engedélyezés",
|
|
||||||
"setExpiry": "Lejárat beállítása",
|
"setExpiry": "Lejárat beállítása",
|
||||||
"disable": "Letiltás",
|
|
||||||
"admin": "Adminisztrátor",
|
|
||||||
"updates": "Frissítések",
|
"updates": "Frissítések",
|
||||||
"update": "Frissítés",
|
"update": "Frissítés",
|
||||||
"download": "Letöltés",
|
"download": "Letöltés",
|
||||||
@ -36,7 +30,6 @@
|
|||||||
"lastActiveTime": "Utoljára aktív",
|
"lastActiveTime": "Utoljára aktív",
|
||||||
"from": "Feladó",
|
"from": "Feladó",
|
||||||
"user": "Felhasználó",
|
"user": "Felhasználó",
|
||||||
"expiry": "Lejárat",
|
|
||||||
"userExpiry": "Felhasználói lejárat",
|
"userExpiry": "Felhasználói lejárat",
|
||||||
"userExpiryDescription": "Egy meghatározott idő után minden regisztrációt töröl, vagy felfüggeszt a jfa-go. Ezt a működést megváltoztathatod a beállításokban.",
|
"userExpiryDescription": "Egy meghatározott idő után minden regisztrációt töröl, vagy felfüggeszt a jfa-go. Ezt a működést megváltoztathatod a beállításokban.",
|
||||||
"aboutProgram": "Névjegy",
|
"aboutProgram": "Névjegy",
|
||||||
@ -55,7 +48,6 @@
|
|||||||
"conditionals": "Feltételek",
|
"conditionals": "Feltételek",
|
||||||
"preview": "Előnézet",
|
"preview": "Előnézet",
|
||||||
"reset": "Visszaállítás",
|
"reset": "Visszaállítás",
|
||||||
"edit": "Szerkesztés",
|
|
||||||
"donate": "Támogatás",
|
"donate": "Támogatás",
|
||||||
"sendPWR": "Jelszó visszaállítás küldése",
|
"sendPWR": "Jelszó visszaállítás küldése",
|
||||||
"contactThrough": "",
|
"contactThrough": "",
|
||||||
@ -134,7 +126,6 @@
|
|||||||
"errorCreateProfile": "",
|
"errorCreateProfile": "",
|
||||||
"errorSetDefaultProfile": "",
|
"errorSetDefaultProfile": "",
|
||||||
"errorLoadUsers": "",
|
"errorLoadUsers": "",
|
||||||
"errorSaveSettings": "",
|
|
||||||
"errorLoadSettings": "",
|
"errorLoadSettings": "",
|
||||||
"errorSetOmbiProfile": "",
|
"errorSetOmbiProfile": "",
|
||||||
"errorLoadOmbiUsers": "",
|
"errorLoadOmbiUsers": "",
|
||||||
|
@ -66,7 +66,6 @@
|
|||||||
"variables": "Variabel",
|
"variables": "Variabel",
|
||||||
"preview": "Pratinjau",
|
"preview": "Pratinjau",
|
||||||
"reset": "Setel ulang",
|
"reset": "Setel ulang",
|
||||||
"edit": "Edit",
|
|
||||||
"customizeMessages": "Sesuaikan Email",
|
"customizeMessages": "Sesuaikan Email",
|
||||||
"customizeMessagesDescription": "Jika Anda tidak ingin menggunakan templat email jfa-go, Anda dapat membuatnya sendiri menggunakan Markdown.",
|
"customizeMessagesDescription": "Jika Anda tidak ingin menggunakan templat email jfa-go, Anda dapat membuatnya sendiri menggunakan Markdown.",
|
||||||
"announce": "Mengumumkan",
|
"announce": "Mengumumkan",
|
||||||
@ -89,7 +88,6 @@
|
|||||||
"errorCreateProfile": "Gagal membuat profil {n}",
|
"errorCreateProfile": "Gagal membuat profil {n}",
|
||||||
"errorSetDefaultProfile": "Gagal menyetel profil default.",
|
"errorSetDefaultProfile": "Gagal menyetel profil default.",
|
||||||
"errorLoadUsers": "Gagal memuat pengguna.",
|
"errorLoadUsers": "Gagal memuat pengguna.",
|
||||||
"errorSaveSettings": "Tidak dapat menyimpan pengaturan.",
|
|
||||||
"errorLoadSettings": "Gagal memuat pengaturan.",
|
"errorLoadSettings": "Gagal memuat pengaturan.",
|
||||||
"errorSetOmbiDefaults": "Gagal menyimpan default ombi.",
|
"errorSetOmbiDefaults": "Gagal menyimpan default ombi.",
|
||||||
"errorLoadOmbiUsers": "Gagal memuat pengguna ombi.",
|
"errorLoadOmbiUsers": "Gagal memuat pengguna ombi.",
|
||||||
|
@ -71,14 +71,9 @@
|
|||||||
"customizeMessagesDescription": "Als je de e-mailsjablonen van jfa-go niet wilt gebruiken, kun je met gebruik van Markdown je eigen aanmaken.",
|
"customizeMessagesDescription": "Als je de e-mailsjablonen van jfa-go niet wilt gebruiken, kun je met gebruik van Markdown je eigen aanmaken.",
|
||||||
"preview": "Voorbeeld",
|
"preview": "Voorbeeld",
|
||||||
"reset": "Reset",
|
"reset": "Reset",
|
||||||
"edit": "Bewerken",
|
|
||||||
"customizeMessages": "E-mails aanpassen",
|
"customizeMessages": "E-mails aanpassen",
|
||||||
"inviteDuration": "Geldigheidsduur uitnodiging",
|
"inviteDuration": "Geldigheidsduur uitnodiging",
|
||||||
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
|
"userExpiryDescription": "Een bepaalde tijd na elke aanmelding, wordt de account verwijderd/uitgeschakeld door jfa-go. Dit kan aangepast worden in de instellingen.",
|
||||||
"enabled": "Ingeschakeld",
|
|
||||||
"disabled": "Uitgeschakeld",
|
|
||||||
"admin": "Beheerder",
|
|
||||||
"expiry": "Verloop",
|
|
||||||
"userExpiry": "Gebruikersverloop",
|
"userExpiry": "Gebruikersverloop",
|
||||||
"extendExpiry": "Verleng verloop",
|
"extendExpiry": "Verleng verloop",
|
||||||
"updates": "Updates",
|
"updates": "Updates",
|
||||||
@ -87,13 +82,10 @@
|
|||||||
"search": "Zoeken",
|
"search": "Zoeken",
|
||||||
"advancedSettings": "Geavanceerde instellingen",
|
"advancedSettings": "Geavanceerde instellingen",
|
||||||
"inviteMonths": "Maanden",
|
"inviteMonths": "Maanden",
|
||||||
"reEnable": "Opnieuw inschakelen",
|
|
||||||
"disable": "Uitschakelen",
|
|
||||||
"conditionals": "Voorwaarden",
|
"conditionals": "Voorwaarden",
|
||||||
"donate": "Doneer",
|
"donate": "Doneer",
|
||||||
"contactThrough": "Stuur bericht via:",
|
"contactThrough": "Stuur bericht via:",
|
||||||
"sendPIN": "Vraag de gebruiker om onderstaande pincode naar de bot te sturen.",
|
"sendPIN": "Vraag de gebruiker om onderstaande pincode naar de bot te sturen.",
|
||||||
"add": "Voeg toe",
|
|
||||||
"searchDiscordUser": "Begin de Discord gebruikersnaam te typen om de gebruiker te vinden.",
|
"searchDiscordUser": "Begin de Discord gebruikersnaam te typen om de gebruiker te vinden.",
|
||||||
"linkMatrixDescription": "Vul de gebruikersnaam en wachtwoord in van de gebruiker om als bot te gebruiken. De app start zodra ze zijn verstuurd.",
|
"linkMatrixDescription": "Vul de gebruikersnaam en wachtwoord in van de gebruiker om als bot te gebruiken. De app start zodra ze zijn verstuurd.",
|
||||||
"select": "Selecteer",
|
"select": "Selecteer",
|
||||||
@ -129,7 +121,6 @@
|
|||||||
"errorCreateProfile": "Aanmaken van profile {n} mislukt",
|
"errorCreateProfile": "Aanmaken van profile {n} mislukt",
|
||||||
"errorSetDefaultProfile": "Fout bij instellen van standaardprofiel.",
|
"errorSetDefaultProfile": "Fout bij instellen van standaardprofiel.",
|
||||||
"errorLoadUsers": "Laden van gebruikers mislukt.",
|
"errorLoadUsers": "Laden van gebruikers mislukt.",
|
||||||
"errorSaveSettings": "Opslaan van instellingen mislukt.",
|
|
||||||
"errorLoadSettings": "Laden van instellingen mislukt.",
|
"errorLoadSettings": "Laden van instellingen mislukt.",
|
||||||
"errorSetOmbiDefaults": "Opslaan van ombi standaardinstellingen mislukt.",
|
"errorSetOmbiDefaults": "Opslaan van ombi standaardinstellingen mislukt.",
|
||||||
"errorLoadOmbiUsers": "Laden van ombi gebruikers mislukt.",
|
"errorLoadOmbiUsers": "Laden van ombi gebruikers mislukt.",
|
||||||
|
@ -18,16 +18,10 @@
|
|||||||
"create": "",
|
"create": "",
|
||||||
"apply": "",
|
"apply": "",
|
||||||
"delete": "",
|
"delete": "",
|
||||||
"add": "",
|
|
||||||
"select": "",
|
"select": "",
|
||||||
"name": "Imię",
|
"name": "Imię",
|
||||||
"date": "Data",
|
"date": "Data",
|
||||||
"enabled": "Włączone",
|
|
||||||
"disabled": "Wyłączone",
|
|
||||||
"reEnable": "",
|
|
||||||
"setExpiry": "",
|
"setExpiry": "",
|
||||||
"disable": "Wyłączone",
|
|
||||||
"admin": "Admin",
|
|
||||||
"updates": "Aktualizacje",
|
"updates": "Aktualizacje",
|
||||||
"update": "Aktualizacja",
|
"update": "Aktualizacja",
|
||||||
"download": "Pobierz",
|
"download": "Pobierz",
|
||||||
@ -36,7 +30,6 @@
|
|||||||
"lastActiveTime": "Ostatnia aktywność",
|
"lastActiveTime": "Ostatnia aktywność",
|
||||||
"from": "Od",
|
"from": "Od",
|
||||||
"user": "Użytkownik",
|
"user": "Użytkownik",
|
||||||
"expiry": "Wygasa",
|
|
||||||
"userExpiry": "Użytkownik wygasa",
|
"userExpiry": "Użytkownik wygasa",
|
||||||
"userExpiryDescription": "",
|
"userExpiryDescription": "",
|
||||||
"aboutProgram": "O",
|
"aboutProgram": "O",
|
||||||
@ -55,7 +48,6 @@
|
|||||||
"conditionals": "",
|
"conditionals": "",
|
||||||
"preview": "",
|
"preview": "",
|
||||||
"reset": "Zresetuj",
|
"reset": "Zresetuj",
|
||||||
"edit": "Edytuj",
|
|
||||||
"donate": "",
|
"donate": "",
|
||||||
"sendPWR": "",
|
"sendPWR": "",
|
||||||
"contactThrough": "",
|
"contactThrough": "",
|
||||||
@ -136,7 +128,6 @@
|
|||||||
"errorCreateProfile": "",
|
"errorCreateProfile": "",
|
||||||
"errorSetDefaultProfile": "",
|
"errorSetDefaultProfile": "",
|
||||||
"errorLoadUsers": "",
|
"errorLoadUsers": "",
|
||||||
"errorSaveSettings": "",
|
|
||||||
"errorLoadSettings": "",
|
"errorLoadSettings": "",
|
||||||
"errorSetOmbiProfile": "",
|
"errorSetOmbiProfile": "",
|
||||||
"errorLoadOmbiUsers": "",
|
"errorLoadOmbiUsers": "",
|
||||||
|
@ -71,14 +71,9 @@
|
|||||||
"variables": "Variáveis",
|
"variables": "Variáveis",
|
||||||
"preview": "Pre-visualizar",
|
"preview": "Pre-visualizar",
|
||||||
"reset": "Redefinir",
|
"reset": "Redefinir",
|
||||||
"edit": "Editar",
|
|
||||||
"customizeMessages": "Customizar Emails",
|
"customizeMessages": "Customizar Emails",
|
||||||
"disabled": "Desativado",
|
|
||||||
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
|
"userExpiryDescription": "Após um determinado período de tempo de cada inscrição, o jfa-go apagará/desabilitará a conta. Você pode alterar essa opção nas configurações.",
|
||||||
"inviteDuration": "Duração do Convite",
|
"inviteDuration": "Duração do Convite",
|
||||||
"enabled": "Habilitado",
|
|
||||||
"admin": "Admin",
|
|
||||||
"expiry": "Expira",
|
|
||||||
"userExpiry": "Vencimento do Usuário",
|
"userExpiry": "Vencimento do Usuário",
|
||||||
"extendExpiry": "Extender o vencimento",
|
"extendExpiry": "Extender o vencimento",
|
||||||
"updates": "Atualizações",
|
"updates": "Atualizações",
|
||||||
@ -87,15 +82,12 @@
|
|||||||
"search": "Procurar",
|
"search": "Procurar",
|
||||||
"advancedSettings": "Configurações Avançada",
|
"advancedSettings": "Configurações Avançada",
|
||||||
"inviteMonths": "Meses",
|
"inviteMonths": "Meses",
|
||||||
"reEnable": "Reativar",
|
|
||||||
"disable": "Desativar",
|
|
||||||
"conditionals": "Condicionais",
|
"conditionals": "Condicionais",
|
||||||
"donate": "Doar",
|
"donate": "Doar",
|
||||||
"contactThrough": "Contato através:",
|
"contactThrough": "Contato através:",
|
||||||
"sendPIN": "Peça que o usuário envie o PIN abaixo para o bot.",
|
"sendPIN": "Peça que o usuário envie o PIN abaixo para o bot.",
|
||||||
"searchDiscordUser": "Digite o nome de usuário do Discord.",
|
"searchDiscordUser": "Digite o nome de usuário do Discord.",
|
||||||
"findDiscordUser": "Encontrar usuário Discord",
|
"findDiscordUser": "Encontrar usuário Discord",
|
||||||
"add": "Adicionar",
|
|
||||||
"linkMatrixDescription": "Digite o nome de usuário e a senha para usar como bot. Depois de enviado, o aplicativo será reiniciado.",
|
"linkMatrixDescription": "Digite o nome de usuário e a senha para usar como bot. Depois de enviado, o aplicativo será reiniciado.",
|
||||||
"select": "Selecionar",
|
"select": "Selecionar",
|
||||||
"templates": "Modelos",
|
"templates": "Modelos",
|
||||||
@ -129,7 +121,6 @@
|
|||||||
"errorCreateProfile": "Falha ao criar perfil {n}",
|
"errorCreateProfile": "Falha ao criar perfil {n}",
|
||||||
"errorSetDefaultProfile": "Falha ao definir o perfil padrão.",
|
"errorSetDefaultProfile": "Falha ao definir o perfil padrão.",
|
||||||
"errorLoadUsers": "Falha ao carregar usuários.",
|
"errorLoadUsers": "Falha ao carregar usuários.",
|
||||||
"errorSaveSettings": "Não foi possível salvar as configurações.",
|
|
||||||
"errorLoadSettings": "Falha ao carregar as configurações.",
|
"errorLoadSettings": "Falha ao carregar as configurações.",
|
||||||
"errorSetOmbiDefaults": "Falha em armazenar os padrões ombi.",
|
"errorSetOmbiDefaults": "Falha em armazenar os padrões ombi.",
|
||||||
"errorLoadOmbiUsers": "Falha ao carregar usuários ombi.",
|
"errorLoadOmbiUsers": "Falha ao carregar usuários ombi.",
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
"variables": "Variabler",
|
"variables": "Variabler",
|
||||||
"preview": "Förhandsvisning",
|
"preview": "Förhandsvisning",
|
||||||
"reset": "Återställ",
|
"reset": "Återställ",
|
||||||
"edit": "Redigera",
|
|
||||||
"customizeMessages": "Anpassa e-post",
|
"customizeMessages": "Anpassa e-post",
|
||||||
"customizeMessagesDescription": "Om du inte vill använda jfa-go's e-postmallar, så kan du skapa dina egna med Markdown.",
|
"customizeMessagesDescription": "Om du inte vill använda jfa-go's e-postmallar, så kan du skapa dina egna med Markdown.",
|
||||||
"markdownSupported": "Markdown stöds.",
|
"markdownSupported": "Markdown stöds.",
|
||||||
@ -73,11 +72,7 @@
|
|||||||
"notifyEvent": "Meddela den:",
|
"notifyEvent": "Meddela den:",
|
||||||
"notifyInviteExpiry": "Vid utgång",
|
"notifyInviteExpiry": "Vid utgång",
|
||||||
"notifyUserCreation": "Vid användarskapande",
|
"notifyUserCreation": "Vid användarskapande",
|
||||||
"disabled": "Inaktiverad",
|
|
||||||
"enabled": "Aktiverad",
|
|
||||||
"inviteDuration": "Varaktighet för inbjudan",
|
"inviteDuration": "Varaktighet för inbjudan",
|
||||||
"admin": "Admin",
|
|
||||||
"expiry": "Löper ut",
|
|
||||||
"userExpiry": "Användarutgång",
|
"userExpiry": "Användarutgång",
|
||||||
"userExpiryDescription": "Efter en angiven tid efter varje registrering så tar jfa-go bort/inaktiverar kontot. Du kan ändra detta beteende i inställningarna.",
|
"userExpiryDescription": "Efter en angiven tid efter varje registrering så tar jfa-go bort/inaktiverar kontot. Du kan ändra detta beteende i inställningarna.",
|
||||||
"extendExpiry": "Förläng utgång"
|
"extendExpiry": "Förläng utgång"
|
||||||
@ -100,7 +95,6 @@
|
|||||||
"errorCreateProfile": "Det gick inte att skapa profilen {n}",
|
"errorCreateProfile": "Det gick inte att skapa profilen {n}",
|
||||||
"errorSetDefaultProfile": "Det gick inte att ange standardprofil.",
|
"errorSetDefaultProfile": "Det gick inte att ange standardprofil.",
|
||||||
"errorLoadUsers": "Det gick inte att läsa in användare.",
|
"errorLoadUsers": "Det gick inte att läsa in användare.",
|
||||||
"errorSaveSettings": "Det gick inte att spara inställningarna.",
|
|
||||||
"errorLoadSettings": "Det gick inte att läsa in inställningarna.",
|
"errorLoadSettings": "Det gick inte att läsa in inställningarna.",
|
||||||
"errorSetOmbiDefaults": "Det gick inte att lagra ombi-standardvärden.",
|
"errorSetOmbiDefaults": "Det gick inte att lagra ombi-standardvärden.",
|
||||||
"errorLoadOmbiUsers": "Det gick inte att ladda ombi-användare.",
|
"errorLoadOmbiUsers": "Det gick inte att ladda ombi-användare.",
|
||||||
|
@ -18,16 +18,10 @@
|
|||||||
"create": "Tạo mới",
|
"create": "Tạo mới",
|
||||||
"apply": "Áp dụng",
|
"apply": "Áp dụng",
|
||||||
"delete": "Xóa",
|
"delete": "Xóa",
|
||||||
"add": "Thêm",
|
|
||||||
"select": "Chọn",
|
"select": "Chọn",
|
||||||
"name": "Tên",
|
"name": "Tên",
|
||||||
"date": "Ngày",
|
"date": "Ngày",
|
||||||
"enabled": "Mở",
|
|
||||||
"disabled": "Tắt",
|
|
||||||
"reEnable": "Mở lại",
|
|
||||||
"setExpiry": "Đặt hết hạn",
|
"setExpiry": "Đặt hết hạn",
|
||||||
"disable": "Tắt",
|
|
||||||
"admin": "Admin",
|
|
||||||
"updates": "Cập nhật",
|
"updates": "Cập nhật",
|
||||||
"update": "Cập nhật",
|
"update": "Cập nhật",
|
||||||
"download": "Tải về",
|
"download": "Tải về",
|
||||||
@ -36,7 +30,6 @@
|
|||||||
"lastActiveTime": "Lần cuối Hoạt động",
|
"lastActiveTime": "Lần cuối Hoạt động",
|
||||||
"from": "Từ",
|
"from": "Từ",
|
||||||
"user": "Người dùng",
|
"user": "Người dùng",
|
||||||
"expiry": "Hết hạn",
|
|
||||||
"userExpiry": "Hết hạn Người dùng",
|
"userExpiry": "Hết hạn Người dùng",
|
||||||
"userExpiryDescription": "Sau một khoảng thời gian nhất định sau khi mỗi đăng ký, jfa-go sẽ xóa/vô hiệu hóa tài khoản. Bạn có thể chỉnh sửa chế độ này trong cài đặt.",
|
"userExpiryDescription": "Sau một khoảng thời gian nhất định sau khi mỗi đăng ký, jfa-go sẽ xóa/vô hiệu hóa tài khoản. Bạn có thể chỉnh sửa chế độ này trong cài đặt.",
|
||||||
"aboutProgram": "Thông tin",
|
"aboutProgram": "Thông tin",
|
||||||
@ -54,7 +47,6 @@
|
|||||||
"conditionals": "Điều kiện",
|
"conditionals": "Điều kiện",
|
||||||
"preview": "Xem trước",
|
"preview": "Xem trước",
|
||||||
"reset": "Đặt lại",
|
"reset": "Đặt lại",
|
||||||
"edit": "Chỉnh sửa",
|
|
||||||
"donate": "Đóng góp",
|
"donate": "Đóng góp",
|
||||||
"sendPWR": "Gửi Đặt lại Mật khẩu",
|
"sendPWR": "Gửi Đặt lại Mật khẩu",
|
||||||
"contactThrough": "Liên lạc qua:",
|
"contactThrough": "Liên lạc qua:",
|
||||||
@ -135,7 +127,6 @@
|
|||||||
"errorCreateProfile": "",
|
"errorCreateProfile": "",
|
||||||
"errorSetDefaultProfile": "",
|
"errorSetDefaultProfile": "",
|
||||||
"errorLoadUsers": "",
|
"errorLoadUsers": "",
|
||||||
"errorSaveSettings": "",
|
|
||||||
"errorLoadSettings": "",
|
"errorLoadSettings": "",
|
||||||
"errorSetOmbiProfile": "",
|
"errorSetOmbiProfile": "",
|
||||||
"errorLoadOmbiUsers": "",
|
"errorLoadOmbiUsers": "",
|
||||||
|
@ -18,15 +18,9 @@
|
|||||||
"create": "创建",
|
"create": "创建",
|
||||||
"apply": "申请",
|
"apply": "申请",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"add": "添加",
|
|
||||||
"select": "选择",
|
"select": "选择",
|
||||||
"name": "名称",
|
"name": "名称",
|
||||||
"date": "日期",
|
"date": "日期",
|
||||||
"enabled": "已启用",
|
|
||||||
"disabled": "已禁用",
|
|
||||||
"reEnable": "重新启用",
|
|
||||||
"disable": "禁用",
|
|
||||||
"admin": "管理员",
|
|
||||||
"updates": "更新",
|
"updates": "更新",
|
||||||
"update": "更新",
|
"update": "更新",
|
||||||
"download": "下载",
|
"download": "下载",
|
||||||
@ -35,7 +29,6 @@
|
|||||||
"lastActiveTime": "上次活动",
|
"lastActiveTime": "上次活动",
|
||||||
"from": "从",
|
"from": "从",
|
||||||
"user": "用户",
|
"user": "用户",
|
||||||
"expiry": "到期",
|
|
||||||
"userExpiry": "用户到期",
|
"userExpiry": "用户到期",
|
||||||
"userExpiryDescription": "每次注册后的指定时间,jfa-go 将删除/禁用该帐户。您可以在设置中更改此行为。",
|
"userExpiryDescription": "每次注册后的指定时间,jfa-go 将删除/禁用该帐户。您可以在设置中更改此行为。",
|
||||||
"aboutProgram": "关于",
|
"aboutProgram": "关于",
|
||||||
@ -53,7 +46,6 @@
|
|||||||
"conditionals": "条件性条款",
|
"conditionals": "条件性条款",
|
||||||
"preview": "预览",
|
"preview": "预览",
|
||||||
"reset": "重设",
|
"reset": "重设",
|
||||||
"edit": "编辑",
|
|
||||||
"donate": "捐助",
|
"donate": "捐助",
|
||||||
"contactThrough": "联系方式:",
|
"contactThrough": "联系方式:",
|
||||||
"extendExpiry": "延长有效期",
|
"extendExpiry": "延长有效期",
|
||||||
@ -137,7 +129,6 @@
|
|||||||
"errorCreateProfile": "创建配置文件{n}失败",
|
"errorCreateProfile": "创建配置文件{n}失败",
|
||||||
"errorSetDefaultProfile": "设置默认配置文件失败。",
|
"errorSetDefaultProfile": "设置默认配置文件失败。",
|
||||||
"errorLoadUsers": "加载用户列表失败。",
|
"errorLoadUsers": "加载用户列表失败。",
|
||||||
"errorSaveSettings": "无法保存设置。",
|
|
||||||
"errorLoadSettings": "加载配置列表失败。",
|
"errorLoadSettings": "加载配置列表失败。",
|
||||||
"errorSetOmbiDefaults": "存储Ombi默认值失败。",
|
"errorSetOmbiDefaults": "存储Ombi默认值失败。",
|
||||||
"errorLoadOmbiUsers": "加载ombi用户列表失败。",
|
"errorLoadOmbiUsers": "加载ombi用户列表失败。",
|
||||||
|
@ -18,16 +18,10 @@
|
|||||||
"create": "創建",
|
"create": "創建",
|
||||||
"apply": "應用",
|
"apply": "應用",
|
||||||
"delete": "刪除",
|
"delete": "刪除",
|
||||||
"add": "添加",
|
|
||||||
"select": "選擇",
|
"select": "選擇",
|
||||||
"name": "帳戶名稱",
|
"name": "帳戶名稱",
|
||||||
"date": "日期",
|
"date": "日期",
|
||||||
"enabled": "已啟用",
|
|
||||||
"disabled": "已禁用",
|
|
||||||
"reEnable": "重新啟用",
|
|
||||||
"setExpiry": "設置到期時間",
|
"setExpiry": "設置到期時間",
|
||||||
"disable": "禁用",
|
|
||||||
"admin": "管理員",
|
|
||||||
"updates": "更新",
|
"updates": "更新",
|
||||||
"update": "更新",
|
"update": "更新",
|
||||||
"download": "下載",
|
"download": "下載",
|
||||||
@ -36,7 +30,6 @@
|
|||||||
"lastActiveTime": "上次啟用時間",
|
"lastActiveTime": "上次啟用時間",
|
||||||
"from": "從",
|
"from": "從",
|
||||||
"user": "帳戶",
|
"user": "帳戶",
|
||||||
"expiry": "到期",
|
|
||||||
"userExpiry": "帳戶到期",
|
"userExpiry": "帳戶到期",
|
||||||
"userExpiryDescription": "每次註冊后指定的時間,jfa-go 將刪除/禁用該帳戶。您可以在設定中更改此行為。",
|
"userExpiryDescription": "每次註冊后指定的時間,jfa-go 將刪除/禁用該帳戶。您可以在設定中更改此行為。",
|
||||||
"aboutProgram": "關於",
|
"aboutProgram": "關於",
|
||||||
@ -55,7 +48,6 @@
|
|||||||
"conditionals": "條件",
|
"conditionals": "條件",
|
||||||
"preview": "預覽",
|
"preview": "預覽",
|
||||||
"reset": "重設",
|
"reset": "重設",
|
||||||
"edit": "編輯",
|
|
||||||
"donate": "捐贈",
|
"donate": "捐贈",
|
||||||
"sendPWR": "發送密碼重置",
|
"sendPWR": "發送密碼重置",
|
||||||
"contactThrough": "聯繫方式:",
|
"contactThrough": "聯繫方式:",
|
||||||
@ -136,7 +128,6 @@
|
|||||||
"errorCreateProfile": "無法創建設置文件 {n}",
|
"errorCreateProfile": "無法創建設置文件 {n}",
|
||||||
"errorSetDefaultProfile": "無法設置預設設置文件。",
|
"errorSetDefaultProfile": "無法設置預設設置文件。",
|
||||||
"errorLoadUsers": "無法讀取帳戶。",
|
"errorLoadUsers": "無法讀取帳戶。",
|
||||||
"errorSaveSettings": "無法儲存設置。",
|
|
||||||
"errorLoadSettings": "無法讀取設置。",
|
"errorLoadSettings": "無法讀取設置。",
|
||||||
"errorSetOmbiProfile": "無法儲存 ombi 設置文件。",
|
"errorSetOmbiProfile": "無法儲存 ombi 設置文件。",
|
||||||
"errorLoadOmbiUsers": "無法讀取 ombi 帳戶。",
|
"errorLoadOmbiUsers": "無法讀取 ombi 帳戶。",
|
||||||
|
@ -3,5 +3,6 @@
|
|||||||
"name": "العربية (AR)"
|
"name": "العربية (AR)"
|
||||||
},
|
},
|
||||||
"strings": {},
|
"strings": {},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Opdater",
|
"refresh": "Opdater",
|
||||||
"required": "Påkrævet",
|
"required": "Påkrævet",
|
||||||
"login": "Log på",
|
"login": "Log på",
|
||||||
"logout": "Log ud"
|
"logout": "Log ud",
|
||||||
|
"admin": "Administrator",
|
||||||
|
"enabled": "Aktiveret",
|
||||||
|
"disabled": "Deaktiveret",
|
||||||
|
"reEnable": "Genaktiver",
|
||||||
|
"disable": "Deaktiver",
|
||||||
|
"expiry": "Udløb",
|
||||||
|
"add": "Tilføj",
|
||||||
|
"edit": "Rediger"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Brugernavnet og/eller adgangskoden blev efterladt tomme.",
|
"errorLoginBlank": "Brugernavnet og/eller adgangskoden blev efterladt tomme.",
|
||||||
"errorConnection": "Kunne ikke oprette forbindelse til jfa-go.",
|
"errorConnection": "Kunne ikke oprette forbindelse til jfa-go.",
|
||||||
"errorUnknown": "Ukendt fejl.",
|
"errorUnknown": "Ukendt fejl.",
|
||||||
"error401Unauthorized": "Adgang nægtet. Prøv at genindlæse siden."
|
"error401Unauthorized": "Adgang nægtet. Prøv at genindlæse siden.",
|
||||||
}
|
"errorSaveSettings": "Kunne ikke gemme indstillingerne."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Aktualisieren",
|
"refresh": "Aktualisieren",
|
||||||
"required": "Erforderlich",
|
"required": "Erforderlich",
|
||||||
"login": "Anmelden",
|
"login": "Anmelden",
|
||||||
"logout": "Abmelden"
|
"logout": "Abmelden",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Aktiviert",
|
||||||
|
"disabled": "Deaktiviert",
|
||||||
|
"reEnable": "Wieder aktivieren",
|
||||||
|
"disable": "Deaktivieren",
|
||||||
|
"expiry": "Ablaufdatum",
|
||||||
|
"add": "Hinzufügen",
|
||||||
|
"edit": "Bearbeiten"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
|
"errorLoginBlank": "Der Benutzername und/oder das Passwort wurden nicht ausgefüllt.",
|
||||||
"errorConnection": "Konnte keine Verbindung zu jfa-go herstellen.",
|
"errorConnection": "Konnte keine Verbindung zu jfa-go herstellen.",
|
||||||
"errorUnknown": "Unbekannter Fehler.",
|
"errorUnknown": "Unbekannter Fehler.",
|
||||||
"error401Unauthorized": "Unberechtigt. Versuch, die Seite zu aktualisieren."
|
"error401Unauthorized": "Unberechtigt. Versuch, die Seite zu aktualisieren.",
|
||||||
}
|
"errorSaveSettings": "Einstellungen konnten nicht gespeichert werden."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -17,12 +17,21 @@
|
|||||||
"time12h": "12 Ώρες",
|
"time12h": "12 Ώρες",
|
||||||
"theme": "Θέμα",
|
"theme": "Θέμα",
|
||||||
"login": "Σύνδεση",
|
"login": "Σύνδεση",
|
||||||
"logout": "Αποσύνδεση"
|
"logout": "Αποσύνδεση",
|
||||||
|
"admin": "Διαχειριστής",
|
||||||
|
"enabled": "Ενεργοποιημένο",
|
||||||
|
"disabled": "Απενεργοποιημένο",
|
||||||
|
"reEnable": "Επανα-ενεργοποίηση",
|
||||||
|
"disable": "Απενεργοποίηση",
|
||||||
|
"expiry": "Λήξη",
|
||||||
|
"edit": "Επεξεργασία"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
|
"errorLoginBlank": "Το όνομα χρήστη και/ή ο κωδικός ήταν κενά.",
|
||||||
"errorConnection": "Δεν μπόρεσε να συνδεθεί με το jfa-go.",
|
"errorConnection": "Δεν μπόρεσε να συνδεθεί με το jfa-go.",
|
||||||
"errorUnknown": "Άγνωστο σφάλμα.",
|
"errorUnknown": "Άγνωστο σφάλμα.",
|
||||||
"error401Unauthorized": "Ανεξουσιοδότητος. Προσπαθήστε να κάνετε επαναφόρτωση την σελίδα."
|
"error401Unauthorized": "Ανεξουσιοδότητος. Προσπαθήστε να κάνετε επαναφόρτωση την σελίδα.",
|
||||||
}
|
"errorSaveSettings": "Αποτυχία αποθήκευσης ρυθμίσεων."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"required": "Required",
|
"required": "Required",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Logout"
|
"logout": "Logout",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"reEnable": "Re-enable",
|
||||||
|
"disable": "Disable",
|
||||||
|
"expiry": "Expiry",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "The username and/or password was left blank.",
|
"errorLoginBlank": "The username and/or password was left blank.",
|
||||||
"errorConnection": "Couldn't connect to jfa-go.",
|
"errorConnection": "Couldn't connect to jfa-go.",
|
||||||
"errorUnknown": "Unknown error.",
|
"errorUnknown": "Unknown error.",
|
||||||
"error401Unauthorized": "Unauthorised. Try refreshing the page."
|
"error401Unauthorized": "Unauthorised. Try refreshing the page.",
|
||||||
}
|
"errorSaveSettings": "Couldn't save settings."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,40 @@
|
|||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"required": "Required",
|
"required": "Required",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Logout"
|
"logout": "Logout",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Enabled",
|
||||||
|
"disabled": "Disabled",
|
||||||
|
"reEnable": "Re-enable",
|
||||||
|
"disable": "Disable",
|
||||||
|
"contactMethods": "Contact Methods",
|
||||||
|
"addContactMethod": "Add Contact Method",
|
||||||
|
"editContactMethod": "Edit Contact Method",
|
||||||
|
"accountStatus": "Account Status",
|
||||||
|
"notSet": "Not set",
|
||||||
|
"expiry": "Expiry",
|
||||||
|
"add": "Add",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "The username and/or password were left blank.",
|
"errorLoginBlank": "The username and/or password were left blank.",
|
||||||
"errorConnection": "Couldn't connect to jfa-go.",
|
"errorConnection": "Couldn't connect to jfa-go.",
|
||||||
"errorUnknown": "Unknown error.",
|
"errorUnknown": "Unknown error.",
|
||||||
"error401Unauthorized": "Unauthorized. Try refreshing the page."
|
"error401Unauthorized": "Unauthorized. Try refreshing the page.",
|
||||||
|
"errorSaveSettings": "Couldn't save settings."
|
||||||
|
},
|
||||||
|
"quantityStrings": {
|
||||||
|
"year": {
|
||||||
|
"singular": "{n} Year",
|
||||||
|
"plural": "{n} Years"
|
||||||
|
},
|
||||||
|
"month": {
|
||||||
|
"singular": "{n} Month",
|
||||||
|
"plural": "{n} Months"
|
||||||
|
},
|
||||||
|
"day": {
|
||||||
|
"singular": "{n} Day",
|
||||||
|
"plural": "{n} Days"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Refrescar",
|
"refresh": "Refrescar",
|
||||||
"required": "Requerido",
|
"required": "Requerido",
|
||||||
"login": "Acceso",
|
"login": "Acceso",
|
||||||
"logout": "Cerrar sesión"
|
"logout": "Cerrar sesión",
|
||||||
|
"admin": "Administrador",
|
||||||
|
"enabled": "Activado",
|
||||||
|
"disabled": "Desactivado",
|
||||||
|
"reEnable": "Reactivar",
|
||||||
|
"disable": "Desactivar",
|
||||||
|
"expiry": "Expiración",
|
||||||
|
"add": "Agregar",
|
||||||
|
"edit": "Editar"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
|
"errorLoginBlank": "El nombre de usuario y/o la contraseña se dejaron en blanco.",
|
||||||
"errorConnection": "No se pudo conectar a jfa-go.",
|
"errorConnection": "No se pudo conectar a jfa-go.",
|
||||||
"errorUnknown": "Error desconocido.",
|
"errorUnknown": "Error desconocido.",
|
||||||
"error401Unauthorized": "No autorizado. Intente actualizar la página."
|
"error401Unauthorized": "No autorizado. Intente actualizar la página.",
|
||||||
}
|
"errorSaveSettings": "No se pudo guardar la configuración."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -24,5 +24,6 @@
|
|||||||
"contactDiscord": "از طریق دیسکورد تماس بگیرید",
|
"contactDiscord": "از طریق دیسکورد تماس بگیرید",
|
||||||
"theme": "موضوع"
|
"theme": "موضوع"
|
||||||
},
|
},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Actualiser",
|
"refresh": "Actualiser",
|
||||||
"required": "Requis",
|
"required": "Requis",
|
||||||
"login": "S'identifier",
|
"login": "S'identifier",
|
||||||
"logout": "Se déconnecter"
|
"logout": "Se déconnecter",
|
||||||
|
"admin": "Administrateur",
|
||||||
|
"enabled": "Activé",
|
||||||
|
"disabled": "Désactivé",
|
||||||
|
"reEnable": "Ré-activé",
|
||||||
|
"disable": "Désactivé",
|
||||||
|
"expiry": "Expiration",
|
||||||
|
"add": "Ajouter",
|
||||||
|
"edit": "Éditer"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
"errorLoginBlank": "Le nom d'utilisateur et/ou le mot de passe sont vides.",
|
||||||
"errorConnection": "Impossible de se connecter à jfa-go.",
|
"errorConnection": "Impossible de se connecter à jfa-go.",
|
||||||
"errorUnknown": "Erreur inconnue.",
|
"errorUnknown": "Erreur inconnue.",
|
||||||
"error401Unauthorized": "Non autorisé. Essayez d'actualiser la page."
|
"error401Unauthorized": "Non autorisé. Essayez d'actualiser la page.",
|
||||||
}
|
"errorSaveSettings": "Impossible d'enregistrer les paramètres."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -4,7 +4,16 @@
|
|||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"login": "Belépés",
|
"login": "Belépés",
|
||||||
"logout": "Kijelentkezés"
|
"logout": "Kijelentkezés",
|
||||||
|
"admin": "Adminisztrátor",
|
||||||
|
"enabled": "Engedélyezve",
|
||||||
|
"disabled": "Tiltva",
|
||||||
|
"reEnable": "Újra engedélyezés",
|
||||||
|
"disable": "Letiltás",
|
||||||
|
"expiry": "Lejárat",
|
||||||
|
"add": "Hozzáadás",
|
||||||
|
"edit": "Szerkesztés"
|
||||||
},
|
},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -17,12 +17,15 @@
|
|||||||
"time12h": "Waktu 12 jam",
|
"time12h": "Waktu 12 jam",
|
||||||
"theme": "Tema",
|
"theme": "Tema",
|
||||||
"login": "Masuk",
|
"login": "Masuk",
|
||||||
"logout": "Keluar"
|
"logout": "Keluar",
|
||||||
|
"edit": "Edit"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Nama pengguna dan / atau sandi kosong.",
|
"errorLoginBlank": "Nama pengguna dan / atau sandi kosong.",
|
||||||
"errorConnection": "Tidak dapat terhubung ke jfa-go.",
|
"errorConnection": "Tidak dapat terhubung ke jfa-go.",
|
||||||
"errorUnknown": "Kesalahan yang tidak diketahui.",
|
"errorUnknown": "Kesalahan yang tidak diketahui.",
|
||||||
"error401Unauthorized": "Tidak ter-otorisasi. Coba segarkan halaman."
|
"error401Unauthorized": "Tidak ter-otorisasi. Coba segarkan halaman.",
|
||||||
}
|
"errorSaveSettings": "Tidak dapat menyimpan pengaturan."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,5 +26,6 @@
|
|||||||
"refresh": "Aggiorna",
|
"refresh": "Aggiorna",
|
||||||
"required": "Richiesto"
|
"required": "Richiesto"
|
||||||
},
|
},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Ververs",
|
"refresh": "Ververs",
|
||||||
"required": "Verplicht",
|
"required": "Verplicht",
|
||||||
"login": "Inloggen",
|
"login": "Inloggen",
|
||||||
"logout": "Uitloggen"
|
"logout": "Uitloggen",
|
||||||
|
"admin": "Beheerder",
|
||||||
|
"enabled": "Ingeschakeld",
|
||||||
|
"disabled": "Uitgeschakeld",
|
||||||
|
"reEnable": "Opnieuw inschakelen",
|
||||||
|
"disable": "Uitschakelen",
|
||||||
|
"expiry": "Verloop",
|
||||||
|
"add": "Voeg toe",
|
||||||
|
"edit": "Bewerken"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
|
"errorLoginBlank": "De gebruikersnaam en/of wachtwoord is leeg.",
|
||||||
"errorConnection": "Kon geen verbinding maken met jfa-go.",
|
"errorConnection": "Kon geen verbinding maken met jfa-go.",
|
||||||
"errorUnknown": "Onbekende fout.",
|
"errorUnknown": "Onbekende fout.",
|
||||||
"error401Unauthorized": "Geen toegang. Probeer de pagina te vernieuwen."
|
"error401Unauthorized": "Geen toegang. Probeer de pagina te vernieuwen.",
|
||||||
}
|
"errorSaveSettings": "Opslaan van instellingen mislukt."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -24,11 +24,18 @@
|
|||||||
"contactDiscord": "Kontakt przez Discord",
|
"contactDiscord": "Kontakt przez Discord",
|
||||||
"theme": "Motyw",
|
"theme": "Motyw",
|
||||||
"refresh": "Odśwież",
|
"refresh": "Odśwież",
|
||||||
"required": "Wymagane"
|
"required": "Wymagane",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Włączone",
|
||||||
|
"disabled": "Wyłączone",
|
||||||
|
"disable": "Wyłączone",
|
||||||
|
"expiry": "Wygasa",
|
||||||
|
"edit": "Edytuj"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorConnection": "Nie udało się połączyć z jfa-go.",
|
"errorConnection": "Nie udało się połączyć z jfa-go.",
|
||||||
"errorUnknown": "Nieznany błąd.",
|
"errorUnknown": "Nieznany błąd.",
|
||||||
"error401Unauthorized": "Nieautoryzowany. Spróbuj odświeżyć stronę."
|
"error401Unauthorized": "Nieautoryzowany. Spróbuj odświeżyć stronę."
|
||||||
}
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "Atualizar",
|
"refresh": "Atualizar",
|
||||||
"required": "Requeridos",
|
"required": "Requeridos",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
"logout": "Sair"
|
"logout": "Sair",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Habilitado",
|
||||||
|
"disabled": "Desativado",
|
||||||
|
"reEnable": "Reativar",
|
||||||
|
"disable": "Desativar",
|
||||||
|
"expiry": "Expira",
|
||||||
|
"add": "Adicionar",
|
||||||
|
"edit": "Editar"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
|
"errorLoginBlank": "O nome de usuário e/ou senha foram deixados em branco.",
|
||||||
"errorConnection": "Não foi possível conectar ao jfa-go.",
|
"errorConnection": "Não foi possível conectar ao jfa-go.",
|
||||||
"errorUnknown": "Erro desconhecido.",
|
"errorUnknown": "Erro desconhecido.",
|
||||||
"error401Unauthorized": "Não autorizado. Tente atualizar a página."
|
"error401Unauthorized": "Não autorizado. Tente atualizar a página.",
|
||||||
}
|
"errorSaveSettings": "Não foi possível salvar as configurações."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -3,5 +3,6 @@
|
|||||||
"name": "Română (ROU)"
|
"name": "Română (ROU)"
|
||||||
},
|
},
|
||||||
"strings": {},
|
"strings": {},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,5 +26,6 @@
|
|||||||
"refresh": "Osveži",
|
"refresh": "Osveži",
|
||||||
"required": "Obvezno"
|
"required": "Obvezno"
|
||||||
},
|
},
|
||||||
"notifications": {}
|
"notifications": {},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -16,12 +16,19 @@
|
|||||||
"time12h": "12 timmarsklocka",
|
"time12h": "12 timmarsklocka",
|
||||||
"theme": "Tema",
|
"theme": "Tema",
|
||||||
"login": "Logga in",
|
"login": "Logga in",
|
||||||
"logout": "Logga ut"
|
"logout": "Logga ut",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Aktiverad",
|
||||||
|
"disabled": "Inaktiverad",
|
||||||
|
"expiry": "Löper ut",
|
||||||
|
"edit": "Redigera"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
"errorLoginBlank": "Användarnamnet och/eller lösenordet lämnades tomt.",
|
||||||
"errorConnection": "Det gick inte att ansluta till jfa-go.",
|
"errorConnection": "Det gick inte att ansluta till jfa-go.",
|
||||||
"errorUnknown": "Okänt fel.",
|
"errorUnknown": "Okänt fel.",
|
||||||
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan."
|
"error401Unauthorized": "Obehörig. Prova att uppdatera sidan.",
|
||||||
}
|
"errorSaveSettings": "Det gick inte att spara inställningarna."
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -4,10 +4,19 @@
|
|||||||
},
|
},
|
||||||
"strings": {
|
"strings": {
|
||||||
"login": "Đăng nhập",
|
"login": "Đăng nhập",
|
||||||
"logout": "Đăng xuất"
|
"logout": "Đăng xuất",
|
||||||
|
"admin": "Admin",
|
||||||
|
"enabled": "Mở",
|
||||||
|
"disabled": "Tắt",
|
||||||
|
"reEnable": "Mở lại",
|
||||||
|
"disable": "Tắt",
|
||||||
|
"expiry": "Hết hạn",
|
||||||
|
"add": "Thêm",
|
||||||
|
"edit": "Chỉnh sửa"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorConnection": "Không thể kết nối với jfa-go.",
|
"errorConnection": "Không thể kết nối với jfa-go.",
|
||||||
"error401Unauthorized": "Không được phép. Hãy thử làm mới trang."
|
"error401Unauthorized": "Không được phép. Hãy thử làm mới trang."
|
||||||
}
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "刷新",
|
"refresh": "刷新",
|
||||||
"required": "必需的",
|
"required": "必需的",
|
||||||
"login": "登录",
|
"login": "登录",
|
||||||
"logout": "登出"
|
"logout": "登出",
|
||||||
|
"admin": "管理员",
|
||||||
|
"enabled": "已启用",
|
||||||
|
"disabled": "已禁用",
|
||||||
|
"reEnable": "重新启用",
|
||||||
|
"disable": "禁用",
|
||||||
|
"expiry": "到期",
|
||||||
|
"add": "添加",
|
||||||
|
"edit": "编辑"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "用户名/密码留空。",
|
"errorLoginBlank": "用户名/密码留空。",
|
||||||
"errorConnection": "无法连接到 jfa-go。",
|
"errorConnection": "无法连接到 jfa-go。",
|
||||||
"errorUnknown": "未知错误。",
|
"errorUnknown": "未知错误。",
|
||||||
"error401Unauthorized": "无授权。尝试刷新页面。"
|
"error401Unauthorized": "无授权。尝试刷新页面。",
|
||||||
}
|
"errorSaveSettings": "无法保存设置。"
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -26,12 +26,22 @@
|
|||||||
"refresh": "重新整理",
|
"refresh": "重新整理",
|
||||||
"required": "必填",
|
"required": "必填",
|
||||||
"login": "登錄",
|
"login": "登錄",
|
||||||
"logout": "登出"
|
"logout": "登出",
|
||||||
|
"admin": "管理員",
|
||||||
|
"enabled": "已啟用",
|
||||||
|
"disabled": "已禁用",
|
||||||
|
"reEnable": "重新啟用",
|
||||||
|
"disable": "禁用",
|
||||||
|
"expiry": "到期",
|
||||||
|
"add": "添加",
|
||||||
|
"edit": "編輯"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "帳戶名稱和/或密碼留空。",
|
"errorLoginBlank": "帳戶名稱和/或密碼留空。",
|
||||||
"errorConnection": "無法連接到 jfa-go。",
|
"errorConnection": "無法連接到 jfa-go。",
|
||||||
"errorUnknown": "未知的錯誤。",
|
"errorUnknown": "未知的錯誤。",
|
||||||
"error401Unauthorized": "未經授權。嘗試重新整理頁面。"
|
"error401Unauthorized": "未經授權。嘗試重新整理頁面。",
|
||||||
}
|
"errorSaveSettings": "無法儲存設置。"
|
||||||
|
},
|
||||||
|
"quantityStrings": {}
|
||||||
}
|
}
|
@ -20,7 +20,7 @@
|
|||||||
"sendPIN": "Send the PIN below to the bot, then come back here to link your account.",
|
"sendPIN": "Send the PIN below to the bot, then come back here to link your account.",
|
||||||
"sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below.",
|
"sendPINDiscord": "Type {command} in {server_channel} on Discord, then send the PIN below.",
|
||||||
"matrixEnterUser": "Enter your User ID, press submit, and a PIN will be sent to you. Enter it here to continue.",
|
"matrixEnterUser": "Enter your User ID, press submit, and a PIN will be sent to you. Enter it here to continue.",
|
||||||
"welcomeUser": "Welcome, {user}"
|
"welcomeUser": "Welcome, {user}!"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorUserExists": "User already exists.",
|
"errorUserExists": "User already exists.",
|
||||||
|
23
models.go
23
models.go
@ -378,4 +378,27 @@ type ReCaptchaResponseDTO struct {
|
|||||||
type MyDetailsDTO struct {
|
type MyDetailsDTO struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
Expiry int64 `json:"expiry"`
|
||||||
|
Admin bool `json:"admin"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
Email *MyDetailsContactMethodsDTO `json:"email,omitempty"`
|
||||||
|
Discord *MyDetailsContactMethodsDTO `json:"discord,omitempty"`
|
||||||
|
Telegram *MyDetailsContactMethodsDTO `json:"telegram,omitempty"`
|
||||||
|
Matrix *MyDetailsContactMethodsDTO `json:"matrix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MyDetailsContactMethodsDTO struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ModifyMyEmailDTO struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConfirmationTarget int
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserEmailChange ConfirmationTarget = iota
|
||||||
|
NoOp
|
||||||
|
)
|
||||||
|
@ -147,6 +147,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
router.GET(p+"/my/account", app.MyUserPage)
|
router.GET(p+"/my/account", app.MyUserPage)
|
||||||
router.GET(p+"/my/token/login", app.getUserTokenLogin)
|
router.GET(p+"/my/token/login", app.getUserTokenLogin)
|
||||||
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
|
router.GET(p+"/my/token/refresh", app.getUserTokenRefresh)
|
||||||
|
router.GET(p+"/my/confirm/:jwt", app.ConfirmMyAction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if *SWAGGER {
|
if *SWAGGER {
|
||||||
@ -227,6 +228,9 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
|
|
||||||
if userPageEnabled {
|
if userPageEnabled {
|
||||||
user.GET(p+"/details", app.MyDetails)
|
user.GET(p+"/details", app.MyDetails)
|
||||||
|
user.POST(p+"/contact", app.SetMyContactMethods)
|
||||||
|
user.POST(p+"/logout", app.LogoutUser)
|
||||||
|
user.POST(p+"/email", app.ModifyMyEmail)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
scripts/langmover/common.json
Normal file
54
scripts/langmover/common.json
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"name": "English (US)"
|
||||||
|
},
|
||||||
|
"strings": {
|
||||||
|
"username": "common",
|
||||||
|
"password": "common",
|
||||||
|
"emailAddress": "common",
|
||||||
|
"name": "common",
|
||||||
|
"submit": "common",
|
||||||
|
"send": "common",
|
||||||
|
"success": "common",
|
||||||
|
"continue": "common",
|
||||||
|
"error": "common",
|
||||||
|
"copy": "common",
|
||||||
|
"copied": "common",
|
||||||
|
"time24h": "common",
|
||||||
|
"time12h": "common",
|
||||||
|
"linkTelegram": "common",
|
||||||
|
"contactEmail": "common",
|
||||||
|
"contactTelegram": "common",
|
||||||
|
"linkDiscord": "common",
|
||||||
|
"linkMatrix": "common",
|
||||||
|
"contactDiscord": "common",
|
||||||
|
"theme": "common",
|
||||||
|
"refresh": "common",
|
||||||
|
"required": "common",
|
||||||
|
"login": "common",
|
||||||
|
"logout": "common",
|
||||||
|
"admin": "common",
|
||||||
|
"enabled": "common",
|
||||||
|
"disabled": "common",
|
||||||
|
"reEnable": "common",
|
||||||
|
"disable": "common",
|
||||||
|
"contactMethods": "common",
|
||||||
|
"accountStatus": "common",
|
||||||
|
"notSet": "common",
|
||||||
|
"expiry": "common",
|
||||||
|
"add": "admin",
|
||||||
|
"edit": "admin"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"errorLoginBlank": "common",
|
||||||
|
"errorConnection": "common",
|
||||||
|
"errorUnknown": "common",
|
||||||
|
"error401Unauthorized": "common",
|
||||||
|
"errorSaveSettings": "common"
|
||||||
|
},
|
||||||
|
"quantityStrings": {
|
||||||
|
"year": "common",
|
||||||
|
"month": "common",
|
||||||
|
"day": "common"
|
||||||
|
}
|
||||||
|
}
|
@ -23,13 +23,19 @@
|
|||||||
"theme": "common",
|
"theme": "common",
|
||||||
"refresh": "common",
|
"refresh": "common",
|
||||||
"required": "common",
|
"required": "common",
|
||||||
"login": "admin",
|
"login": "common",
|
||||||
"logout": "admin"
|
"logout": "common",
|
||||||
|
"admin": "common",
|
||||||
|
"enabled": "common",
|
||||||
|
"disabled": "common",
|
||||||
|
"reEnable": "common",
|
||||||
|
"disable": "common"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorLoginBlank": "admin",
|
"errorLoginBlank": "common",
|
||||||
"errorConnection": "admin",
|
"errorConnection": "common",
|
||||||
"errorUnknown": "admin",
|
"errorUnknown": "common",
|
||||||
"error401Unauthorized": "admin"
|
"error401Unauthorized": "common",
|
||||||
|
"errorSaveSettings": "admin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
37
storage.go
37
storage.go
@ -144,6 +144,10 @@ func (st *Storage) loadLang(filesystems ...fs.FS) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = st.loadLangEmail(filesystems...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
err = st.loadLangUser(filesystems...)
|
err = st.loadLangUser(filesystems...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -152,10 +156,6 @@ func (st *Storage) loadLang(filesystems ...fs.FS) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = st.loadLangEmail(filesystems...)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = st.loadLangTelegram(filesystems...)
|
err = st.loadLangTelegram(filesystems...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -202,6 +202,25 @@ func (common *commonLangs) patchCommonNotifications(to *langSection, from ...str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (common *commonLangs) patchCommonQuantityStrings(to *map[string]quantityString, from ...string) {
|
||||||
|
if *to == nil {
|
||||||
|
*to = map[string]quantityString{}
|
||||||
|
}
|
||||||
|
for n, ev := range (*common)[from[len(from)-1]].QuantityStrings {
|
||||||
|
if v, ok := (*to)[n]; !ok || (v.Singular == "" && v.Plural == "") {
|
||||||
|
i := 0
|
||||||
|
for i < len(from)-1 {
|
||||||
|
ev, ok = (*common)[from[i]].QuantityStrings[n]
|
||||||
|
if ok && ev.Singular != "" && ev.Plural != "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
(*to)[n] = ev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func patchLang(to *langSection, from ...*langSection) {
|
func patchLang(to *langSection, from ...*langSection) {
|
||||||
if *to == nil {
|
if *to == nil {
|
||||||
*to = langSection{}
|
*to = langSection{}
|
||||||
@ -283,10 +302,14 @@ func (st *Storage) loadLangCommon(filesystems ...fs.FS) error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
loadedLangs[fsIndex][lang.Meta.Fallback+".json"] = true
|
loadedLangs[fsIndex][lang.Meta.Fallback+".json"] = true
|
||||||
patchLang(&lang.Strings, &fallback.Strings, &english.Strings)
|
patchLang(&lang.Strings, &fallback.Strings, &english.Strings)
|
||||||
|
patchLang(&lang.Notifications, &fallback.Notifications, &english.Notifications)
|
||||||
|
patchQuantityStrings(&lang.QuantityStrings, &fallback.QuantityStrings, &english.QuantityStrings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lang.Meta.Fallback != "" && err != nil) || lang.Meta.Fallback == "" {
|
if (lang.Meta.Fallback != "" && err != nil) || lang.Meta.Fallback == "" {
|
||||||
patchLang(&lang.Strings, &english.Strings)
|
patchLang(&lang.Strings, &english.Strings)
|
||||||
|
patchLang(&lang.Notifications, &english.Notifications)
|
||||||
|
patchQuantityStrings(&lang.QuantityStrings, &english.QuantityStrings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
st.lang.Common[index] = lang
|
st.lang.Common[index] = lang
|
||||||
@ -437,6 +460,12 @@ func (st *Storage) loadLangUser(filesystems ...fs.FS) error {
|
|||||||
}
|
}
|
||||||
st.lang.Common.patchCommonStrings(&lang.Strings, index)
|
st.lang.Common.patchCommonStrings(&lang.Strings, index)
|
||||||
st.lang.Common.patchCommonNotifications(&lang.Notifications, index)
|
st.lang.Common.patchCommonNotifications(&lang.Notifications, index)
|
||||||
|
st.lang.Common.patchCommonQuantityStrings(&lang.QuantityStrings, index)
|
||||||
|
// turns out, a lot of email strings are useful on the user page.
|
||||||
|
emailLang := []langSection{st.lang.Email[index].WelcomeEmail, st.lang.Email[index].UserDisabled, st.lang.Email[index].UserExpired}
|
||||||
|
for _, v := range emailLang {
|
||||||
|
patchLang(&lang.Strings, &v)
|
||||||
|
}
|
||||||
if fname != "en-us.json" {
|
if fname != "en-us.json" {
|
||||||
if lang.Meta.Fallback != "" {
|
if lang.Meta.Fallback != "" {
|
||||||
fallback, ok := st.lang.User[lang.Meta.Fallback]
|
fallback, ok := st.lang.User[lang.Meta.Fallback]
|
||||||
|
10
ts/admin.ts
10
ts/admin.ts
@ -177,12 +177,6 @@ login.onLogin = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
login.login("", "");
|
login.bindLogout(document.getElementById("logout-button"));
|
||||||
|
|
||||||
(document.getElementById('logout-button') as HTMLButtonElement).onclick = () => _post("/logout", null, (req: XMLHttpRequest): boolean => {
|
login.login("", "");
|
||||||
if (req.readyState == 4 && req.status == 200) {
|
|
||||||
window.token = "";
|
|
||||||
location.reload();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
import { Modal } from "../modules/modal.js";
|
import { Modal } from "../modules/modal.js";
|
||||||
import { toggleLoader } from "../modules/common.js";
|
import { toggleLoader, _post } from "../modules/common.js";
|
||||||
|
|
||||||
export class Login {
|
export class Login {
|
||||||
private _modal: Modal;
|
private _modal: Modal;
|
||||||
private _form: HTMLFormElement;
|
private _form: HTMLFormElement;
|
||||||
private _url: string;
|
private _url: string;
|
||||||
private _onLogin: (username: string, password: string) => void;
|
private _onLogin: (username: string, password: string) => void;
|
||||||
|
private _logoutButton: HTMLElement = null;
|
||||||
|
|
||||||
constructor(modal: Modal, endpoint: string) {
|
constructor(modal: Modal, endpoint: string) {
|
||||||
|
|
||||||
this._url = window.URLBase + endpoint;
|
this._url = window.URLBase + endpoint;
|
||||||
if (this._url[this._url.length-1] != '/') this._url += "/";
|
if (this._url[this._url.length-1] != '/') this._url += "/";
|
||||||
this._url += "token/";
|
|
||||||
|
|
||||||
this._modal = modal;
|
this._modal = modal;
|
||||||
this._form = this._modal.asElement().querySelector(".form-login") as HTMLFormElement;
|
this._form = this._modal.asElement().querySelector(".form-login") as HTMLFormElement;
|
||||||
@ -29,6 +29,18 @@ export class Login {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindLogout = (button: HTMLElement) => {
|
||||||
|
this._logoutButton = button;
|
||||||
|
this._logoutButton.classList.add("unfocused");
|
||||||
|
this._logoutButton.onclick = () => _post(this._url + "logout", null, (req: XMLHttpRequest): boolean => {
|
||||||
|
if (req.readyState == 4 && req.status == 200) {
|
||||||
|
window.token = "";
|
||||||
|
location.reload();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
get onLogin() { return this._onLogin; }
|
get onLogin() { return this._onLogin; }
|
||||||
set onLogin(f: (username: string, password: string) => void) { this._onLogin = f; }
|
set onLogin(f: (username: string, password: string) => void) { this._onLogin = f; }
|
||||||
|
|
||||||
@ -36,7 +48,7 @@ export class Login {
|
|||||||
const req = new XMLHttpRequest();
|
const req = new XMLHttpRequest();
|
||||||
req.responseType = 'json';
|
req.responseType = 'json';
|
||||||
const refresh = (username == "" && password == "");
|
const refresh = (username == "" && password == "");
|
||||||
req.open("GET", this._url + (refresh ? "refresh" : "login"), true);
|
req.open("GET", this._url + (refresh ? "token/refresh" : "token/login"), true);
|
||||||
if (!refresh) {
|
if (!refresh) {
|
||||||
req.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password));
|
req.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password));
|
||||||
}
|
}
|
||||||
@ -46,6 +58,10 @@ export class Login {
|
|||||||
let errorMsg = window.lang.notif("errorConnection");
|
let errorMsg = window.lang.notif("errorConnection");
|
||||||
if (req.response) {
|
if (req.response) {
|
||||||
errorMsg = req.response["error"];
|
errorMsg = req.response["error"];
|
||||||
|
const langErrorMsg = window.lang.strings(errorMsg);
|
||||||
|
if (langErrorMsg) {
|
||||||
|
errorMsg = langErrorMsg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!errorMsg) {
|
if (!errorMsg) {
|
||||||
errorMsg = window.lang.notif("errorUnknown");
|
errorMsg = window.lang.notif("errorUnknown");
|
||||||
@ -62,7 +78,8 @@ export class Login {
|
|||||||
this._onLogin(username, password);
|
this._onLogin(username, password);
|
||||||
}
|
}
|
||||||
this._modal.close();
|
this._modal.close();
|
||||||
document.getElementById("logout-button").classList.remove("unfocused");
|
if (this._logoutButton != null)
|
||||||
|
this._logoutButton.classList.remove("unfocused");
|
||||||
}
|
}
|
||||||
if (run) { run(+req.status); }
|
if (run) { run(+req.status); }
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ declare interface Modals {
|
|||||||
matrix: Modal;
|
matrix: Modal;
|
||||||
sendPWR?: Modal;
|
sendPWR?: Modal;
|
||||||
logs: Modal;
|
logs: Modal;
|
||||||
|
email?: Modal;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Invite {
|
interface Invite {
|
||||||
|
287
ts/user.ts
287
ts/user.ts
@ -1,7 +1,7 @@
|
|||||||
import { ThemeManager } from "./modules/theme.js";
|
import { ThemeManager } from "./modules/theme.js";
|
||||||
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
|
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
|
||||||
import { Modal } from "./modules/modal.js";
|
import { Modal } from "./modules/modal.js";
|
||||||
import { _get, _post, notificationBox, whichAnimationEvent } from "./modules/common.js";
|
import { _get, _post, notificationBox, whichAnimationEvent, toDateString, toggleLoader } from "./modules/common.js";
|
||||||
import { Login } from "./modules/login.js";
|
import { Login } from "./modules/login.js";
|
||||||
|
|
||||||
interface userWindow extends Window {
|
interface userWindow extends Window {
|
||||||
@ -25,26 +25,299 @@ window.modals = {} as Modals;
|
|||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
window.modals.login = new Modal(document.getElementById("modal-login"), true);
|
window.modals.login = new Modal(document.getElementById("modal-login"), true);
|
||||||
|
window.modals.email = new Modal(document.getElementById("modal-email"), false);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
|
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
|
||||||
|
|
||||||
var rootCard = document.getElementById("card-user");
|
var rootCard = document.getElementById("card-user");
|
||||||
|
var contactCard = document.getElementById("card-contact");
|
||||||
|
var statusCard = document.getElementById("card-status");
|
||||||
|
|
||||||
const login = new Login(window.modals.login as Modal, "/my/");
|
interface MyDetailsContactMethod {
|
||||||
login.onLogin = () => {
|
value: string;
|
||||||
console.log("Logged in.");
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MyDetails {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
expiry: number;
|
||||||
|
admin: boolean;
|
||||||
|
disabled: boolean;
|
||||||
|
email?: MyDetailsContactMethod;
|
||||||
|
discord?: MyDetailsContactMethod;
|
||||||
|
telegram?: MyDetailsContactMethod;
|
||||||
|
matrix?: MyDetailsContactMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ContactDTO {
|
||||||
|
email?: boolean;
|
||||||
|
discord?: boolean;
|
||||||
|
telegram?: boolean;
|
||||||
|
matrix?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContactMethods {
|
||||||
|
private _card: HTMLElement;
|
||||||
|
private _content: HTMLElement;
|
||||||
|
private _buttons: { [name: string]: { element: HTMLElement, details: MyDetailsContactMethod } };
|
||||||
|
|
||||||
|
constructor (card: HTMLElement) {
|
||||||
|
this._card = card;
|
||||||
|
this._content = this._card.querySelector(".content");
|
||||||
|
this._buttons = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
clear = () => {
|
||||||
|
this._content.textContent = "";
|
||||||
|
this._buttons = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
append = (name: string, details: MyDetailsContactMethod, icon: string, addEditFunc?: (add: boolean) => void) => {
|
||||||
|
const row = document.createElement("div");
|
||||||
|
row.classList.add("row", "flex-expand", "my-2");
|
||||||
|
let innerHTML = `
|
||||||
|
<div class="inline align-middle">
|
||||||
|
<span class="shield ~urge" alt="${name}">
|
||||||
|
<span class="icon">
|
||||||
|
${icon}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span class="ml-2 font-bold">${(details.value == "") ? window.lang.strings("notSet") : details.value}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<button class="user-contact-enabled-disabled button ~neutral" ${details.value =="" ? "disabled" : ""}>
|
||||||
|
<input type="checkbox" class="mr-2">
|
||||||
|
<span>${window.lang.strings("enabled")}</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
if (addEditFunc) {
|
||||||
|
innerHTML += `
|
||||||
|
<button class="user-contact-edit button ~info ml-2">
|
||||||
|
<i class="ri-${details.value == "" ? "add" : "edit"}-fill mr-2"></i>
|
||||||
|
<span>${details.value == "" ? window.lang.strings("add") : window.lang.strings("edit")}</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
innerHTML += `
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
row.innerHTML = innerHTML;
|
||||||
|
|
||||||
|
this._buttons[name] = {
|
||||||
|
element: row,
|
||||||
|
details: details
|
||||||
|
};
|
||||||
|
|
||||||
|
const button = row.querySelector(".user-contact-enabled-disabled") as HTMLButtonElement;
|
||||||
|
const checkbox = button.querySelector("input[type=checkbox]") as HTMLInputElement;
|
||||||
|
const setButtonAppearance = () => {
|
||||||
|
if (checkbox.checked) {
|
||||||
|
button.classList.add("~urge");
|
||||||
|
button.classList.remove("~neutral");
|
||||||
|
} else {
|
||||||
|
button.classList.add("~neutral");
|
||||||
|
button.classList.remove("~urge");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onPress = () => {
|
||||||
|
this._buttons[name].details.enabled = checkbox.checked;
|
||||||
|
setButtonAppearance();
|
||||||
|
this._save();
|
||||||
|
};
|
||||||
|
|
||||||
|
checkbox.onchange = onPress;
|
||||||
|
button.onclick = () => {
|
||||||
|
checkbox.checked = !checkbox.checked;
|
||||||
|
onPress();
|
||||||
|
};
|
||||||
|
|
||||||
|
checkbox.checked = details.enabled;
|
||||||
|
setButtonAppearance();
|
||||||
|
|
||||||
|
if (addEditFunc) {
|
||||||
|
const addEditButton = row.querySelector(".user-contact-edit") as HTMLButtonElement;
|
||||||
|
addEditButton.onclick = () => addEditFunc(details.value == "");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._content.appendChild(row);
|
||||||
|
};
|
||||||
|
|
||||||
|
private _save = () => {
|
||||||
|
let data: ContactDTO = {};
|
||||||
|
for (let method of Object.keys(this._buttons)) {
|
||||||
|
data[method] = this._buttons[method].details.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
_post("/my/contact", data, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4) {
|
||||||
|
if (req.status != 200) {
|
||||||
|
window.notifications.customError("errorSetNotify", window.lang.notif("errorSaveSettings"));
|
||||||
|
document.dispatchEvent(new CustomEvent("details-reload"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExpiryCard {
|
||||||
|
private _card: HTMLElement;
|
||||||
|
private _expiry: Date;
|
||||||
|
private _aside: HTMLElement;
|
||||||
|
private _countdown: HTMLElement;
|
||||||
|
private _interval: number = null;
|
||||||
|
|
||||||
|
constructor(card: HTMLElement) {
|
||||||
|
this._card = card;
|
||||||
|
this._aside = this._card.querySelector(".user-expiry") as HTMLElement;
|
||||||
|
this._countdown = this._card.querySelector(".user-expiry-countdown") as HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _drawCountdown = () => {
|
||||||
|
let now = new Date();
|
||||||
|
// Years, Months, Days
|
||||||
|
let ymd = [0, 0, 0];
|
||||||
|
while (now.getFullYear() != this._expiry.getFullYear()) {
|
||||||
|
ymd[0] += 1;
|
||||||
|
now.setFullYear(now.getFullYear()+1);
|
||||||
|
}
|
||||||
|
if (now.getMonth() > this._expiry.getMonth()) {
|
||||||
|
ymd[0] -=1;
|
||||||
|
now.setFullYear(now.getFullYear()-1);
|
||||||
|
}
|
||||||
|
while (now.getMonth() != this._expiry.getMonth()) {
|
||||||
|
ymd[1] += 1;
|
||||||
|
now.setMonth(now.getMonth() + 1);
|
||||||
|
}
|
||||||
|
if (now.getDate() > this._expiry.getDate()) {
|
||||||
|
ymd[1] -=1;
|
||||||
|
now.setMonth(now.getMonth()-1);
|
||||||
|
}
|
||||||
|
while (now.getDate() != this._expiry.getDate()) {
|
||||||
|
ymd[2] += 1;
|
||||||
|
now.setDate(now.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const langKeys = ["year", "month", "day"];
|
||||||
|
let innerHTML = ``;
|
||||||
|
for (let i = 0; i < langKeys.length; i++) {
|
||||||
|
if (ymd[i] == 0) continue;
|
||||||
|
const words = window.lang.quantity(langKeys[i], ymd[i]).split(" ");
|
||||||
|
innerHTML += `
|
||||||
|
<div class="row my-3">
|
||||||
|
<div class="inline baseline">
|
||||||
|
<span class="text-2xl">${words[0]}</span> <span class="text-gray-400 text-lg">${words[1]}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
this._countdown.innerHTML = innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
get expiry(): Date { return this._expiry; };
|
||||||
|
set expiry(expiryUnix: number) {
|
||||||
|
if (this._interval !== null) {
|
||||||
|
window.clearInterval(this._interval);
|
||||||
|
this._interval = null;
|
||||||
|
}
|
||||||
|
if (expiryUnix == 0) return;
|
||||||
|
this._expiry = new Date(expiryUnix * 1000);
|
||||||
|
this._aside.textContent = window.lang.strings("yourAccountIsValidUntil").replace("{date}", toDateString(this._expiry));
|
||||||
|
this._card.classList.remove("unfocused");
|
||||||
|
|
||||||
|
this._interval = window.setInterval(this._drawCountdown, 60*1000);
|
||||||
|
this._drawCountdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var expiryCard = new ExpiryCard(statusCard);
|
||||||
|
|
||||||
|
var contactMethodList = new ContactMethods(contactCard);
|
||||||
|
|
||||||
|
const addEditEmail = (add: boolean): void => {
|
||||||
|
console.log("call");
|
||||||
|
const heading = window.modals.email.modal.querySelector(".heading");
|
||||||
|
heading.innerHTML = (add ? window.lang.strings("addContactMethod") : window.lang.strings("editContactMethod")) + `<span class="modal-close">×</span>`;
|
||||||
|
const input = document.getElementById("modal-email-input") as HTMLInputElement;
|
||||||
|
input.value = "";
|
||||||
|
const confirmationRequired = window.modals.email.modal.querySelector(".confirmation-required");
|
||||||
|
confirmationRequired.classList.add("unfocused");
|
||||||
|
|
||||||
|
const content = window.modals.email.modal.querySelector(".content");
|
||||||
|
content.classList.remove("unfocused");
|
||||||
|
|
||||||
|
const submit = window.modals.email.modal.querySelector(".modal-submit") as HTMLButtonElement;
|
||||||
|
submit.onclick = () => {
|
||||||
|
toggleLoader(submit);
|
||||||
|
_post("/my/email", {"email": input.value}, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4 && (req.status == 303 || req.status == 200)) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}, true, (req: XMLHttpRequest) => {
|
||||||
|
if (req.readyState == 4 && req.status == 401) {
|
||||||
|
content.classList.add("unfocused");
|
||||||
|
confirmationRequired.classList.remove("unfocused");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.modals.email.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("details-reload", () => {
|
||||||
_get("/my/details", null, (req: XMLHttpRequest) => {
|
_get("/my/details", null, (req: XMLHttpRequest) => {
|
||||||
if (req.readyState == 4) {
|
if (req.readyState == 4) {
|
||||||
if (req.status != 200) {
|
if (req.status != 200) {
|
||||||
window.notifications.customError("myDetailsError", req.response["error"]);
|
window.notifications.customError("myDetailsError", req.response["error"]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.jellyfinID = req.response["id"];
|
const details: MyDetails = req.response as MyDetails;
|
||||||
window.username = req.response["username"];
|
window.jellyfinID = details.id;
|
||||||
rootCard.querySelector(".heading").textContent = window.lang.strings("welcomeUser").replace("{user}", window.username);
|
window.username = details.username;
|
||||||
|
let innerHTML = `
|
||||||
|
<span>${window.lang.strings("welcomeUser").replace("{user}", window.username)}</span>
|
||||||
|
`;
|
||||||
|
if (details.admin) {
|
||||||
|
innerHTML += `<span class="chip ~info ml-4">${window.lang.strings("admin")}</span>`;
|
||||||
|
}
|
||||||
|
if (details.disabled) {
|
||||||
|
innerHTML += `<span class="chip ~warning ml-4">${window.lang.strings("disabled")}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
rootCard.querySelector(".heading").innerHTML = innerHTML;
|
||||||
|
|
||||||
|
contactMethodList.clear();
|
||||||
|
|
||||||
|
const contactMethods: { name: string, icon: string, f: (add: boolean) => void }[] = [
|
||||||
|
{name: "email", icon: `<i class="ri-mail-fill ri-lg"></i>`, f: addEditEmail},
|
||||||
|
{name: "discord", icon: `<i class="ri-discord-fill ri-lg"></i>`, f: null},
|
||||||
|
{name: "telegram", icon: `<i class="ri-telegram-fill ri-lg"></i>`, f: null},
|
||||||
|
{name: "matrix", icon: `<span class="font-bold">[m]</span>`, f: null}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (let method of contactMethods) {
|
||||||
|
if (method.name in details) {
|
||||||
|
contactMethodList.append(method.name, details[method.name], method.icon, method.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expiryCard.expiry = details.expiry;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const login = new Login(window.modals.login as Modal, "/my/");
|
||||||
|
login.onLogin = () => {
|
||||||
|
console.log("Logged in.");
|
||||||
|
document.dispatchEvent(new CustomEvent("details-reload"));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
login.bindLogout(document.getElementById("logout-button"));
|
||||||
|
|
||||||
login.login("", "");
|
login.login("", "");
|
||||||
|
@ -60,7 +60,7 @@ func (app *appContext) getUserTokenLogin(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.debug.Printf("Token generated for non-admin user \"%s\"", username)
|
app.debug.Printf("Token generated for non-admin user \"%s\"", username)
|
||||||
gc.SetCookie("refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/my", gc.Request.URL.Hostname(), true, true)
|
gc.SetCookie("user-refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/my", gc.Request.URL.Hostname(), true, true)
|
||||||
gc.JSON(200, getTokenDTO{token})
|
gc.JSON(200, getTokenDTO{token})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ func (app *appContext) getUserTokenRefresh(gc *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.info.Println("UserToken request (refresh token)")
|
app.info.Println("UserToken request (refresh token)")
|
||||||
claims, ok := app.decodeValidateRefreshCookie(gc)
|
claims, ok := app.decodeValidateRefreshCookie(gc, "user-refresh")
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -93,6 +93,6 @@ func (app *appContext) getUserTokenRefresh(gc *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gc.SetCookie("refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/my", gc.Request.URL.Hostname(), true, true)
|
gc.SetCookie("user-refresh", refresh, REFRESH_TOKEN_VALIDITY_SEC, "/my", gc.Request.URL.Hostname(), true, true)
|
||||||
gc.JSON(200, getTokenDTO{jwt})
|
gc.JSON(200, getTokenDTO{jwt})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user