1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2025-01-03 23:10:11 +00:00

Compare commits

...

6 Commits

Author SHA1 Message Date
d81679fbae
print error if logging fails 2021-12-20 19:05:18 +00:00
ebb49fce97
fix FAQ link in bug report template 2021-12-20 18:52:06 +00:00
0fd4f516b1
email: Add option to require on sign-up
for #172
2021-12-20 18:50:48 +00:00
9fff5781f4
lowercase lang 2021-12-20 17:58:34 +00:00
hongphuctran77
e19352a69f translation from Weblate (Vietnamese)
Currently translated at 71.2% (124 of 174 strings)

Translation: jfa-go/Admin Page
Translate-URL: https://weblate.jfa-go.com/projects/jfa-go/admin/vi/
2021-12-11 09:55:10 +01:00
hongphuctran77
09b96e5983 add translation from Weblate (Vietnamese) 2021-12-09 13:29:46 +01:00
10 changed files with 250 additions and 5 deletions

View File

@ -7,7 +7,7 @@ assignees: ''
---
#### Read the [FAQ](https://github.com/hrfee/jfa-go/wiki/FAQ) first!
#### Read the [FAQ](https://wiki.jfa-go.com/docs/faq/) first!
**Describe the bug**

5
api.go
View File

@ -644,6 +644,11 @@ func (app *appContext) NewUser(gc *gin.Context) {
gc.JSON(200, validation)
return
}
if emailEnabled && app.config.Section("email").Key("required").MustBool(false) && !strings.Contains(req.Email, "@") {
app.info.Printf("%s: New user failed: Email Required", req.Code)
respond(400, "errorNoEmail", gc)
return
}
f, success := app.newUser(req, false)
if !success {
f(gc)

View File

@ -458,6 +458,15 @@
"type": "bool",
"value": false,
"description": "Send emails as plain text instead of HTML."
},
"required": {
"name": "Require on sign-up",
"required": false,
"requires_restart": false,
"depends_true": "method",
"type": "bool",
"value": false,
"description": "Require an email address on sign-up."
}
}
},

View File

@ -17,6 +17,7 @@
window.telegramEnabled = {{ .telegramEnabled }};
window.telegramRequired = {{ .telegramRequired }};
window.telegramPIN = "{{ .telegramPIN }}";
window.emailRequired = {{ .emailRequired }};
window.discordEnabled = {{ .discordEnabled }};
window.discordRequired = {{ .discordRequired }};
window.discordPIN = "{{ .discordPIN }}";

210
lang/admin/vi-vn.json Normal file
View File

