Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Multi-Language #180

Open
wants to merge 83 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
1ff2af1
add: vue-i18n file
foroughi1380 Oct 27, 2022
a2db446
creade client ip db model
hossinasaadi Oct 29, 2022
d864d20
add email and ip limit to vmess ui
hossinasaadi Oct 29, 2022
20e7b9e
add client ip limit job
hossinasaadi Oct 29, 2022
07c53bc
update: remove vue i18n
foroughi1380 Oct 29, 2022
eae4ca6
update: add .chache folder to gitignore
foroughi1380 Oct 29, 2022
057491d
update: user i18n to show title
foroughi1380 Oct 29, 2022
0685387
update: add pages title
foroughi1380 Oct 29, 2022
1bb9cd5
update: translate page header title with i18n
foroughi1380 Oct 29, 2022
35652d2
updatE: ignore
foroughi1380 Oct 29, 2022
01970cf
update: read localizer from cookies
foroughi1380 Oct 29, 2022
90cb773
update: create supoorted lanquage array
foroughi1380 Oct 29, 2022
74b5dcd
update: relocate the langs.js
foroughi1380 Oct 29, 2022
214a2e3
update: load langs file
foroughi1380 Oct 29, 2022
d4a32a2
update: add required function for set and get current lang
foroughi1380 Oct 29, 2022
bf34f23
update: add a select box to select lang
foroughi1380 Oct 29, 2022
da1f161
update: add language button to setting
foroughi1380 Oct 29, 2022
1f87c1f
update: translate common sider
foroughi1380 Oct 29, 2022
2d2d13a
pass i18n to next level
foroughi1380 Oct 30, 2022
1811783
update: add a function to translate
foroughi1380 Oct 30, 2022
d2544e7
update: pass name to i18n function
foroughi1380 Oct 30, 2022
25e818e
update: translate login page toasts
foroughi1380 Oct 30, 2022
d28da19
update: translate panel config in setting page
foroughi1380 Oct 30, 2022
3289658
update: translate tabs
foroughi1380 Oct 30, 2022
7c72aac
translate user
foroughi1380 Oct 30, 2022
f3d394a
update: translate xray configuration in setting page
foroughi1380 Oct 30, 2022
41023ef
update: translate tg panel
foroughi1380 Oct 30, 2022
ab0a7f9
update: translate other setting
foroughi1380 Oct 30, 2022
9289ce6
update: translate dashboard
foroughi1380 Oct 30, 2022
fa62f8e
update: translate dashboard
foroughi1380 Oct 30, 2022
5e4c8b4
update: translate inbound table titles
foroughi1380 Oct 30, 2022
33aa572
update: translate table
foroughi1380 Oct 30, 2022
cdd96ee
update: translate operate menu
foroughi1380 Oct 30, 2022
7c2471d
update: translate dialogs
foroughi1380 Oct 30, 2022
b7233a9
update: translate buttons and title of details dialog
foroughi1380 Oct 30, 2022
2722d29
restart xray service after disable inbound
hossinasaadi Oct 30, 2022
e0abaf5
add ip log, clear ip log button in edit modal
hossinasaadi Oct 30, 2022
6863c2b
update: translate restart panel dialog
foroughi1380 Oct 30, 2022
606b741
update: translate dialog
foroughi1380 Oct 30, 2022
beacad3
remove merging new ips and old ones in ip log
hossinasaadi Oct 30, 2022
41e7201
update: translate inbound_info
foroughi1380 Oct 30, 2022
6f97a5c
update: translate inbound modal
foroughi1380 Oct 30, 2022
17b9057
update: translate dokodemo porotocol
foroughi1380 Oct 30, 2022
58327d5
replace text and add condtion to field
hossinasaadi Oct 30, 2022
441ae56
update: fix target address
foroughi1380 Oct 30, 2022
60b649b
bugs fix
hossinasaadi Oct 30, 2022
061e005
update: translate protocol
foroughi1380 Oct 31, 2022
114af22
update: translate inbound modal
foroughi1380 Oct 31, 2022
2b5fd5c
update: util controller translate
foroughi1380 Oct 31, 2022
d6f8c9d
update :translate base cotroller
foroughi1380 Oct 31, 2022
2cea3d0
update: translate inbound component
foroughi1380 Oct 31, 2022
66d21fa
update: translate setting and server controller
foroughi1380 Oct 31, 2022
9235ef5
update: remove always return true in debug mode
foroughi1380 Oct 31, 2022
f8bddd4
add vless limit ip
proshir Nov 1, 2022
375835e
clear ip log for clients after 1 min with bulk add
proshir Nov 2, 2022
91e416b
set default limitIp value
hossinasaadi Nov 2, 2022
74f7af6
fix funny bug in line 49 check_clinet_ip_job
proshir Nov 2, 2022
b5a6882
Merge pull request #1 from proshir/main
hossinasaadi Nov 2, 2022
3d0f25b
add connection limit inbound
hossinasaadi Nov 4, 2022
87b301c
fix run schedule run time
hossinasaadi Nov 4, 2022
d564956
ip sort and fix bug
hossinasaadi Nov 4, 2022
131a9ae
change job run time
hossinasaadi Nov 4, 2022
b95a8ec
Merge pull request #6 from hossinasaadi/limit-connection
hossinasaadi Nov 4, 2022
44ca9cc
fix IP Restrict bug
hossinasaadi Nov 5, 2022
10613bd
Merge pull request #11 from hossinasaadi/limit-connection
hossinasaadi Nov 5, 2022
91c891c
Update README.md
hossinasaadi Nov 5, 2022
8282a3b
Update install.sh
hossinasaadi Nov 5, 2022
7327f26
Update x-ui.sh
hossinasaadi Nov 5, 2022
675c211
fix getting server IP
hossinasaadi Nov 5, 2022
5e2c12b
Merge pull request #12 from hossinasaadi/limit-connection
hossinasaadi Nov 5, 2022
253f5dc
sort Log Ips
hossinasaadi Nov 5, 2022
b9f1dcc
Merge pull request #13 from hossinasaadi/limit-connection
hossinasaadi Nov 5, 2022
3f03070
lower schedule time
hossinasaadi Nov 5, 2022
3bac66c
Merge pull request #16 from hossinasaadi/limit-connection
hossinasaadi Nov 5, 2022
ec56af4
revert schedule time
hossinasaadi Nov 5, 2022
be55e44
Merge pull request #18 from hossinasaadi/limit-connection
hossinasaadi Nov 5, 2022
3c5ddad
fix clean all Ip database
hossinasaadi Nov 6, 2022
e2150c3
add func
hossinasaadi Nov 6, 2022
cb4f02c
Merge pull request #22 from hossinasaadi/limit-connection
hossinasaadi Nov 6, 2022
62d8c47
add Environment & update sh files
hossinasaadi Nov 7, 2022
979eccf
Update release.yml
hossinasaadi Nov 7, 2022
5705948
Merge pull request #25 from hossinasaadi/limit-connection
hossinasaadi Nov 7, 2022
a73f20e
Merge branch 'main' into main
hossinasaadi Nov 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ x-ui-*.tar.gz
/release.sh
.sync*
main
.cache
79 changes: 79 additions & 0 deletions web/assets/js/langs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
supportLangs = [
{
name : "English",
value : "en-US",
icon : "🇺🇸"
},
{
name : "汉语",
value : "zh-Hans",
icon : "🇨🇳"
},
]

