Browse Source

refactor and add i18n, to be continue

shiqstone 4 years ago
parent
commit
1239620f75

+ 12 - 12
commands/command.go

@@ -163,40 +163,40 @@ func RegisterLogger(log string) {
 	if level := beego.AppConfig.DefaultString("log_level", "Trace"); level != "" {
 		switch level {
 		case "Emergency":
-			config["level"] = beego.LevelEmergency
+			config["level"] = logs.LevelEmergency
 			break
 		case "Alert":
-			config["level"] = beego.LevelAlert
+			config["level"] = logs.LevelAlert
 			break
 		case "Critical":
-			config["level"] = beego.LevelCritical
+			config["level"] = logs.LevelCritical
 			break
 		case "Error":
-			config["level"] = beego.LevelError
+			config["level"] = logs.LevelError
 			break
 		case "Warning":
-			config["level"] = beego.LevelWarning
+			config["level"] = logs.LevelWarning
 			break
 		case "Notice":
-			config["level"] = beego.LevelNotice
+			config["level"] = logs.LevelNotice
 			break
 		case "Informational":
-			config["level"] = beego.LevelInformational
+			config["level"] = logs.LevelInformational
 			break
 		case "Debug":
-			config["level"] = beego.LevelDebug
+			config["level"] = logs.LevelDebug
 			break
 		}
 	}
 	b, err := json.Marshal(config)
 	if err != nil {
 		logs.Error("初始化文件日志时出错 ->", err)
-		_ = beego.SetLogger("file", `{"filename":"`+logPath+`"}`)
+		_ = logs.SetLogger("file", `{"filename":"`+logPath+`"}`)
 	} else {
-		_ = beego.SetLogger(logs.AdapterFile, string(b))
+		_ = logs.SetLogger(logs.AdapterFile, string(b))
 	}
 
-	beego.SetLogFuncCall(true)
+	logs.SetLogFuncCall(true)
 }
 
 // RunCommand 注册orm命令行工具
@@ -454,7 +454,7 @@ func RegisterCache() {
 
 	} else {
 		cache.Init(&cache.NullCache{})
-		beego.Warn("不支持的缓存管道,缓存将禁用 ->", cacheProvider)
+		logs.Warn("不支持的缓存管道,缓存将禁用 ->", cacheProvider)
 		return
 	}
 	logs.Info("缓存初始化完成.")

+ 52 - 2
conf/lang/en-us.ini

@@ -7,8 +7,58 @@ person_center = Persona Center
 my_project = My Project
 my_blog = My Article
 manage = Management
-login = Login
-logout = Logout
+login = Log In
+logout = Log Out
+official_website = Official Website
+feedback = Feedback
+source_code = Source Code
+manual = Manual
+username = Username
+email = Email
+password = Password
+captcha = Captcha
+keep_login = Stay signed in
+forgot_password = Forgot password?
+register = Create New Account
+dingtalk_login = DingTalk QrCode login
+account_recovery = Account recovery
+new_password = New password
+confirm_password = Confirm password
 
 [message]
 keyword_placeholder = input keyword please...
+wrong_account_password = Incorrect username or password
+click_to_change = Click to change one
+logging_in = logging in...
+return_account_login = Return account password login
+no_account_yet = No account yet?
+account_empty = Account cannot be empty
+email_empty = Email cannot be empty
+password_empty = Password cannot be empty
+captcha_empty = Captcha cannot be empty
+system_error = System error
+processing = Processing...
+email_sent = The email is sent successfully, please log in to check it.
+password_empty = Confirm password cannot be empty
+incorrect_confirm_password = Incorrect confirm password
+illegal_request = Illegal request
+account_or_password_empty = Account or Password cannot be empty
+captcha_wrong = Incorrect captcha
+password_length_invalid = The password cannot be empty and must be between 6-50 characters
+mail_expired = Mail has expired
+captcha_expired = The verification code has expired, please try again.
+user_not_existed = User does not exist
+email_not_exist = Email does not exist
+failed_save_password = Failed to save password
+mail_service_not_enable = Mail service is not enabled
+account_disable = Account has been disabled
+failed_send_mail = Failed to send mail
+sent_too_many_times = Send too many times, please try again later
+account_not_support_retrieval = The current user does not support password retrieval
+username_invalid_format = The account number can only be composed of English alphanumerics and 3-50 characters
+email_invalid_format = Email format is incorrect
+account_existed = Username already existed
+failed_register = Registration failed, please contact the system administrator
+failed_obtain_user_info = Failed to obtain identity information
+dingtalk_auto_login_not_enable = DingTalk automatic login function is not enabled
+failed_auto_login = Automatic login failed

+ 50 - 0
conf/lang/zh-cn.ini

@@ -9,6 +9,56 @@ my_blog = 我的文章
 manage = 管理后台
 login = 登录
 logout = 退出登录
+official_website = 官方网站
+feedback = 意见反馈
+source_code = 项目源码
+manual = 使用手册
+username = 用户名
+email = 邮箱
+password = 密码
+captcha = 验证码
+keep_login = 保持登录
+forgot_password = 忘记密码?
+register = 立即注册
+dingtalk_login = 扫码登录
+account_recovery = 找回密码
+new_password = 新密码
+confirm_password = 确认密码
 
 [message]
 keyword_placeholder = 请输入关键词...
