Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
66de947d
M
metersphere
项目概览
MeterSphere
/
metersphere
上一次同步 3 年多
通知
25
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
metersphere
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
66de947d
编写于
4月 16, 2020
作者:
S
shiziyuan9527
浏览文件
操作
浏览文件
下载
差异文件
Merge remote-tracking branch 'origin/dev' into dev
上级
1e4d780e
f59618ff
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
82 addition
and
311 deletion
+82
-311
Dockerfile
Dockerfile
+1
-2
backend/src/main/java/io/metersphere/controller/HelloController.java
.../main/java/io/metersphere/controller/HelloController.java
+21
-0
backend/src/main/java/io/metersphere/controller/LoginController.java
.../main/java/io/metersphere/controller/LoginController.java
+2
-2
backend/src/main/java/io/metersphere/i18n/Translator.java
backend/src/main/java/io/metersphere/i18n/Translator.java
+13
-260
backend/src/main/resources/application.properties
backend/src/main/resources/application.properties
+3
-1
backend/src/main/resources/i18n/en-US.json
backend/src/main/resources/i18n/en-US.json
+0
-23
backend/src/main/resources/i18n/messages.properties
backend/src/main/resources/i18n/messages.properties
+0
-0
backend/src/main/resources/i18n/messages_en_US.properties
backend/src/main/resources/i18n/messages_en_US.properties
+21
-0
backend/src/main/resources/i18n/messages_zh_CN.properties
backend/src/main/resources/i18n/messages_zh_CN.properties
+21
-0
backend/src/main/resources/i18n/zh-CN.json
backend/src/main/resources/i18n/zh-CN.json
+0
-23
未找到文件。
Dockerfile
浏览文件 @
66de947d
...
...
@@ -10,6 +10,5 @@ ENV JAVA_APP_JAR=/opt/apps/backend-1.0.jar
ENV
AB_OFF=true
ENV
JAVA_OPTIONS=-Dfile.encoding=utf-8
ENV
JAVA_OPTIONS="-Dfile.encoding=utf-8 -Djava.awt.headless=true"
CMD
["/deployments/run-java.sh"]
backend/src/main/java/io/metersphere/controller/HelloController.java
0 → 100644
浏览文件 @
66de947d
package
io.metersphere.controller
;
import
org.springframework.context.MessageSource
;
import
org.springframework.context.i18n.LocaleContextHolder
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.annotation.Resource
;
@RestController
@RequestMapping
(
"anonymous"
)
public
class
HelloController
{
@Resource
MessageSource
messageSource
;
@GetMapping
(
"hello"
)
public
String
hello
()
{
return
messageSource
.
getMessage
(
"max_thread_insufficient"
,
null
,
"默认值"
,
LocaleContextHolder
.
getLocale
());
}
}
backend/src/main/java/io/metersphere/controller/LoginController.java
浏览文件 @
66de947d
...
...
@@ -3,13 +3,13 @@ package io.metersphere.controller;
import
io.metersphere.base.domain.UserRole
;
import
io.metersphere.controller.request.LoginRequest
;
import
io.metersphere.dto.UserDTO
;
import
io.metersphere.i18n.Translator
;
import
io.metersphere.service.UserService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.shiro.SecurityUtils
;
import
org.apache.shiro.authc.*
;
import
org.apache.shiro.authz.UnauthorizedException
;
import
org.apache.shiro.subject.Subject
;
import
org.springframework.context.i18n.LocaleContextHolder
;
import
org.springframework.web.bind.annotation.*
;
import
javax.annotation.Resource
;
...
...
@@ -26,7 +26,7 @@ public class LoginController {
@GetMapping
(
value
=
"/isLogin"
)
public
ResultHolder
isLogin
()
{
if
(
SecurityUtils
.
getSubject
().
isAuthenticated
())
{
return
ResultHolder
.
success
(
Translator
.
getLangDes
());
return
ResultHolder
.
success
(
LocaleContextHolder
.
getLocale
());
}
return
ResultHolder
.
error
(
""
);
}
...
...
backend/src/main/java/io/metersphere/i18n/Translator.java
浏览文件 @
66de947d
package
io.metersphere.i18n
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.serializer.JavaBeanSerializer
;
import
com.alibaba.fastjson.serializer.ObjectSerializer
;
import
com.alibaba.fastjson.serializer.SerializeConfig
;
import
io.metersphere.commons.constants.I18nConstants
;
import
io.metersphere.commons.exception.MSException
;
import
io.metersphere.commons.utils.BeanUtils
;
import
io.metersphere.commons.utils.CommonBeanFactory
;
import
io.metersphere.commons.utils.LogUtil
;
import
io.metersphere.service.SystemParameterService
;
import
io.metersphere.user.SessionUtils
;
import
org.apache.commons.collections4.MapUtils
;
import
org.apache.commons.collections4.map.PassiveExpiringMap
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.commons.lang3.exception.ExceptionUtils
;
import
org.apache.commons.text.StringSubstitutor
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.web.context.request.RequestContextHolder
;
import
org.springframework.web.context.request.ServletRequestAttributes
;
import
org.springframework.context.MessageSource
;
import
org.springframework.context.i18n.LocaleContextHolder
;
import
org.springframework.stereotype.Component
;
import
javax.servlet.http.Cookie
;
import
javax.servlet.http.HttpServletRequest
;
import
java.lang.reflect.Array
;
import
java.util.*
;
import
java.util.concurrent.TimeUnit
;
import
javax.annotation.Resource
;
@Component
public
class
Translator
{
private
static
MessageSource
messageSource
;
public
static
final
String
PREFIX
=
"$[{"
;
public
static
final
String
SUFFIX
=
"}]"
;
private
static
final
String
JSON_SYMBOL
=
"\":"
;
private
static
final
HashSet
<
String
>
IGNORE_KEYS
=
new
HashSet
<>(
Arrays
.
asList
(
"id"
,
"password"
,
"passwd"
));
private
static
Map
<
String
,
String
>
langCache4Thread
=
Collections
.
synchronizedMap
(
new
PassiveExpiringMap
(
1
,
TimeUnit
.
MINUTES
));
public
static
String
getLangDes
()
{
return
getLang
().
getDesc
();
}
public
static
Lang
getLang
()
{
HttpServletRequest
request
=
getRequest
();
return
getLang
(
request
);
}
public
static
Object
gets
(
Object
keys
)
{
return
gets
(
getLang
(),
keys
);
}
public
static
Object
gets
(
Lang
lang
,
Object
keys
)
{
Map
<
String
,
String
>
context
=
I18nManager
.
getI18nMap
().
get
(
lang
.
getDesc
().
toLowerCase
());
return
translateObject
(
keys
,
context
);
}
// 单Key翻译
/**
* 单Key翻译
*/
public
static
String
get
(
String
key
)
{
return
get
(
getLang
(),
key
);
}
public
static
String
get
(
Lang
lang
,
String
key
)
{
if
(
StringUtils
.
isBlank
(
key
))
{
return
StringUtils
.
EMPTY
;
}
return
translateKey
(
key
,
I18nManager
.
getI18nMap
().
get
(
lang
.
getDesc
().
toLowerCase
()));
}
public
static
String
toI18nKey
(
String
key
)
{
return
String
.
format
(
"%s%s%s"
,
PREFIX
,
key
,
SUFFIX
);
}
private
static
HttpServletRequest
getRequest
()
{
try
{
return
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
}
catch
(
NullPointerException
npe
)
{
return
null
;
}
}
private
static
Lang
getLang
(
HttpServletRequest
request
)
{
String
preferLang
=
Lang
.
zh_CN
.
getDesc
();
try
{
if
(
request
!=
null
)
{
Object
sessionLang
=
request
.
getSession
(
true
).
getAttribute
(
I18nConstants
.
LANG_COOKIE_NAME
);
if
(
sessionLang
!=
null
&&
StringUtils
.
isNotBlank
(
sessionLang
.
toString
()))
{
return
Lang
.
getLang
(
sessionLang
.
toString
());
}
preferLang
=
getSystemParameterLanguage
(
preferLang
);
if
(
StringUtils
.
isNotBlank
(
request
.
getHeader
(
HttpHeaders
.
ACCEPT_LANGUAGE
)))
{
String
preferLangWithComma
=
StringUtils
.
substringBefore
(
request
.
getHeader
(
HttpHeaders
.
ACCEPT_LANGUAGE
),
";"
);
String
acceptLanguage
=
StringUtils
.
replace
(
StringUtils
.
substringBefore
(
preferLangWithComma
,
","
),
"-"
,
"_"
);
if
(
Lang
.
getLangWithoutDefault
(
acceptLanguage
)
!=
null
)
{
preferLang
=
acceptLanguage
;
}
}
if
(
request
.
getCookies
()
!=
null
&&
request
.
getCookies
().
length
>
0
)
{
for
(
Cookie
cookie
:
request
.
getCookies
())
{
if
(
StringUtils
.
equalsIgnoreCase
(
cookie
.
getName
(),
I18nConstants
.
LANG_COOKIE_NAME
))
{
preferLang
=
cookie
.
getValue
();
}
}
}
if
(
SessionUtils
.
getUser
()
!=
null
&&
StringUtils
.
isNotBlank
(
SessionUtils
.
getUser
().
getLanguage
()))
{
preferLang
=
SessionUtils
.
getUser
().
getLanguage
();
}
request
.
getSession
(
true
).
setAttribute
(
I18nConstants
.
LANG_COOKIE_NAME
,
preferLang
);
}
else
{
preferLang
=
getSystemParameterLanguage
(
preferLang
);
}
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
"Fail to getLang."
,
e
);
}
return
Lang
.
getLang
(
preferLang
);
}
private
static
String
getSystemParameterLanguage
(
String
defaultLang
)
{
String
result
=
defaultLang
;
try
{
String
cachedLang
=
langCache4Thread
.
get
(
I18nConstants
.
LANG_COOKIE_NAME
);
if
(
StringUtils
.
isNotBlank
(
cachedLang
))
{
return
cachedLang
;
}
String
systemLanguage
=
Objects
.
requireNonNull
(
CommonBeanFactory
.
getBean
(
SystemParameterService
.
class
)).
getSystemLanguage
();
if
(
StringUtils
.
isNotBlank
(
systemLanguage
))
{
result
=
systemLanguage
;
}
langCache4Thread
.
put
(
I18nConstants
.
LANG_COOKIE_NAME
,
result
);
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
e
);
}
return
result
;
}
private
static
Object
translateObject
(
Object
javaObject
,
final
Map
<
String
,
String
>
context
)
{
if
(
MapUtils
.
isEmpty
(
context
))
{
return
javaObject
;
}
if
(
javaObject
==
null
)
{
return
null
;
}
try
{
if
(
javaObject
instanceof
String
)
{
String
rawString
=
javaObject
.
toString
();
if
(
StringUtils
.
contains
(
rawString
,
JSON_SYMBOL
))
{
try
{
Object
jsonObject
=
JSON
.
parse
(
rawString
);
Object
a
=
translateObject
(
jsonObject
,
context
);
return
JSON
.
toJSONString
(
a
);
}
catch
(
Exception
e
)
{
LogUtil
.
warn
(
"Failed to translate object "
+
rawString
+
". Error: "
+
ExceptionUtils
.
getStackTrace
(
e
));
return
translateRawString
(
null
,
rawString
,
context
);
}
}
else
{
return
translateRawString
(
null
,
rawString
,
context
);
}
}
if
(
javaObject
instanceof
Map
)
{
Map
<
Object
,
Object
>
map
=
(
Map
<
Object
,
Object
>)
javaObject
;
for
(
Map
.
Entry
<
Object
,
Object
>
entry
:
map
.
entrySet
())
{
if
(
entry
.
getValue
()
!=
null
)
{
if
(
entry
.
getValue
()
instanceof
String
)
{
if
(
StringUtils
.
contains
(
entry
.
getValue
().
toString
(),
JSON_SYMBOL
))
{
map
.
put
(
entry
.
getKey
(),
translateObject
(
entry
.
getValue
(),
context
));
}
else
{
map
.
put
(
entry
.
getKey
(),
translateRawString
(
entry
.
getKey
().
toString
(),
entry
.
getValue
().
toString
(),
context
));
}
}
else
{
translateObject
(
entry
.
getValue
(),
context
);
}
}
}
}
if
(
javaObject
instanceof
Collection
)
{
Collection
<
Object
>
collection
=
(
Collection
<
Object
>)
javaObject
;
for
(
Object
item
:
collection
)
{
translateObject
(
item
,
context
);
}
}
if
(
javaObject
.
getClass
().
isArray
())
{
for
(
int
i
=
0
;
i
<
Array
.
getLength
(
javaObject
);
++
i
)
{
Object
item
=
Array
.
get
(
javaObject
,
i
);
Array
.
set
(
javaObject
,
i
,
translateObject
(
item
,
context
));
}
}
ObjectSerializer
serializer
=
SerializeConfig
.
globalInstance
.
getObjectWriter
(
javaObject
.
getClass
());
if
(
serializer
instanceof
JavaBeanSerializer
)
{
JavaBeanSerializer
javaBeanSerializer
=
(
JavaBeanSerializer
)
serializer
;
try
{
Map
<
String
,
Object
>
values
=
javaBeanSerializer
.
getFieldValuesMap
(
javaObject
);
for
(
Map
.
Entry
<
String
,
Object
>
entry
:
values
.
entrySet
())
{
if
(
entry
.
getValue
()
!=
null
)
{
if
(
entry
.
getValue
()
instanceof
String
)
{
if
(
StringUtils
.
contains
(
entry
.
getValue
().
toString
(),
JSON_SYMBOL
))
{
BeanUtils
.
setFieldValueByName
(
javaObject
,
entry
.
getKey
(),
translateObject
(
entry
.
getValue
(),
context
),
String
.
class
);
}
else
{
BeanUtils
.
setFieldValueByName
(
javaObject
,
entry
.
getKey
(),
translateRawString
(
entry
.
getKey
(),
entry
.
getValue
().
toString
(),
context
),
String
.
class
);
}
}
else
{
translateObject
(
entry
.
getValue
(),
context
);
}
}
}
}
catch
(
Exception
e
)
{
MSException
.
throwException
(
e
);
}
}
return
javaObject
;
}
catch
(
StackOverflowError
stackOverflowError
)
{
try
{
return
JSON
.
parseObject
(
translateRawString
(
null
,
JSON
.
toJSONString
(
javaObject
),
context
).
toString
(),
javaObject
.
getClass
());
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
"Failed to translate object "
+
javaObject
.
toString
(),
e
);
return
javaObject
;
}
}
}
private
static
Object
translateRawString
(
String
key
,
String
rawString
,
Map
<
String
,
String
>
context
)
{
if
(
StringUtils
.
isBlank
(
rawString
))
{
return
rawString
;
}
for
(
String
ignoreKey
:
IGNORE_KEYS
)
{
if
(
StringUtils
.
containsIgnoreCase
(
key
,
ignoreKey
))
{
return
rawString
;
}
}
if
(
StringUtils
.
contains
(
rawString
,
PREFIX
))
{
rawString
=
new
StringSubstitutor
(
context
,
PREFIX
,
SUFFIX
).
replace
(
rawString
);
if
(
StringUtils
.
contains
(
rawString
,
PREFIX
))
{
String
[]
unTrans
=
StringUtils
.
substringsBetween
(
rawString
,
PREFIX
,
SUFFIX
);
if
(
unTrans
!=
null
)
{
for
(
String
unTran
:
unTrans
)
{
rawString
=
StringUtils
.
replace
(
rawString
,
PREFIX
+
unTran
+
SUFFIX
,
unTran
);
}
}
}
}
if
(
key
!=
null
)
{
String
desc
=
context
.
get
(
rawString
);
if
(
StringUtils
.
isNotBlank
(
desc
))
{
return
desc
;
}
}
return
rawString
;
return
messageSource
.
getMessage
(
key
,
null
,
"Not Support Key"
,
LocaleContextHolder
.
getLocale
());
}
private
static
String
translateKey
(
String
key
,
Map
<
String
,
String
>
context
)
{
if
(
MapUtils
.
isEmpty
(
context
))
{
return
key
;
}
String
desc
=
context
.
get
(
StringUtils
.
replace
(
StringUtils
.
replace
(
key
,
PREFIX
,
StringUtils
.
EMPTY
),
SUFFIX
,
StringUtils
.
EMPTY
));
if
(
StringUtils
.
isNotBlank
(
desc
))
{
return
desc
;
}
return
key
;
@Resource
public
void
setMessageSource
(
MessageSource
messageSource
)
{
Translator
.
messageSource
=
messageSource
;
}
}
backend/src/main/resources/application.properties
浏览文件 @
66de947d
...
...
@@ -34,4 +34,6 @@ spring.flyway.locations=classpath:db/migration
spring.flyway.table
=
metersphere_version
spring.flyway.baseline-version
=
0
spring.flyway.encoding
=
UTF-8
spring.flyway.validate-on-migrate
=
false
\ No newline at end of file
spring.flyway.validate-on-migrate
=
false
spring.messages.basename
=
i18n/messages
\ No newline at end of file
backend/src/main/resources/i18n/en-US.json
已删除
100644 → 0
浏览文件 @
1e4d780e
{
"error_lang_invalid"
:
"Invalid language parameter"
,
"load_test_already_exists"
:
"Duplicate load test name"
,
"project_name_is_null"
:
"Project name cannot be null"
,
"project_name_already_exists"
:
"The project name already exists"
,
"workspace_name_is_null"
:
"Workspace name cannot be null"
,
"workspace_name_already_exists"
:
"The workspace name already exists"
,
"workspace_does_not_belong_to_user"
:
"The current workspace does not belong to the current user"
,
"organization_does_not_belong_to_user"
:
"The current organization does not belong to the current user"
,
"file_cannot_be_null"
:
"File cannot be empty!"
,
"edit_load_test_not_found"
:
"Cannot edit test, test not found:"
,
"run_load_test_not_found"
:
"Cannot run test, test not found:"
,
"run_load_test_file_not_found"
:
"Unable to run test, unable to get test file meta information, test ID:"
,
"run_load_test_file_content_not_found"
:
"Cannot run test, cannot get test file content, test ID:"
,
"run_load_test_file_init_error"
:
"Failed to run test, failed to initialize run environment, test ID:"
,
"load_test_is_running"
:
"Load test is running, please wait."
,
"node_deep_limit"
:
"The node depth does not exceed 5 layers!"
,
"no_nodes_message"
:
"No node message"
,
"duplicate_node_ip"
:
"Duplicate IPs"
,
"only_one_k8s"
:
"Only one K8s can be added"
,
"organization_id_is_null"
:
"Organization ID cannot be null"
,
"max_thread_insufficient"
:
"The number of concurrent users exceeds"
}
\ No newline at end of file
backend/src/main/resources/i18n/messages.properties
0 → 100644
浏览文件 @
66de947d
backend/src/main/resources/i18n/messages_en_US.properties
0 → 100644
浏览文件 @
66de947d
error_lang_invalid
=
Invalid language parameter
load_test_already_exists
=
Duplicate load test name
project_name_is_null
=
Project name cannot be null
project_name_already_exists
=
The project name already exists
workspace_name_is_null
=
Workspace name cannot be null
workspace_name_already_exists
=
The workspace name already exists
workspace_does_not_belong_to_user
=
The current workspace does not belong to the current user
organization_does_not_belong_to_user
=
The current organization does not belong to the current user
file_cannot_be_null
=
File cannot be empty!
edit_load_test_not_found
=
Cannot edit test, test not found=
run_load_test_not_found
=
Cannot run test, test not found=
run_load_test_file_not_found
=
Unable to run test, unable to get test file meta information, test ID=
run_load_test_file_content_not_found
=
Cannot run test, cannot get test file content, test ID=
run_load_test_file_init_error
=
Failed to run test, failed to initialize run environment, test ID=
load_test_is_running
=
Load test is running, please wait.
node_deep_limit
=
The node depth does not exceed 5 layers!
no_nodes_message
=
No node message
duplicate_node_ip
=
Duplicate IPs
only_one_k8s
=
Only one K8s can be added
organization_id_is_null
=
Organization ID cannot be null
max_thread_insufficient
=
The number of concurrent users exceeds
backend/src/main/resources/i18n/messages_zh_CN.properties
0 → 100644
浏览文件 @
66de947d
error_lang_invalid
=
语言参数错误
load_test_already_exists
=
测试名称不能重复
project_name_is_null
=
项目名称不能为空
project_name_already_exists
=
项目名称已存在
workspace_name_is_null
=
工作空间名不能为空
workspace_name_already_exists
=
工作空间名已存在
workspace_does_not_belong_to_user
=
当前工作空间不属于当前用户
organization_does_not_belong_to_user
=
当前组织不属于当前用户
file_cannot_be_null
=
文件不能为空!
edit_load_test_not_found
=
无法编辑测试,未找到测试:
run_load_test_not_found
=
无法运行测试,未找到测试:
run_load_test_file_not_found
=
无法运行测试,无法获取测试文件元信息,测试ID:
run_load_test_file_content_not_found
=
无法运行测试,无法获取测试文件内容,测试ID:
run_load_test_file_init_error
=
无法运行测试,初始化运行环境失败,测试ID:
load_test_is_running
=
测试正在运行, 请等待
node_deep_limit
=
节点深度不超过5层!
no_nodes_message
=
没有节点信息
duplicate_node_ip
=
节点 IP 重复
only_one_k8s
=
只能添加一个 K8s
organization_id_is_null
=
组织 ID 不能为空
max_thread_insufficient
=
并发用户数超额
backend/src/main/resources/i18n/zh-CN.json
已删除
100644 → 0
浏览文件 @
1e4d780e
{
"error_lang_invalid"
:
"语言参数错误"
,
"load_test_already_exists"
:
"测试名称不能重复"
,
"project_name_is_null"
:
"项目名称不能为空"
,
"project_name_already_exists"
:
"项目名称已存在"
,
"workspace_name_is_null"
:
"工作空间名不能为空"
,
"workspace_name_already_exists"
:
"工作空间名已存在"
,
"workspace_does_not_belong_to_user"
:
"当前工作空间不属于当前用户"
,
"organization_does_not_belong_to_user"
:
"当前组织不属于当前用户"
,
"file_cannot_be_null"
:
"文件不能为空!"
,
"edit_load_test_not_found"
:
"无法编辑测试,未找到测试:"
,
"run_load_test_not_found"
:
"无法运行测试,未找到测试:"
,
"run_load_test_file_not_found"
:
"无法运行测试,无法获取测试文件元信息,测试ID:"
,
"run_load_test_file_content_not_found"
:
"无法运行测试,无法获取测试文件内容,测试ID:"
,
"run_load_test_file_init_error"
:
"无法运行测试,初始化运行环境失败,测试ID:"
,
"load_test_is_running"
:
"测试正在运行, 请等待"
,
"node_deep_limit"
:
"节点深度不超过5层!"
,
"no_nodes_message"
:
"没有节点信息"
,
"duplicate_node_ip"
:
"节点 IP 重复"
,
"only_one_k8s"
:
"只能添加一个 K8s"
,
"organization_id_is_null"
:
"组织 ID 不能为空"
,
"max_thread_insufficient"
:
"并发用户数超额"
}
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录