function getLang(){
let lang = getCookie('lang')

if (! lang){
if (window.navigator){
lang = window.navigator.language || window.navigator.userLanguage;

if (isSupportLang(lang)){
setCookie('lang' , lang , 150)
}else{
setCookie('lang' , 'en-US' , 150)
window.location.reload();
}
}else{
setCookie('lang' , 'en-US' , 150)
window.location.reload();
}
}

return lang;
}

function setLang(lang){

if (!isSupportLang(lang)){
lang = 'en-US';
}

setCookie('lang' , lang , 150)
window.location.reload();
}

function isSupportLang(lang){
for (l of supportLangs){
if (l.value === lang){
return true;
}
}

return false;
}



function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for(let i = 0; i <ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return "";
}

function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
let expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
8 changes: 4 additions & 4 deletions web/assets/js/util/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ function safeBase64(str) {

function formatSecond(second) {
if (second < 60) {
return second.toFixed(0) + ' ';
return second.toFixed(0) + ' s';
} else if (second < 3600) {
return (second / 60).toFixed(0) + ' 分钟';
return (second / 60).toFixed(0) + ' m';
} else if (second < 3600 * 24) {
return (second / 3600).toFixed(0) + ' 小时';
return (second / 3600).toFixed(0) + ' h';
} else {
return (second / 3600 / 24).toFixed(0) + ' ';
return (second / 3600 / 24).toFixed(0) + ' d';
}
}

Expand Down
12 changes: 11 additions & 1 deletion web/controller/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type BaseController struct {
func (a *BaseController) checkLogin(c *gin.Context) {
if !session.IsLogin(c) {
if isAjax(c) {
pureJsonMsg(c, false, "登录时效已过,请重新登录")
pureJsonMsg(c, false, I18n(c , "pages.login.loginAgain"))
} else {
c.Redirect(http.StatusTemporaryRedirect, c.GetString("base_path"))
}
Expand All @@ -21,3 +21,13 @@ func (a *BaseController) checkLogin(c *gin.Context) {
c.Next()
}
}


func I18n(c *gin.Context , name string, data ...string) string{
anyfunc, _ := c.Get("I18n")
i18n, _ := anyfunc.(func(key string, params ...string) (string, error))

message, _ := i18n(name)

return message;
}
16 changes: 8 additions & 8 deletions web/controller/inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (a *InboundController) getInbounds(c *gin.Context) {
user := session.GetLoginUser(c)
inbounds, err := a.inboundService.GetInbounds(user.Id)
if err != nil {
jsonMsg(c, "获取", err)
jsonMsg(c, I18n(c , "pages.inbounds.toasts.obtain"), err)
return
}
jsonObj(c, inbounds, nil)
Expand All @@ -59,15 +59,15 @@ func (a *InboundController) addInbound(c *gin.Context) {
inbound := &model.Inbound{}
err := c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "添加", err)
jsonMsg(c, I18n(c , "pages.inbounds.addTo"), err)
return
}
user := session.GetLoginUser(c)
inbound.UserId = user.Id
inbound.Enable = true
inbound.Tag = fmt.Sprintf("inbound-%v", inbound.Port)
err = a.inboundService.AddInbound(inbound)
jsonMsg(c, "添加", err)
jsonMsg(c, I18n(c , "pages.inbounds.addTo"), err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
Expand All @@ -76,11 +76,11 @@ func (a *InboundController) addInbound(c *gin.Context) {
func (a *InboundController) delInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "删除", err)
jsonMsg(c, I18n(c , "delete"), err)
return
}
err = a.inboundService.DelInbound(id)
jsonMsg(c, "删除", err)
jsonMsg(c, I18n(c , "delete"), err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
Expand All @@ -89,19 +89,19 @@ func (a *InboundController) delInbound(c *gin.Context) {
func (a *InboundController) updateInbound(c *gin.Context) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil {
jsonMsg(c, "修改", err)
jsonMsg(c, I18n(c , "pages.inbounds.revise"), err)
return
}
inbound := &model.Inbound{
Id: id,
}
err = c.ShouldBind(inbound)
if err != nil {
jsonMsg(c, "修改", err)
jsonMsg(c, I18n(c , "pages.inbounds.revise"), err)
return
}
err = a.inboundService.UpdateInbound(inbound)
jsonMsg(c, "修改", err)
jsonMsg(c, I18n(c , "pages.inbounds.revise"), err)
if err == nil {
a.xrayService.SetToNeedRestart()
}
Expand Down
12 changes: 6 additions & 6 deletions web/controller/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,30 +39,30 @@ func (a *IndexController) index(c *gin.Context) {
c.Redirect(http.StatusTemporaryRedirect, "xui/")
return
}
html(c, "login.html", "登录", nil)
html(c, "login.html", "pages.login.title", nil)
}

func (a *IndexController) login(c *gin.Context) {
var form LoginForm
err := c.ShouldBind(&form)
if err != nil {
pureJsonMsg(c, false, "数据格式错误")
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.invalidFormData"))
return
}
if form.Username == "" {
pureJsonMsg(c, false, "请输入用户名")
pureJsonMsg(c, false, I18n(c, "pages.login.toasts.emptyUsername"))
return
}
if form.Password == "" {
pureJsonMsg(c, false, "请输入密码")
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.emptyPassword"))
return
}
user := a.userService.CheckUser(form.Username, form.Password)
timeStr := time.Now().Format("2006-01-02 15:04:05")
if user == nil {
job.NewStatsNotifyJob().UserLoginNotify(form.Username, getRemoteIp(c), timeStr, 0)
logger.Infof("wrong username or password: \"%s\" \"%s\"", form.Username, form.Password)
pureJsonMsg(c, false, "用户名或密码错误")
pureJsonMsg(c, false, I18n(c , "pages.login.toasts.wrongUsernameOrPassword"))
return
} else {
logger.Infof("%s login success,Ip Address:%s\n", form.Username, getRemoteIp(c))
Expand All @@ -71,7 +71,7 @@ func (a *IndexController) login(c *gin.Context) {

err = session.SetLoginUser(c, user)
logger.Info("user", user.Id, "login success")
jsonMsg(c, "登录", err)
jsonMsg(c, I18n(c , "pages.login.toasts.successLogin"), err)
}

func (a *IndexController) logout(c *gin.Context) {
Expand Down
4 changes: 2 additions & 2 deletions web/controller/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {

versions, err := a.serverService.GetXrayVersions()
if err != nil {
jsonMsg(c, "获取版本", err)
jsonMsg(c, I18n(c , "getVersion"), err)
return
}

Expand All @@ -81,5 +81,5 @@ func (a *ServerController) getXrayVersion(c *gin.Context) {
func (a *ServerController) installXray(c *gin.Context) {
version := c.Param("version")
err := a.serverService.UpdateXray(version)
jsonMsg(c, "安装 xray", err)
jsonMsg(c, I18n(c , "install") + " xray", err)
}
16 changes: 8 additions & 8 deletions web/controller/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (a *SettingController) initRouter(g *gin.RouterGroup) {
func (a *SettingController) getAllSetting(c *gin.Context) {
allSetting, err := a.settingService.GetAllSetting()
if err != nil {
jsonMsg(c, "获取设置", err)
jsonMsg(c, I18n(c , "pages.setting.toasts.getSetting"), err)
return
}
jsonObj(c, allSetting, nil)
Expand All @@ -50,27 +50,27 @@ func (a *SettingController) updateSetting(c *gin.Context) {
allSetting := &entity.AllSetting{}
err := c.ShouldBind(allSetting)
if err != nil {
jsonMsg(c, "修改设置", err)
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
return
}
err = a.settingService.UpdateAllSetting(allSetting)
jsonMsg(c, "修改设置", err)
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
}

func (a *SettingController) updateUser(c *gin.Context) {
form := &updateUserForm{}
err := c.ShouldBind(form)
if err != nil {
jsonMsg(c, "修改用户", err)
jsonMsg(c, I18n(c , "pages.setting.toasts.modifySetting"), err)
return
}
user := session.GetLoginUser(c)
if user.Username != form.OldUsername || user.Password != form.OldPassword {
jsonMsg(c, "修改用户", errors.New("原用户名或原密码错误"))
jsonMsg(c, I18n(c , "pages.setting.toasts.modifyUser"), errors.New(I18n(c , "pages.setting.toasts.originalUserPassIncorrect")))
return
}
if form.NewUsername == "" || form.NewPassword == "" {
jsonMsg(c, "修改用户", errors.New("新用户名和新密码不能为空"))
jsonMsg(c,I18n(c , "pages.setting.toasts.modifyUser"), errors.New(I18n(c , "pages.setting.toasts.userPassMustBeNotEmpty")))
return
}
err = a.userService.UpdateUser(user.Id, form.NewUsername, form.NewPassword)
Expand All @@ -79,10 +79,10 @@ func (a *SettingController) updateUser(c *gin.Context) {
user.Password = form.NewPassword
session.SetLoginUser(c, user)
}
jsonMsg(c, "修改用户", err)
jsonMsg(c, I18n(c , "pages.setting.toasts.modifyUser"), err)
}

func (a *SettingController) restartPanel(c *gin.Context) {
err := a.panelService.RestartPanel(time.Second * 3)
jsonMsg(c, "重启面板", err)
jsonMsg(c, I18n(c , "pages.setting.restartPanel"), err)
}
6 changes: 3 additions & 3 deletions web/controller/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,12 @@ func jsonMsgObj(c *gin.Context, msg string, obj interface{}, err error) {
if err == nil {
m.Success = true
if msg != "" {
m.Msg = msg + "成功"
m.Msg = msg + I18n(c , "success")
}
} else {
m.Success = false
m.Msg = msg + "失败: " + err.Error()
logger.Warning(msg+"失败: ", err)
m.Msg = msg + I18n(c , "fail") + ": " + err.Error()
logger.Warning(msg + I18n(c , "fail") + ": ", err)
}
c.JSON(http.StatusOK, m)
}
Expand Down
6 changes: 3 additions & 3 deletions web/controller/xui.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ func (a *XUIController) initRouter(g *gin.RouterGroup) {
}

func (a *XUIController) index(c *gin.Context) {
html(c, "index.html", "系统状态", nil)
html(c, "index.html", "pages.index.title", nil)
}

func (a *XUIController) inbounds(c *gin.Context) {
html(c, "inbounds.html", "入站列表", nil)
html(c, "inbounds.html", "pages.inbounds.title", nil)
}

func (a *XUIController) setting(c *gin.Context) {
html(c, "setting.html", "设置", nil)
html(c, "setting.html", "pages.setting.title", nil)
}
2 changes: 1 addition & 1 deletion web/html/common/head.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@
display: none;
}
</style>
<title>{{.title}}</title>
<title>{{ i18n .title}}</title>
</head>
{{end}}
1 change: 1 addition & 0 deletions web/html/common/js.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<script src="{{ .base_path }}assets/js/util/utils.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/model/xray.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/model/models.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/js/langs.js"></script>
<script>
const basePath = '{{ .base_path }}';
axios.defaults.baseURL = basePath;
Expand Down
6 changes: 3 additions & 3 deletions web/html/common/prompt_modal.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{define "promptModal"}}
<a-modal id="prompt-modal" v-model="promptModal.visible" :title="promptModal.title"
:closable="true" @ok="promptModal.ok" :mask-closable="false"
:ok-text="promptModal.okText" cancel-text="取消">
:ok-text="promptModal.okText" cancel-text='{{ i18n "cancel" }}'>
<a-input id="prompt-modal-input" :type="promptModal.type"
v-model="promptModal.value"
:autosize="{minRows: 10, maxRows: 20}"
Expand All @@ -15,7 +15,7 @@
title: '',
type: '',
value: '',
okText: '确定',
okText: '{{ i18n "sure"}}',
visible: false,
keyEnter(e) {
if (this.type !== 'textarea') {
Expand All @@ -38,7 +38,7 @@
title='',
type='text',
value='',
okText='确定',
okText='{{ i18n "sure"}}',
confirm=() => {},
}) {
this.title = title;
Expand Down
Loading