+wrong_account_password = 账号或密码错误
+click_to_change = 点击换一张
+logging_in = 正在登录...
+return_account_login = 返回账号密码登录
+no_account_yet = 还没有账号?
+account_empty = 账号不能为空
+email_empty = 邮箱不能为空
+password_empty = 密码不能为空
+captcha_empty = 验证码不能为空
+system_error = 系统错误
+processing = 正在处理...
+email_sent = 邮件发送成功,请登录邮箱查看。
+confirm_password_empty = 确认密码不能为空
+incorrect_confirm_password = 确认密码输入不正确
+illegal_request = 非法请求
+account_or_password_empty = 账号或密码不能为空
+captcha_wrong = 验证码不正确
+password_length_invalid = 密码不能为空且必须在6-50个字符之间
+mail_expired = 邮件已失效
+captcha_expired = 验证码已过期,请重新操作。
+user_not_existed = 用户不存在
+email_not_exist = 邮箱不存在
+failed_save_password = 保存密码失败
+mail_service_not_enable = 未启用邮件服务
+account_disable = 账号已被禁用
+failed_send_mail = 发送邮件失败
+sent_too_many_times = 发送次数太多,请稍候再试
+account_not_support_retrieval = 当前用户不支持找回密码
+username_invalid_format = 账号只能由英文字母数字组成,且在3-50个字符
+email_invalid_format = 邮箱格式不正确
+account_existed = 账号已存在
+failed_register = 注册失败,请联系管理员
+failed_obtain_user_info = 获取身份信息失败
+dingtalk_auto_login_not_enable = 未开启钉钉自动登录功能
+failed_auto_login = 自动登录失败

+ 50 - 61
controllers/AccountController.go

@@ -54,17 +54,17 @@ func (c *AccountController) Prepare() {
 		}
 		if token == "" {
 			if c.IsAjax() {
-				c.JsonResult(403, "非法请求")
+				c.JsonResult(403, i18n.Tr(c.Lang, "message.illegal_request"))
 			} else {
-				c.ShowErrorPage(403, "非法请求")
+				c.ShowErrorPage(403, i18n.Tr(c.Lang, "message.illegal_request"))
 			}
 		}
 		xsrfToken := c.XSRFToken()
 		if xsrfToken != token {
 			if c.IsAjax() {
-				c.JsonResult(403, "非法请求")
+				c.JsonResult(403, i18n.Tr(c.Lang, "message.illegal_request"))
 			} else {
-				c.ShowErrorPage(403, "非法请求")
+				c.ShowErrorPage(403, i18n.Tr(c.Lang, "message.illegal_request"))
 			}
 		}
 	}
@@ -108,12 +108,12 @@ func (c *AccountController) Login() {
 		if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
 			v, ok := c.GetSession(conf.CaptchaSessionName).(string)
 			if !ok || !strings.EqualFold(v, captcha) {
-				c.JsonResult(6001, "验证码不正确")
+				c.JsonResult(6001, i18n.Tr(c.Lang, "message.captcha_wrong"))
 			}
 		}
 
 		if account == "" || password == "" {
-			c.JsonResult(6002, "账号或密码不能为空")
+			c.JsonResult(6002, i18n.Tr(c.Lang, "message.account_or_password_empty"))
 		}
 
 		member, err := models.NewMember().Login(account, password)
