Skip to content

Commit 83ce744

Browse files
authored
feat: Adapt to internationalization (#7205)
1 parent ae03b85 commit 83ce744

File tree

19 files changed

+219
-149
lines changed

19 files changed

+219
-149
lines changed

backend/app/api/v1/auth.go

+9
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ func (b *BaseApi) CheckIsDemo(c *gin.Context) {
130130
helper.SuccessWithData(c, global.CONF.System.IsDemo)
131131
}
132132

133+
// @Tags Auth
134+
// @Summary Check System isDemo
135+
// @Description 判断是否为国际版
136+
// @Success 200
137+
// @Router /auth/intl [get]
138+
func (b *BaseApi) CheckIsIntl(c *gin.Context) {
139+
helper.SuccessWithData(c, global.CONF.System.IsIntl)
140+
}
141+
133142
// @Tags Auth
134143
// @Summary Load System Language
135144
// @Description 获取系统语言设置

backend/configs/system.go

+2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ type System struct {
2020
Username string `mapstructure:"username"`
2121
Password string `mapstructure:"password"`
2222
Entrance string `mapstructure:"entrance"`
23+
Language string `mapstructure:"language"`
2324
IsDemo bool `mapstructure:"is_demo"`
25+
IsIntl bool `mapstructure:"is_intl"`
2426
AppRepo string `mapstructure:"app_repo"`
2527
ChangeUserInfo string `mapstructure:"change_user_info"`
2628
OneDriveID string `mapstructure:"one_drive_id"`

backend/init/migration/migrations/init.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ var AddTableSetting = &gormigrate.Migration{
7272
}
7373
global.CONF.System.EncryptKey = encryptKey
7474
pass, _ := encrypt.StringEncrypt(global.CONF.System.Password)
75+
language := "en"
76+
if global.CONF.System.Language == "zh" {
77+
language = "zh"
78+
}
79+
7580
if err := tx.Create(&model.Setting{Key: "Password", Value: pass}).Error; err != nil {
7681
return err
7782
}
@@ -82,7 +87,7 @@ var AddTableSetting = &gormigrate.Migration{
8287
if err := tx.Create(&model.Setting{Key: "PanelName", Value: "1Panel"}).Error; err != nil {
8388
return err
8489
}
85-
if err := tx.Create(&model.Setting{Key: "Language", Value: "zh"}).Error; err != nil {
90+
if err := tx.Create(&model.Setting{Key: "Language", Value: language}).Error; err != nil {
8691
return err
8792
}
8893
if err := tx.Create(&model.Setting{Key: "Theme", Value: "light"}).Error; err != nil {

backend/init/viper/viper.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func Init() {
2121
port := "9999"
2222
mode := ""
2323
version := "v1.0.0"
24-
username, password, entrance := "", "", ""
24+
username, password, entrance, language := "", "", "", "zh"
2525
fileOp := files.NewFileOp()
2626
v := viper.NewWithOptions()
2727
v.SetConfigType("yaml")
@@ -46,6 +46,7 @@ func Init() {
4646
username = loadParams("ORIGINAL_USERNAME")
4747
password = loadParams("ORIGINAL_PASSWORD")
4848
entrance = loadParams("ORIGINAL_ENTRANCE")
49+
language = loadParams("LANGUAGE")
4950

5051
reader := bytes.NewReader(conf.AppYaml)
5152
if err := v.ReadConfig(reader); err != nil {
@@ -80,11 +81,15 @@ func Init() {
8081
if serverConfig.System.Entrance != "" {
8182
entrance = serverConfig.System.Entrance
8283
}
84+
if serverConfig.System.IsIntl {
85+
language = "en"
86+
}
8387
}
8488

8589
global.CONF = serverConfig
8690
global.CONF.System.BaseDir = baseDir
8791
global.CONF.System.IsDemo = v.GetBool("system.is_demo")
92+
global.CONF.System.IsIntl = v.GetBool("system.is_intl")
8893
global.CONF.System.DataDir = path.Join(global.CONF.System.BaseDir, "1panel")
8994
global.CONF.System.Cache = path.Join(global.CONF.System.DataDir, "cache")
9095
global.CONF.System.Backup = path.Join(global.CONF.System.DataDir, "backup")
@@ -96,6 +101,7 @@ func Init() {
96101
global.CONF.System.Username = username
97102
global.CONF.System.Password = password
98103
global.CONF.System.Entrance = entrance
104+
global.CONF.System.Language = language
99105
global.CONF.System.ChangeUserInfo = loadChangeInfo()
100106
global.Viper = v
101107
}

backend/router/ro_base.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ func (s *BaseRouter) InitRouter(Router *gin.RouterGroup) {
1717
baseRouter.POST("/logout", baseApi.LogOut)
1818
baseRouter.GET("/demo", baseApi.CheckIsDemo)
1919
baseRouter.GET("/language", baseApi.GetLanguage)
20+
baseRouter.GET("/intl", baseApi.CheckIsIntl)
2021
}
2122
}

cmd/server/conf/app.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ system:
55
repo_url: https://resource.fit2cloud.com/1panel/package
66
app_repo: https://apps-assets.fit2cloud.com
77
is_demo: false
8+
is_intl: true
89
port: 9999
910
username: admin
1011
password: admin123

frontend/src/api/modules/auth.ts

+4
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ export const checkIsDemo = () => {
2424
export const getLanguage = () => {
2525
return http.get<string>(`/auth/language`);
2626
};
27+
28+
export const checkIsIntl = () => {
29+
return http.get<boolean>('/auth/intl');
30+
};

frontend/src/components/system-upgrade/index.vue

+10-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<el-link type="primary" :underline="false" @click="toForum">
66
<span class="font-normal">{{ $t('setting.forum') }}</span>
77
</el-link>
8-
<el-divider direction="vertical" />
9-
<el-link type="primary" :underline="false" @click="toDoc">
8+
<el-divider direction="vertical" v-if="!globalStore.isIntl" />
9+
<el-link type="primary" :underline="false" @click="toDoc" v-if="!globalStore.isIntl">
1010
<span class="font-normal">{{ $t('setting.doc2') }}</span>
1111
</el-link>
1212
<el-divider direction="vertical" />
@@ -17,7 +17,7 @@
1717
</div>
1818
<div class="flex flex-wrap items-center">
1919
<el-link :underline="false" type="primary" @click="toHalo">
20-
{{ isProductPro ? $t('license.pro') : $t('license.community') }}
20+
{{ isProductPro && globalStore.isIntl ? $t('license.pro') : $t('license.community') }}
2121
</el-link>
2222
<el-link :underline="false" class="version" type="primary" @click="copyText(version)">
2323
{{ version }}
@@ -122,15 +122,20 @@ const handleClose = () => {
122122
};
123123
124124
const toHalo = () => {
125-
window.open('https://www.lxware.cn/1panel' + '', '_blank', 'noopener,noreferrer');
125+
if (!globalStore.isIntl) {
126+
window.open('https://www.lxware.cn/1panel' + '', '_blank', 'noopener,noreferrer');
127+
}
126128
};
127129
128130
const toDoc = () => {
129131
window.open('https://1panel.cn/docs/', '_blank', 'noopener,noreferrer');
130132
};
131133
132134
const toForum = () => {
133-
window.open('https://bbs.fit2cloud.com/c/1p/7', '_blank');
135+
let url = globalStore.isIntl
136+
? 'https://github.com/1Panel-dev/1Panel/discussions'
137+
: 'https://bbs.fit2cloud.com/c/1p/7';
138+
window.open(url, '_blank');
134139
};
135140
136141
const toGithub = () => {

frontend/src/lang/modules/en.ts

+2
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,8 @@ const message = {
344344
kernelArch: 'Kernel arch',
345345
network: 'Network',
346346
io: 'Disk IO',
347+
ip: 'Host Address',
348+
proxy: 'System Proxy',
347349
baseInfo: 'Base info',
348350
totalSend: 'Total send',
349351
totalRecv: 'Total recv',

frontend/src/layout/components/Sidebar/index.vue

+15-5
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import Logo from './components/Logo.vue';
4242
import Collapse from './components/Collapse.vue';
4343
import SubItem from './components/SubItem.vue';
4444
import router, { menuList } from '@/routers/router';
45-
import { logOutApi } from '@/api/modules/auth';
45+
import { checkIsIntl, logOutApi } from '@/api/modules/auth';
4646
import i18n from '@/lang';
4747
import { ElMessageBox } from 'element-plus';
4848
import { GlobalStore, MenuStore } from '@/store';
@@ -68,7 +68,7 @@ const activeMenu = computed(() => {
6868
const isCollapse = computed((): boolean => menuStore.isCollapse);
6969
7070
let routerMenus = computed((): RouteRecordRaw[] => {
71-
return menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar);
71+
return menuStore.menuList.filter((route) => route.meta && !route.meta.hideInSidebar) as RouteRecordRaw[];
7272
});
7373
7474
const screenWidth = ref(0);
@@ -132,9 +132,14 @@ function getCheckedLabels(json: Node): string[] {
132132
}
133133
134134
const search = async () => {
135-
const res = await getSettingInfo();
136-
const json: Node = JSON.parse(res.data.xpackHideMenu);
137-
const checkedLabels = getCheckedLabels(json);
135+
await checkIsSystemIntl();
136+
let checkedLabels: string | any[];
137+
if (!globalStore.isIntl) {
138+
const res = await getSettingInfo();
139+
const json: Node = JSON.parse(res.data.xpackHideMenu);
140+
checkedLabels = getCheckedLabels(json);
141+
}
142+
138143
let rstMenuList: RouteRecordRaw[] = [];
139144
menuStore.menuList.forEach((item) => {
140145
let menuItem = JSON.parse(JSON.stringify(item));
@@ -173,6 +178,11 @@ const search = async () => {
173178
menuStore.menuList = rstMenuList;
174179
};
175180
181+
const checkIsSystemIntl = async () => {
182+
const res = await checkIsIntl();
183+
globalStore.isIntl = res.data;
184+
};
185+
176186
onMounted(() => {
177187
menuStore.setMenuList(menuList);
178188
search();

frontend/src/store/interface/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export interface GlobalState {
3434
defaultNetwork: string;
3535

3636
isProductPro: boolean;
37+
isIntl: boolean;
3738
isTrial: boolean;
3839
productProExpires: number;
3940

frontend/src/store/modules/global.ts

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const GlobalStore = defineStore({
3737
defaultNetwork: 'all',
3838

3939
isProductPro: false,
40+
isIntl: false,
4041
isTrial: false,
4142
productProExpires: 0,
4243

frontend/src/views/cronjob/operate/index.vue

+26-24
Original file line numberDiff line numberDiff line change
@@ -320,30 +320,32 @@
320320
</el-form-item>
321321
</div>
322322

323-
<el-form-item prop="hasAlert">
324-
<el-checkbox v-model="dialogData.rowData!.hasAlert" :label="$t('alert.isAlert')" />
325-
<span class="input-help">{{ $t('alert.cronJobHelper') }}</span>
326-
</el-form-item>
327-
<el-form-item
328-
prop="alertCount"
329-
v-if="dialogData.rowData!.hasAlert && isProductPro"
330-
:label="$t('alert.alertCount')"
331-
>
332-
<el-input-number
333-
style="width: 200px"
334-
:min="1"
335-
step-strictly
336-
:step="1"
337-
v-model.number="dialogData.rowData!.alertCount"
338-
></el-input-number>
339-
<span class="input-help">{{ $t('alert.alertCountHelper') }}</span>
340-
</el-form-item>
341-
<el-form-item v-if="dialogData.rowData!.hasAlert && !isProductPro">
342-
<span>{{ $t('alert.licenseHelper') }}</span>
343-
<el-button link type="primary" @click="toUpload">
344-
{{ $t('license.levelUpPro') }}
345-
</el-button>
346-
</el-form-item>
323+
<div v-if="!globalStore.isIntl">
324+
<el-form-item prop="hasAlert">
325+
<el-checkbox v-model="dialogData.rowData!.hasAlert" :label="$t('alert.isAlert')" />
326+
<span class="input-help">{{ $t('alert.cronJobHelper') }}</span>
327+
</el-form-item>
328+
<el-form-item
329+
prop="alertCount"
330+
v-if="dialogData.rowData!.hasAlert && isProductPro"
331+
:label="$t('alert.alertCount')"
332+
>
333+
<el-input-number
334+
style="width: 200px"
335+
:min="1"
336+
step-strictly
337+
:step="1"
338+
v-model.number="dialogData.rowData!.alertCount"
339+
></el-input-number>
340+
<span class="input-help">{{ $t('alert.alertCountHelper') }}</span>
341+
</el-form-item>
342+
<el-form-item v-if="dialogData.rowData!.hasAlert && !isProductPro">
343+
<span>{{ $t('alert.licenseHelper') }}</span>
344+
<el-button link type="primary" @click="toUpload">
345+
{{ $t('license.levelUpPro') }}
346+
</el-button>
347+
</el-form-item>
348+
</div>
347349

348350
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
349351
<el-input-number

frontend/src/views/home/index.vue

+4-6
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
]"
1010
>
1111
<template #route-button>
12-
<div class="router-button">
13-
<template v-if="!isProductPro">
14-
<el-button link type="primary" @click="toUpload">
15-
{{ $t('license.levelUpPro') }}
16-
</el-button>
17-
</template>
12+
<div class="router-button" v-if="!isProductPro && !globalStore.isIntl">
13+
<el-button link type="primary" @click="toUpload">
14+
{{ $t('license.levelUpPro') }}
15+
</el-button>
1816
</div>
1917
</template>
2018
</RouterButton>

frontend/src/views/login/components/login-form.vue

+30-17
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,24 @@
120120
{{ $t('commons.button.login') }}
121121
</el-button>
122122
</el-form-item>
123-
<el-form-item prop="agreeLicense">
124-
<el-checkbox v-model="loginForm.agreeLicense">
125-
<template #default>
126-
<span class="agree" v-html="$t('commons.login.licenseHelper')"></span>
127-
</template>
128-
</el-checkbox>
129-
</el-form-item>
130-
<div class="agree-helper">
131-
<span
132-
v-if="!loginForm.agreeLicense && !_isMobile()"
133-
class="input-error"
134-
style="line-height: 14px"
135-
>
136-
{{ $t('commons.login.errorAgree') }}
137-
</span>
138-
</div>
123+
<template v-if="!isIntl">
124+
<el-form-item prop="agreeLicense">
125+
<el-checkbox v-model="loginForm.agreeLicense">
126+
<template #default>
127+
<span class="agree" v-html="$t('commons.login.licenseHelper')"></span>
128+
</template>
129+
</el-checkbox>
130+
</el-form-item>
131+
<div class="agree-helper">
132+
<span
133+
v-if="!loginForm.agreeLicense && !_isMobile()"
134+
class="input-error"
135+
style="line-height: 14px"
136+
>
137+
{{ $t('commons.login.errorAgree') }}
138+
</span>
139+
</div>
140+
</template>
139141
</el-form>
140142
<div class="demo">
141143
<span v-if="isDemo">
@@ -171,7 +173,7 @@
171173
import { ref, reactive, onMounted, computed } from 'vue';
172174
import { useRouter } from 'vue-router';
173175
import type { ElForm } from 'element-plus';
174-
import { loginApi, getCaptcha, mfaLoginApi, checkIsDemo, getLanguage } from '@/api/modules/auth';
176+
import { loginApi, getCaptcha, mfaLoginApi, checkIsDemo, getLanguage, checkIsIntl } from '@/api/modules/auth';
175177
import { GlobalStore, MenuStore, TabsStore } from '@/store';
176178
import { MsgSuccess } from '@/utils/message';
177179
import { useI18n } from 'vue-i18n';
@@ -188,6 +190,7 @@ const errAuthInfo = ref(false);
188190
const errCaptcha = ref(false);
189191
const errMfaInfo = ref(false);
190192
const isDemo = ref(false);
193+
const isIntl = ref(true);
191194
const agreeVisible = ref(false);
192195
193196
type FormInstance = InstanceType<typeof ElForm>;
@@ -235,6 +238,12 @@ const mfaShow = ref<boolean>(false);
235238
const router = useRouter();
236239
const dropdownText = ref('中文(简体)');
237240
241+
const checkIsSystemIntl = async () => {
242+
const res = await checkIsIntl();
243+
isIntl.value = res.data;
244+
globalStore.isIntl = isIntl.value;
245+
};
246+
238247
function handleCommand(command: string) {
239248
loginForm.language = command;
240249
usei18n.locale.value = command;
@@ -258,6 +267,9 @@ const login = (formEl: FormInstance | undefined) => {
258267
if (!formEl || isLoggingIn) return;
259268
formEl.validate(async (valid) => {
260269
if (!valid) return;
270+
if (isIntl.value) {
271+
loginForm.agreeLicense = true;
272+
}
261273
if (!loginForm.agreeLicense) {
262274
if (_isMobile()) {
263275
agreeVisible.value = true;
@@ -372,6 +384,7 @@ const loadDataFromDB = async () => {
372384
373385
onMounted(() => {
374386
globalStore.isOnRestart = false;
387+
checkIsSystemIntl();
375388
loginVerify();
376389
loadLanguage();
377390
document.title = globalStore.themeConfig.panelName;

frontend/src/views/setting/about/index.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<SystemUpgrade />
1717
</div>
1818
<div class="flex w-full justify-center my-5 flex-wrap md:flex-row gap-4">
19-
<el-link @click="toDoc" class="system-link">
19+
<el-link @click="toDoc" class="system-link" v-if="!globalStore.isIntl">
2020
<el-icon><Document /></el-icon>
2121
<span>{{ $t('setting.doc2') }}</span>
2222
</el-link>

0 commit comments

Comments
 (0)