@ -0,0 +1,210 @@
{
"meta": {
"name": "Vietnamese (VN)"
},
"strings": {
"invites": "Lời mời",
"accounts": "Tài khoản",
"settings": "Cài đặt",
"inviteMonths": "Tháng",
"inviteDays": "Ngày",
"inviteHours": "Giờ",
"inviteMinutes": "Phút",
"inviteNumberOfUses": "Số lần sử dụng",
"inviteDuration": "Thời hạn hiệu lực",
"warning": "Cảnh báo",
"inviteInfiniteUsesWarning": "các lời mời không giới hạn số lần sử dụng có thể bị lạm dụng",
"inviteSendToEmail": "Gửi tới",
"login": "Đăng nhập",
"logout": "Đăng xuất",
"create": "Tạo mới",
"apply": "Áp dụng",
"delete": "Xóa",
"add": "Thêm",
"select": "Chọn",
"name": "Tên",
"date": "Ngày",
"enabled": "Mở",
"disabled": "Tắt",
"reEnable": "Mở lại",
"setExpiry": "Đặt hết hạn",
"disable": "Tắt",
"admin": "Admin",
"updates": "Cập nhật",
"update": "Cập nhật",
"download": "Tải về",
"search": "Tìm kiếm",
"advancedSettings": "Cài đặt Cấp cao",
"lastActiveTime": "Lần cuối Hoạt động",
"from": "Từ",
"user": "Người dùng",
"expiry": "Hết hạn",
"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.",
"aboutProgram": "Thông tin",
"version": "Phiên bản",
"commitNoun": "Gửi",
"newUser": "Người dùng mới",
"profile": "Hồ sơ",
"unknown": "Không xác định",
"label": "Nhãn",
"announce": "Thông báo",
"templates": "Mẫu",
"subject": "Chủ đề",
"message": "Tin nhắn",
"variables": "Biến",
"conditionals": "Điều kiện",
"preview": "Xem trước",
"reset": "Đặt lại",
"edit": "Chỉnh sửa",
"donate": "Đóng góp",
"sendPWR": "Gửi Đặt lại Mật khẩu",
"contactThrough": "Liên lạc qua:",
"extendExpiry": "Gia hạn",
"sendPWRManual": "Người dùng {n} không có phương thức liên lạc, nhấn chép để lấy đường link để gửi cho họ.",
"sendPWRSuccess": "Link đặt lại mật khẩu đã được gửi đi.",
"sendPWRSuccessManual": "Nếu người dùng chưa nhận được, nhấn chép để lấy đường link có thể gửi đến họ.",
"sendPWRValidFor": "Link có hiệu lực trong vòng 30 phút.",
"customizeMessages": "Tùy chỉnh Tin nhắn",
"customizeMessagesDescription": "Nếu bạn không muốn sử dụng mẫu tin nhắn của jfa-go, bạn có thể tự tạo mẫu của mình bằng Markdown.",
"markdownSupported": "Có hỗ trợ Markdown.",
"modifySettings": "Chỉnh sửa Cài đặt",
"modifySettingsDescription": "Áp dụng các cài đặt từ một mẫu có sẵn, hoặc lấy trực tiếp từ một người dùng.",
"applyHomescreenLayout": "Áp dụng bố cục trang chủ",
"sendDeleteNotificationEmail": "Gửi tin nhắn thông báo",
"sendDeleteNotifiationExample": "Tài khoản của bạn đã bị xóa.",
"settingsRestart": "Khởi động lại",
"settingsRestarting": "Đang khởi động lại…",
"settingsRestartRequired": "Cần khởi động lại",
"settingsRestartRequiredDescription": "Một số cài đặt bạn đã thay đổi cần phải khởi động lại để có hiệu lực. Khởi động lại ngay hay để sau?",
"settingsApplyRestartLater": "Áp dụng, khởi động lại sau",
"settingsApplyRestartNow": "Áp dụng & khởi động lại",
"settingsApplied": "Cài đặt đã được áp dụng.",
"settingsRefreshPage": "Làm mới trang trong một vài giây nữa.",
"settingsRequiredOrRestartMessage": "Lưu ý: {n} là những cài đặt cần thiết, {n} là những cài đặt cần khởi động lại nếu chúng được thay đổi.",
"settingsSave": "Lưu",
"ombiProfile": "Tài khoản người dùng Ombi",
"ombiUserDefaultsDescription": "Tạo và cài đặt một tài khoản người dùng Ombi, sau đó chọn nó bên dưới. Các cài đặt/quyền sẽ được lưu lại và được áp dụng cho các tài khoản Ombi được tạo bởi jfa-go khi tài khoản mẫy này được chọn.",
"userProfiles": "Thông tin Người dùng",
"userProfilesDescription": "Mẫu tài khoản được áp dụng cho người dùng khi họ tạo tài khoản. Mẫu tài khoản bao gồm các quyền truy cập thư viện và bốc cục trang chủ.",
"userProfilesIsDefault": "Mặc định",
"userProfilesLibraries": "Thư viện",
"addProfile": "Thêm Tài khoản Mẫu",
"addProfileDescription": "Tạo một tài khoản Jellyfin và cấu hình nó, rồi chọn nó bên dưới. Khi tài khoản mẫu này được áp dụng trong lời mời, các người dùng mới sẽ được tạo với các cài đặt tương tự.",
"addProfileNameOf": "Tên Tài khoản mẫu",
"addProfileStoreHomescreenLayout": "Lưu bố cục trang chủ",
"inviteNoUsersCreated": "Chưa có!",
"inviteUsersCreated": "Người dùng đã tạo",
"inviteNoProfile": "Không có Tài khoản mẫu",
"inviteDateCreated": "Tạo",
"inviteRemainingUses": "Số lần sử dụng còn lại",
"inviteNoInvites": "Không có",
"inviteExpiresInTime": "Hết hạn trong {n}",
"notifyEvent": "Thông báo khi:",
"notifyInviteExpiry": "Khi hết hạn",
"notifyUserCreation": "Khi có người dùng được tạo",
"sendPIN": "Yêu cầu người dùng gửi mã PIN bên dưới cho bot.",
"searchDiscordUser": "Gõ tên người dùng Discord để tìm người dùng.",
"findDiscordUser": "Tìm người dùng Discord",
"linkMatrixDescription": "Nhập tên đăng nhập và mật khẩu của người dùng được sử dụng làm bot. Khi hoàn thành, ứng dụng sẽ khởi động lại.",
"matrixHomeServer": "Địa chỉ máy chủ",
"saveAsTemplate": "Lưu thành mẫu",
"deleteTemplate": "Xóa mẫu",
"templateEnterName": "Nhập tên mẫu để lưu mẫu này."
},
"notifications": {
"changedEmailAddress": "Đã đổi địa chỉ email của {n}.",
"userCreated": "Người dùng {n} đã được tạo.",
"createProfile": "Đã tạo tài khoản mẫu {n}.",
"saveSettings": "Cài đặt đã được lưu",
"saveEmail": "Email đã được lưu.",
"sentAnnouncement": "Thông báo đã được gửi.",
"savedAnnouncement": "Thông báo đã được lưu.",
"setOmbiProfile": "Mẫu tài khoản Ombi đã được lưu trữ.",
"updateApplied": "Cập nhật mới đã được áp dụng, vui lòng khởi động lại.",
"updateAppliedRefresh": "Cập nhật mới đã được áp dụng, vui lòng làm mới lại trang.",
"telegramVerified": "Tài khoản Telegram đã được xác thực.",
"accountConnected": "Tài khoản đã được kết nối.",
"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.",
"errorSettingsAppliedNoHomescreenLayout": "Cài đặt đã được áp dụng, nhưng việc áp dụng bố cục màn hình chính có thể không thành công.",
"errorHomescreenAppliedNoSettings": "",
"errorSettingsFailed": "",
"errorLoginBlank": "",
"errorUnknown": "",
"errorSaveEmail": "",
"errorBlankFields": "",
"errorDeleteProfile": "",
"errorLoadProfiles": "",
"errorCreateProfile": "",
"errorSetDefaultProfile": "",
"errorLoadUsers": "",
"errorSaveSettings": "",
"errorLoadSettings": "",
"errorSetOmbiProfile": "",
"errorLoadOmbiUsers": "",
"errorChangedEmailAddress": "",
"errorFailureCheckLogs": "",
"errorPartialFailureCheckLogs": "",
"errorUserCreated": "",
"errorSendWelcomeEmail": "",
"errorApplyUpdate": "",
"errorCheckUpdate": "",
"updateAvailable": "",
"noUpdatesAvailable": ""
},
"quantityStrings": {
"modifySettingsFor": {
"singular": "",
"plural": ""
},
"deleteNUsers": {
"singular": "",
"plural": ""
},
"disableUsers": {
"singular": "",
"plural": ""
},
"reEnableUsers": {
"singular": "",
"plural": ""
},
"addUser": {
"singular": "",
"plural": ""
},
"deleteUser": {
"singular": "",
"plural": ""
},
"deletedUser": {
"singular": "",
"plural": ""
},
"disabledUser": {
"singular": "",
"plural": ""
},
"enabledUser": {
"singular": "",
"plural": ""
},
"announceTo": {
"singular": "",
"plural": ""
},
"appliedSettings": {
"singular": "",
"plural": ""
},
"extendExpiry": {
"singular": "",
"plural": ""
},
"extendedExpiry": {
"singular": "",
"plural": ""
}
}
}