@@ -149,7 +149,7 @@ func (c *AccountController) DingTalkLogin() {
 
 	code := c.GetString("dingtalk_code")
 	if code == "" {
-		c.JsonResult(500, "获取身份信息失败", nil)
+		c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_obtain_user_info"), nil)
 	}
 
 	appKey := beego.AppConfig.String("dingtalk_app_key")
@@ -157,29 +157,29 @@ func (c *AccountController) DingTalkLogin() {
 	tmpReader := beego.AppConfig.String("dingtalk_tmp_reader")
 
 	if appKey == "" || appSecret == "" || tmpReader == "" {
-		c.JsonResult(500, "未开启钉钉自动登录功能", nil)
+		c.JsonResult(500, i18n.Tr(c.Lang, "message.dingtalk_auto_login_not_enable"), nil)
 		c.StopRun()
 	}
 
 	dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
 	err := dingtalkAgent.GetAccesstoken()
 	if err != nil {
-		beego.Warn("获取钉钉临时Token失败 ->", err)
-		c.JsonResult(500, "自动登录失败", nil)
+		logs.Warn("获取钉钉临时Token失败 ->", err)
+		c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
 		c.StopRun()
 	}
 
 	userid, err := dingtalkAgent.GetUserIDByCode(code)
 	if err != nil {
-		beego.Warn("获取钉钉用户ID失败 ->", err)
-		c.JsonResult(500, "自动登录失败", nil)
+		logs.Warn("获取钉钉用户ID失败 ->", err)
+		c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
 		c.StopRun()
 	}
 
 	username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
 	if err != nil {
-		beego.Warn("获取钉钉用户信息失败 ->", err)
-		c.JsonResult(500, "自动登录失败", nil)
+		logs.Warn("获取钉钉用户信息失败 ->", err)
+		c.JsonResult(500, i18n.Tr(c.Lang, "message.failed_auto_login"), nil)
 		c.StopRun()
 	}
 
@@ -218,7 +218,7 @@ func (c *AccountController) QRLogin() {
 		qrDingtalk := dingtalk.NewDingtalkQRLogin(appSecret, appKey)
 		unionID, err := qrDingtalk.GetUnionIDByCode(code)
 		if err != nil {
-			beego.Warn("获取钉钉临时UnionID失败 ->", err)
+			logs.Warn("获取钉钉临时UnionID失败 ->", err)
 			c.Redirect(conf.URLFor("AccountController.Login"), 302)
 			c.StopRun()
 		}
@@ -230,21 +230,21 @@ func (c *AccountController) QRLogin() {
 		dingtalkAgent := dingtalk.NewDingTalkAgent(appSecret, appKey)
 		err = dingtalkAgent.GetAccesstoken()
 		if err != nil {
-			beego.Warn("获取钉钉临时Token失败 ->", err)
+			logs.Warn("获取钉钉临时Token失败 ->", err)
 			c.Redirect(conf.URLFor("AccountController.Login"), 302)
 			c.StopRun()
 		}
 
 		userid, err := dingtalkAgent.GetUserIDByUnionID(unionID)
 		if err != nil {
-			beego.Warn("获取钉钉用户ID失败 ->", err)
+			logs.Warn("获取钉钉用户ID失败 ->", err)
 			c.Redirect(conf.URLFor("AccountController.Login"), 302)
 			c.StopRun()
 		}
 
 		username, avatar, err := dingtalkAgent.GetUserNameAndAvatarByUserID(userid)
 		if err != nil {
-			beego.Warn("获取钉钉用户信息失败 ->", err)
+			logs.Warn("获取钉钉用户信息失败 ->", err)
 			c.Redirect(conf.URLFor("AccountController.Login"), 302)
 			c.StopRun()
 		}
@@ -308,29 +308,29 @@ func (c *AccountController) Register() {
 		captcha := c.GetString("code")
 
 		if ok, err := regexp.MatchString(conf.RegexpAccount, account); account == "" || !ok || err != nil {
-			c.JsonResult(6001, "账号只能由英文字母数字组成,且在3-50个字符")
+			c.JsonResult(6001, i18n.Tr(c.Lang, "message.username_invalid_format"))
 		}
 		if l := strings.Count(password1, ""); password1 == "" || l > 50 || l < 6 {
-			c.JsonResult(6002, "密码必须在6-50个字符之间")
+			c.JsonResult(6002, i18n.Tr(c.Lang, "message.password_length_invalid"))
 		}
 		if password1 != password2 {
-			c.JsonResult(6003, "确认密码不正确")
+			c.JsonResult(6003, i18n.Tr(c.Lang, "message.incorrect_confirm_password"))
 		}
 		if ok, err := regexp.MatchString(conf.RegexpEmail, email); !ok || err != nil || email == "" {
-			c.JsonResult(6004, "邮箱格式不正确")
+			c.JsonResult(6004, i18n.Tr(c.Lang, "message.email_invalid_format"))
 		}
 		// 如果开启了验证码
 		if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
 			v, ok := c.GetSession(conf.CaptchaSessionName).(string)
 			if !ok || !strings.EqualFold(v, captcha) {
-				c.JsonResult(6001, "验证码不正确")
+				c.JsonResult(6001, i18n.Tr(c.Lang, "message.captcha_wrong"))
 			}
 		}
 
 		member := models.NewMember()
 
 		if _, err := member.FindByAccount(account); err == nil && member.MemberId > 0 {
-			c.JsonResult(6005, "账号已存在")
+			c.JsonResult(6005, i18n.Tr(c.Lang, "message.account_existed"))
 		}
 
 		member.Account = account
@@ -341,7 +341,7 @@ func (c *AccountController) Register() {
 		member.Email = email
 		member.Status = 0
 		if err := member.Add(); err != nil {
-			c.JsonResult(6006, "注册失败,请联系系统管理员处理")
+			c.JsonResult(6006, i18n.Tr(c.Lang, "message.failed_register"))
 		}
 
 		c.JsonResult(0, "ok", member)
@@ -359,39 +359,39 @@ func (c *AccountController) FindPassword() {
 		captcha := c.GetString("code")
 
 		if email == "" {
-			c.JsonResult(6005, "邮箱地址不能为空")
+			c.JsonResult(6005, i18n.Tr(c.Lang, "message.email_empty"))
 		}
 		if !mailConf.EnableMail {
-			c.JsonResult(6004, "未启用邮件服务")
+			c.JsonResult(6004, i18n.Tr(c.Lang, "message.mail_service_not_enable"))
 		}
 
 		// 如果开启了验证码
 		if v, ok := c.Option["ENABLED_CAPTCHA"]; ok && strings.EqualFold(v, "true") {
 			v, ok := c.GetSession(conf.CaptchaSessionName).(string)
 			if !ok || !strings.EqualFold(v, captcha) {
-				c.JsonResult(6001, "验证码不正确")
+				c.JsonResult(6001, i18n.Tr(c.Lang, "message.captcha_wrong"))
 			}
 		}
 
 		member, err := models.NewMember().FindByFieldFirst("email", email)
 		if err != nil {
-			c.JsonResult(6006, "邮箱不存在")
+			c.JsonResult(6006, i18n.Tr(c.Lang, "message.email_not_exist"))
 		}
-		if member.Status != 0 {
-			c.JsonResult(6007, "账号已被禁用")
+		if member == nil || member.Status != 0 {
+			c.JsonResult(6007, i18n.Tr(c.Lang, "message.account_disable"))
 		}
-		if member.AuthMethod == conf.AuthMethodLDAP {
-			c.JsonResult(6011, "当前用户不支持找回密码")
+		if member == nil || member.AuthMethod == conf.AuthMethodLDAP {
+			c.JsonResult(6011, i18n.Tr(c.Lang, "message.account_not_support_retrieval"))
 		}
 
 		count, err := models.NewMemberToken().FindSendCount(email, time.Now().Add(-1*time.Hour), time.Now())
 
 		if err != nil {
 			logs.Error(err)
-			c.JsonResult(6008, "发送邮件失败")
+			c.JsonResult(6008, i18n.Tr(c.Lang, "message.failed_send_mail"))
 		}
 		if count > mailConf.MailNumber {
-			c.JsonResult(6008, "发送次数太多,请稍候再试")
+			c.JsonResult(6008, i18n.Tr(c.Lang, "message.sent_too_many_times"))
 		}
 
 		memberToken := models.NewMemberToken()
@@ -401,7 +401,7 @@ func (c *AccountController) FindPassword() {
 		memberToken.MemberId = member.MemberId
 		memberToken.IsValid = false
 		if _, err := memberToken.InsertOrUpdate(); err != nil {
-			c.JsonResult(6009, "邮件发送失败")
+			c.JsonResult(6009, i18n.Tr(c.Lang, "message.failed_send_mail"))
 		}
 
 		data := map[string]interface{}{
@@ -413,7 +413,7 @@ func (c *AccountController) FindPassword() {
 		body, err := c.ExecuteViewPathTemplate("account/mail_template.tpl", data)
 		if err != nil {
 			logs.Error(err)
-			c.JsonResult(6003, "邮件发送失败")
+			c.JsonResult(6003, i18n.Tr(c.Lang, "message.failed_send_mail"))
 		}
 
 		go func(mailConf *conf.SmtpConf, email string, body string) {
@@ -472,17 +472,16 @@ func (c *AccountController) FindPassword() {
 
 	if token != "" && email != "" {
 		memberToken, err := models.NewMemberToken().FindByFieldFirst("token", token)
-
 		if err != nil {
 			logs.Error(err)
-			c.Data["ErrorMessage"] = "邮件已失效"
+			c.Data["ErrorMessage"] = i18n.Tr(c.Lang, "message.mail_expired")
 			c.TplName = "errors/error.tpl"
 			return
 		}
 		subTime := memberToken.SendTime.Sub(time.Now())
 
 		if !strings.EqualFold(memberToken.Email, email) || subTime.Minutes() > float64(mailConf.MailExpired) || !memberToken.ValidTime.IsZero() {
-			c.Data["ErrorMessage"] = "验证码已过期,请重新操作。"
+			c.Data["ErrorMessage"] = i18n.Tr(c.Lang, "message.captcha_expired")
 			c.TplName = "errors/error.tpl"
 			return
 		}
@@ -503,48 +502,46 @@ func (c *AccountController) ValidEmail() {
 	email := c.GetString("mail")
 
 	if password1 == "" {
-		c.JsonResult(6001, "密码不能为空")
+		c.JsonResult(6001, i18n.Tr(c.Lang, "message.password_empty"))
 	}
 	if l := strings.Count(password1, ""); l < 6 || l > 50 {
-		c.JsonResult(6001, "密码不能为空且必须在6-50个字符之间")
+		c.JsonResult(6001, i18n.Tr(c.Lang, "message.password_length_invalid"))
 	}
 	if password2 == "" {
-		c.JsonResult(6002, "确认密码不能为空")
+		c.JsonResult(6002, i18n.Tr(c.Lang, "message.confirm_password_empty"))
 	}
 	if password1 != password2 {
-		c.JsonResult(6003, "确认密码输入不正确")
+		c.JsonResult(6003, i18n.Tr(c.Lang, "message.incorrect_confirm_password"))
 	}
 	if captcha == "" {
-		c.JsonResult(6004, "验证码不能为空")
+		c.JsonResult(6004, i18n.Tr(c.Lang, "message.captcha_empty"))
 	}
 	v, ok := c.GetSession(conf.CaptchaSessionName).(string)
 	if !ok || !strings.EqualFold(v, captcha) {
-		c.JsonResult(6001, "验证码不正确")
+		c.JsonResult(6001, i18n.Tr(c.Lang, "message.captcha_wrong"))
 	}
 
 	mailConf := conf.GetMailConfig()
 	memberToken, err := models.NewMemberToken().FindByFieldFirst("token", token)
-
 	if err != nil {
 		logs.Error(err)
-		c.JsonResult(6007, "邮件已失效")
+		c.JsonResult(6007, i18n.Tr(c.Lang, "message.mail_expired"))
 	}
 	subTime := memberToken.SendTime.Sub(time.Now())
 
 	if !strings.EqualFold(memberToken.Email, email) || subTime.Minutes() > float64(mailConf.MailExpired) || !memberToken.ValidTime.IsZero() {
 
-		c.JsonResult(6008, "验证码已过期,请重新操作。")
+		c.JsonResult(6008, i18n.Tr(c.Lang, "message.captcha_expired"))
 	}
 	member, err := models.NewMember().Find(memberToken.MemberId)
 	if err != nil {
 		logs.Error(err)
-		c.JsonResult(6005, "用户不存在")
+		c.JsonResult(6005, i18n.Tr(c.Lang, "message.user_not_existed"))
 	}
 	hash, err := utils.PasswordHash(password1)
-
 	if err != nil {
 		logs.Error(err)
-		c.JsonResult(6006, "保存密码失败")
+		c.JsonResult(6006, i18n.Tr(c.Lang, "message.failed_save_password"))
 	}
 
 	member.Password = hash
@@ -556,7 +553,7 @@ func (c *AccountController) ValidEmail() {
 
 	if err != nil {
 		logs.Error(err)
-		c.JsonResult(6006, "保存密码失败")
+		c.JsonResult(6006, i18n.Tr(c.Lang, "message.failed_save_password"))
 	}
 	c.JsonResult(0, "ok", conf.URLFor("AccountController.Login"))
 }
@@ -564,11 +561,8 @@ func (c *AccountController) ValidEmail() {
 // Logout 退出登录
 func (c *AccountController) Logout() {
 	c.SetMember(models.Member{})
-
 	c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
-
 	u := c.Ctx.Request.Header.Get("Referer")
-
 	c.Redirect(conf.URLFor("AccountController.Login", "url", u), 302)
 }
 
@@ -578,11 +572,6 @@ func (c *AccountController) Captcha() {
 
 	captchaImage := gocaptcha.NewCaptchaImage(140, 40, gocaptcha.RandLightColor())
 
-	//if err != nil {
-	//	logs.Error(err)
-	//	c.Abort("500")
-	//}
-
 	captchaImage.DrawNoise(gocaptcha.CaptchaComplexLower)
 
 	// captchaImage.DrawTextNoise(gocaptcha.CaptchaComplexHigh)

+ 32 - 16
controllers/BaseController.go

@@ -2,9 +2,9 @@ package controllers
 
 import (
 	"bytes"
-	"github.com/beego/i18n"
-
 	"encoding/json"
+	"github.com/astaxie/beego/logs"
+	"github.com/beego/i18n"
 	"io"
 	"strings"
 	"time"
@@ -24,6 +24,7 @@ type BaseController struct {
 	Option                map[string]string
 	EnableAnonymous       bool
 	EnableDocumentHistory bool
+	Lang                  string
 }
 
 type CookieRemember struct {
@@ -45,7 +46,6 @@ func (c *BaseController) Prepare() {
 	c.EnableDocumentHistory = false
 
 	if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
-
 		c.Member = &member
 		c.Data["Member"] = c.Member
 	} else {
@@ -78,13 +78,8 @@ func (c *BaseController) Prepare() {
 	if b, err := ioutil.ReadFile(filepath.Join(beego.BConfig.WebConfig.ViewsPath, "widgets", "scripts.tpl")); err == nil {
 		c.Data["Scripts"] = template.HTML(string(b))
 	}
-	lang := c.Input().Get("lang")
-	if len(lang) == 0 ||
-		!i18n.IsExist(lang) {
-		lang = "zh-cn"
-	}
-	c.Data["Lang"] = lang
 
+	c.SetLang()
 }
 
 //判断用户是否登录.
@@ -117,14 +112,16 @@ func (c *BaseController) JsonResult(errCode int, errMsg string, data ...interfac
 	}
 
 	returnJSON, err := json.Marshal(jsonData)
-
 	if err != nil {
-		beego.Error(err)
+		logs.Error(err)
 	}
 
 	c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")
 	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache, no-store")
-	io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
+	_, err = io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
+	if err != nil {
+		logs.Error(err)
+	}
 
 	c.StopRun()
 }
@@ -141,14 +138,16 @@ func (c *BaseController) CheckJsonError(code int, err error) {
 	jsonData["message"] = err.Error()
 
 	returnJSON, err := json.Marshal(jsonData)
-
 	if err != nil {
-		beego.Error(err)
+		logs.Error(err)
 	}
 
 	c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")
 	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache, no-store")
-	io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
+	_, err = io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
+	if err != nil {
+		logs.Error(err)
+	}
 
 	c.StopRun()
 }
@@ -201,9 +200,26 @@ func (c *BaseController) ShowErrorPage(errCode int, errMsg string) {
 	}
 }
 
-
 func (c *BaseController) CheckErrorResult(code int, err error) {
 	if err != nil {
 		c.ShowErrorPage(code, err.Error())
 	}
 }
+
+func (c *BaseController) SetLang() {
+	hasCookie := false
+	lang := c.Input().Get("lang")
+	if len(lang) == 0 {
+		lang = c.Ctx.GetCookie("lang")
+		hasCookie = true
+	}
+	if len(lang) == 0 ||
+		!i18n.IsExist(lang) {
+		lang = beego.AppConfig.String("default_lang")
+	}
+	if !hasCookie {
+		c.Ctx.SetCookie("lang", lang, 1<<31-1, "/")
+	}
+	c.Data["Lang"] = lang
+	c.Lang = lang
+}

+ 10 - 10
views/account/find_password_setp1.tpl

@@ -7,7 +7,7 @@
     <meta name="renderer" content="webkit" />
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <meta name="author" content="MinDoc" />
-    <title>找回密码 - Powered by MinDoc</title>
+    <title>{{i18n .Lang "common.account_recovery"}} - Powered by MinDoc</title>
 
     <!-- Bootstrap -->
     <link href="{{cdncss "/static/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">
@@ -35,13 +35,13 @@
         <div class="login-body">
             <form role="form" method="post" id="findPasswordForm">
             {{ .xsrfdata }}
-                <h3 class="text-center">找回密码</h3>
+                <h3 class="text-center">{{i18n .Lang "common.account_recovery"}}</h3>
                 <div class="form-group">
                     <div class="input-group">
                         <div class="input-group-addon">
                             <i class="fa fa-at"></i>
                         </div>
-                        <input type="text" class="form-control" placeholder="邮箱" name="email" id="email" autocomplete="off">
+                        <input type="text" class="form-control" placeholder="{{i18n .Lang "common.email"}}" name="email" id="email" autocomplete="off">
                     </div>
                 </div>
                 <div class="form-group">
@@ -49,14 +49,14 @@
                         <div class="input-group-addon">
                             <i class="fa fa-check-square"></i>
                         </div>
-                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="验证码" autocomplete="off">&nbsp;
+                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="{{i18n .Lang "common.captcha"}}" autocomplete="off">&nbsp;
                     </div>
-                    <img id="captcha-img" style="width: 140px;height: 40px;display: inline-block;float: right" src="{{urlfor "AccountController.Captcha"}}" onclick="this.src='{{urlfor "AccountController.Captcha"}}?key=login&t='+(new Date()).getTime();" title="点击换一张">
+                    <img id="captcha-img" style="width: 140px;height: 40px;display: inline-block;float: right" src="{{urlfor "AccountController.Captcha"}}" onclick="this.src='{{urlfor "AccountController.Captcha"}}?key=login&t='+(new Date()).getTime();" title="{{i18n .Lang "message.click_to_change"}}">
                     <div class="clearfix"></div>
                 </div>
 
                 <div class="form-group">
-                    <button type="submit" id="btnSendMail" class="btn btn-success" style="width: 100%"  data-loading-text="正在处理..." autocomplete="off">找回密码</button>
+                    <button type="submit" id="btnSendMail" class="btn btn-success" style="width: 100%"  data-loading-text="{{i18n .Lang "message.processing"}}" autocomplete="off">{{i18n .Lang "common.account_recovery"}}</button>
                 </div>
 
             </form>
@@ -88,7 +88,7 @@
 
                 var email = $.trim($("#email").val());
                 if(email === ""){
-                    $("#email").tooltip({placement:"auto",title : "邮箱不能为空",trigger : 'manual'})
+                    $("#email").tooltip({placement:"auto",title : "{{i18n .Lang "message.email_empty"}}",trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
                     $btn.button('reset');
@@ -97,7 +97,7 @@
                 }
                 var code = $.trim($("#code").val());
                 if(code === ""){
-                    $("#code").tooltip({title : '验证码不能为空',trigger : 'manual'})
+                    $("#code").tooltip({title : '{{i18n .Lang "message.captcha_empty"}}',trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
                     $btn.button('reset');
@@ -113,14 +113,14 @@
                     layer.msg(res.message);
                     $("#btnSendMail").button('reset');
                 }else{
-                    alert("邮件发送成功,请登录邮箱查看。")
+                    alert("{{i18n .Lang "message.email_sent"}}")
                     window.location = res.data;
                 }
             },
             error :function () {
                 $("#captcha-img").click();
                 $("#code").val('');
-                layer.msg('系统错误');
+                layer.msg('{{i18n .Lang "message.system_error"}}');
                 $("#btnSendMail").button('reset');
             }
         });

+ 14 - 14
views/account/find_password_setp2.tpl

@@ -6,8 +6,8 @@
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
     <meta name="renderer" content="webkit" />
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <meta name="author" content="SmartWiki" />
-    <title>找回密码 - Powered by MinDoc</title>
+    <meta name="author" content="MinDoc" />
+    <title>{{i18n .Lang "common.account_recovery"}} - Powered by MinDoc</title>
 
     <!-- Bootstrap -->
     <link href="{{cdncss "/static/bootstrap/css/bootstrap.min.css"}}" rel="stylesheet">
@@ -37,14 +37,14 @@
             {{ .xsrfdata }}
                 <input type="hidden" name="token" value="{{.Token}}">
                 <input type="hidden" name="mail" value="{{.Email}}">
-                <h3 class="text-center">找回密码</h3>
+                <h3 class="text-center">{{i18n .Lang "common.account_recovery"}}</h3>
                 <div class="form-group">
-                    <label for="newPasswd">新密码</label>
-                    <input type="password" class="form-control" name="password1" id="newPassword" maxlength="20" placeholder="新密码"  autocomplete="off">
+                    <label for="newPasswd">{{i18n .Lang "common.new_password"}}</label>
+                    <input type="password" class="form-control" name="password1" id="newPassword" maxlength="20" placeholder="{{i18n .Lang "common.new_password"}}"  autocomplete="off">
                 </div>
                 <div class="form-group">
-                    <label for="configPasswd">确认密码</label>
-                    <input type="password" class="form-control" id="confirmPassword" name="password2" maxlength="20" placeholder="确认密码"  autocomplete="off">
+                    <label for="configPasswd">{{i18n .Lang "common.confirm_password"}}</label>
+                    <input type="password" class="form-control" id="confirmPassword" name="password2" maxlength="20" placeholder="{{i18n .Lang "common.confirm_password"}}"  autocomplete="off">
                 </div>
 
                 <div class="form-group">
@@ -52,13 +52,13 @@
                         <div class="input-group-addon">
                             <i class="fa fa-check-square"></i>
                         </div>
-                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="验证码" autocomplete="off">&nbsp;
+                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="{{i18n .Lang "common.captcha"}}" autocomplete="off">&nbsp;
                     </div>
                     <img id="captcha-img" style="width: 140px;height: 40px;display: inline-block;float: right" src="{{urlfor "AccountController.Captcha"}}" onclick="this.src='{{urlfor "AccountController.Captcha"}}?key=login&t='+(new Date()).getTime();" title="点击换一张">
                     <div class="clearfix"></div>
                 </div>
                 <div class="form-group">
-                    <button type="submit" id="btnSendMail" class="btn btn-success" style="width: 100%"  data-loading-text="正在处理..." autocomplete="off">找回密码</button>
+                    <button type="submit" id="btnSendMail" class="btn btn-success" style="width: 100%"  data-loading-text="{{i18n .Lang "message.processing"}}" autocomplete="off">{{i18n .Lang "common.account_recovery"}}</button>
                 </div>
 
             </form>
@@ -92,26 +92,26 @@
                 var code = $.trim($("#code").val());
 
                 if(newPassword === ""){
-                    $("#newPassword").tooltip({placement:"auto",title : "密码不能为空",trigger : 'manual'})
+                    $("#newPassword").tooltip({placement:"auto",title : "{{i18n .Lang "message.password_empty"}}",trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
 
                     return false;
 
                 }else if(confirmPassword === ""){
-                    $("#confirmPassword").tooltip({placement:"auto",title : "确认密码不能为空",trigger : 'manual'})
+                    $("#confirmPassword").tooltip({placement:"auto",title : "{{i18n .Lang "message.confirm_password_empty"}}",trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
 
                     return false;
                 }else if(newPassword !== confirmPassword) {
-                    $("#confirmPassword").tooltip({placement:"auto",title : "确认密码输入不正确",trigger : 'manual'})
+                    $("#confirmPassword").tooltip({placement:"auto",title : "{{i18n .Lang "message.incorrect_confirm_password"}}",trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
 
                     return false;
                 }else if(code === ""){
-                    $("#code").tooltip({title : '验证码不能为空',trigger : 'manual'})
+                    $("#code").tooltip({title : '{{i18n .Lang "message.captcha_empty"}}',trigger : 'manual'})
                         .tooltip('show')
                         .parents('.form-group').addClass('has-error');
 
@@ -134,7 +134,7 @@
             error :function () {
                 $("#captcha-img").click();
                 $("#code").val('');
-                layer.msg('系统错误');
+                layer.msg('{{i18n .Lang "message.system_error"}}');
                 $("#btnSendMail").button('reset');
             }
         });

+ 16 - 16
views/account/login.tpl

@@ -7,7 +7,7 @@
     <meta name="renderer" content="webkit" />
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <meta name="author" content="MinDoc" />
-    <title>用户登录 - Powered by MinDoc</title>
+    <title>{{i18n .Lang "common.login"}} - Powered by MinDoc</title>
     <meta name="keywords" content="MinDoc,文档在线管理系统,WIKI,wiki,wiki在线,文档在线管理,接口文档在线管理,接口文档管理">
     <meta name="description" content="MinDoc文档在线管理系统 {{.site_description}}">
     <!-- Bootstrap -->
@@ -30,13 +30,13 @@
         <div class="login-body">
             <form role="form" method="post">
             {{ .xsrfdata }}
-                <h3 class="text-center">用户登录</h3>
+                <h3 class="text-center">{{i18n .Lang "common.login"}}</h3>
                 <div class="form-group">
                     <div class="input-group">
                         <div class="input-group-addon">
                             <i class="fa fa-user"></i>
                         </div>
-                        <input type="text" class="form-control" placeholder="邮箱 / 用户名" name="account" id="account" autocomplete="off">
+                        <input type="text" class="form-control" placeholder="{{i18n .Lang "common.email"}} / {{i18n .Lang "common.username"}}" name="account" id="account" autocomplete="off">
                     </div>
                 </div>
                 <div class="form-group">
@@ -44,7 +44,7 @@
                         <div class="input-group-addon">
                             <i class="fa fa-lock"></i>
                         </div>
-                        <input type="password" class="form-control" placeholder="密码" name="password" id="password" autocomplete="off">
+                        <input type="password" class="form-control" placeholder="{{i18n .Lang "common.password"}}" name="password" id="password" autocomplete="off">
                     </div>
                 </div>
                 {{if .ENABLED_CAPTCHA }}
@@ -54,38 +54,38 @@
                         <div class="input-group-addon">
                             <i class="fa fa-check-square"></i>
                         </div>
-                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="验证码" autocomplete="off">&nbsp;
+                        <input type="text" name="code" id="code" class="form-control" style="width: 150px" maxlength="5" placeholder="{{i18n .Lang "common.captcha"}}" autocomplete="off">&nbsp;
                     </div>
-                    <img id="captcha-img" style="width: 140px;height: 40px;display: inline-block;float: right" src="{{urlfor "AccountController.Captcha"}}" onclick="this.src='{{urlfor "AccountController.Captcha"}}?key=login&t='+(new Date()).getTime();" title="点击换一张">
+                    <img id="captcha-img" style="width: 140px;height: 40px;display: inline-block;float: right" src="{{urlfor "AccountController.Captcha"}}" onclick="this.src='{{urlfor "AccountController.Captcha"}}?key=login&t='+(new Date()).getTime();" title={{i18n .Lang "message.click_to_change"}}>
                     <div class="clearfix"></div>
                 </div>
                 {{end}}
                 {{end}}
                 <div class="checkbox">
                     <label>
-                        <input type="checkbox" name="is_remember" value="yes"> 保持登录
+                        <input type="checkbox" name="is_remember" value="yes"> {{i18n .Lang "common.keep_login"}}
                     </label>
-                    <a href="{{urlfor "AccountController.FindPassword" }}" style="display: inline-block;float: right">忘记密码?</a>
+                    <a href="{{urlfor "AccountController.FindPassword" }}" style="display: inline-block;float: right">{{i18n .Lang "common.forgot_password"}}</a>
                 </div>
                 <div class="form-group">
-                    <button type="button" id="btn-login" class="btn btn-success" style="width: 100%"  data-loading-text="正在登录..." autocomplete="off">立即登录</button>
+                    <button type="button" id="btn-login" class="btn btn-success" style="width: 100%"  data-loading-text="{{i18n .Lang "common.logging_in"}}" autocomplete="off">{{i18n .Lang "common.login"}}</button>
                 </div>
                 {{if .ENABLE_QR_DINGTALK}}
                 <div class="form-group">
-                    <a id="btn-dingtalk-qr" class="btn btn-default" style="width: 100%" data-loading-text="" autocomplete="off">钉钉扫码登录</a>
+                    <a id="btn-dingtalk-qr" class="btn btn-default" style="width: 100%" data-loading-text="" autocomplete="off">{{i18n .Lang "common.dingtalk_login"}}</a>
                 </div>
                 {{end}}
                 {{if .ENABLED_REGISTER}}
                 {{if ne .ENABLED_REGISTER "false"}}
                 <div class="form-group">
-                    还没有账号?<a href="{{urlfor "AccountController.Register" }}" title="立即注册">立即注册</a>
+                    {{i18n .Lang "message.no_account_yet"}}<a href="{{urlfor "AccountController.Register" }}" title={{i18n .Lang "common.register"}}>{{i18n .Lang "common.register"}}</a>
                 </div>
                 {{end}}
                 {{end}}
             </form>
             <div class="form-group dingtalk-container" style="display: none;">
                 <div id="dingtalk-qr-container"></div>
-                <a class="btn btn-default btn-dingtalk" style="width: 100%" data-loading-text="" autocomplete="off">返回账号密码登录</a>
+                <a class="btn btn-default btn-dingtalk" style="width: 100%" data-loading-text="" autocomplete="off">{{i18n .Lang "message.return_account_login"}}</a>
             </div>
         </div>
     </div>
@@ -196,19 +196,19 @@
             var code = $("#code").val();
 
             if (account === "") {
-                $("#account").tooltip({ placement: "auto", title: "账号不能为空", trigger: 'manual' })
+                $("#account").tooltip({ placement: "auto", title: "{{i18n .Lang "message.account_empty"}}", trigger: 'manual' })
                     .tooltip('show')
                     .parents('.form-group').addClass('has-error');
                 $btn.button('reset');
                 return false;
             } else if (password === "") {
-                $("#password").tooltip({ title: '密码不能为空', trigger: 'manual' })
+                $("#password").tooltip({ title: '{{i18n .Lang "message.password_empty"}}', trigger: 'manual' })
                     .tooltip('show')
                     .parents('.form-group').addClass('has-error');
                 $btn.button('reset');
                 return false;
             } else if (code !== undefined && code === "") {
-                $("#code").tooltip({ title: '验证码不能为空', trigger: 'manual' })
+                $("#code").tooltip({ title: '{{i18n .Lang "message.captcha_empty"}}', trigger: 'manual' })
                     .tooltip('show')
                     .parents('.form-group').addClass('has-error');
                 $btn.button('reset');
@@ -236,7 +236,7 @@
                     error: function () {
                         $("#captcha-img").click();
                         $("#code").val('');
-                        layer.msg('系统错误');
+                        layer.msg('{{i18n .Lang "message.system_error"}}');
                         $btn.button('reset');
                     }
                 });

+ 4 - 4
views/widgets/footer.tpl

@@ -1,13 +1,13 @@
 <div class="footer">
     <div class="container">
         <div class="row text-center border-top">
-            <span><a href="https://www.iminho.me" target="_blank">官方网站</a></span>
+            <span><a href="https://www.iminho.me" target="_blank">{{i18n .Lang "common.official_website"}}</a></span>
             <span>&nbsp;·&nbsp;</span>
-            <span><a href="https://github.com/mindoc-org/mindoc/issues" target="_blank">意见反馈</a></span>
+            <span><a href="https://github.com/mindoc-org/mindoc/issues" target="_blank">{{i18n .Lang "common.feedback"}}</a></span>
             <span>&nbsp;·&nbsp;</span>
-            <span><a href="https://github.com/mindoc-org/mindoc" target="_blank">项目源码</a></span>
+            <span><a href="https://github.com/mindoc-org/mindoc" target="_blank">{{i18n .Lang "common.source_code"}}</a></span>
             <span>&nbsp;·&nbsp;</span>
-            <span><a href="https://www.iminho.me/wiki/docs/mindoc/" target="_blank">使用手册</a></span>
+            <span><a href="https://www.iminho.me/wiki/docs/mindoc/" target="_blank">{{i18n .Lang "common.manual"}}</a></span>
         </div>
         {{if .site_beian}}
         <div class="row text-center">