View File

@ -29,6 +29,7 @@
"errorMatrixVerification": "Matrix verification required.",
"errorInvalidPIN": "PIN is invalid.",
"errorUnknown": "Unknown error.",
"errorNoEmail": "Email required.",
"verified": "Account verified."
},
"validationStrings": {

5
log.go
View File

@ -14,14 +14,15 @@ import (
var logPath string = filepath.Join(temp, "jfa-go.log")
var lineCache = linecache.NewLineCache(100)
func logOutput() (closeFunc func()) {
func logOutput() (closeFunc func(), err error) {
old := os.Stdout
writers := []io.Writer{old, colorStripper{lineCache}}
wExit := make(chan bool)
r, w, _ := os.Pipe()
var f *os.File
if TRAY {
log.Printf("Logging to \"%s\"", logPath)
f, err := os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
f, err = os.OpenFile(logPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
closeFunc = func() {}
return

View File

@ -667,7 +667,10 @@ func printVersion() {
}
func main() {
f := logOutput()
f, err := logOutput()
if err != nil {
fmt.Printf("Failed to start logging: %v\n", err)
}
defer f()
printVersion()
SOCK = filepath.Join(temp, SOCK)

View File

@ -29,6 +29,7 @@ interface formWindow extends Window {
userExpiryHours: number;
userExpiryMinutes: number;
userExpiryMessage: string;
emailRequired: boolean;
}
loadLangSelector("form");
@ -39,6 +40,7 @@ window.animationEvent = whichAnimationEvent();
window.successModal = new Modal(document.getElementById("modal-success"), true);
var telegramVerified = false;
if (window.telegramEnabled) {
window.telegramModal = new Modal(document.getElementById("modal-telegram"), window.telegramRequired);
@ -230,6 +232,18 @@ if (!window.usernameEnabled) { usernameField.parentElement.remove(); usernameFie
const passwordField = document.getElementById("create-password") as HTMLInputElement;
const rePasswordField = document.getElementById("create-reenter-password") as HTMLInputElement;
if (window.emailRequired) {
emailField.addEventListener("keyup", () => {
if (emailField.value.includes("@")) {
submitButton.disabled = false;
submitSpan.removeAttribute("disabled");
} else {
submitButton.disabled = true;
submitSpan.setAttribute("disabled", "");
}
});
}
var requirements = initValidator(passwordField, rePasswordField, submitButton, submitSpan)
interface respDTO {
@ -302,7 +316,7 @@ const create = (event: SubmitEvent) => {
}, true, (req: XMLHttpRequest) => {
if (req.readyState == 4) {
toggleLoader(submitSpan);
if (req.status == 401) {
if (req.status == 401 || req.status == 400) {
if (req.response["error"] as string) {
if (req.response["error"] == "confirmEmail") {
window.confirmationModal.show();

View File

@ -358,6 +358,7 @@ func (app *appContext) InviteProxy(gc *gin.Context) {
"telegramEnabled": telegram,
"discordEnabled": discord,
"matrixEnabled": matrix,
"emailRequired": app.config.Section("email").Key("required").MustBool(false),
}
if telegram {
data["telegramPIN"] = app.telegram.NewAuthToken()