From 6feefcc23ee832a965e9694edf66277ad6903aeb Mon Sep 17 00:00:00 2001 From: "Captain.B" Date: Thu, 16 Apr 2020 19:16:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BD=BF=E7=94=A8=20spring=20boot=20=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/HelloController.java | 21 ++ .../controller/LoginController.java | 4 +- .../java/io/metersphere/i18n/Translator.java | 273 +----------------- .../src/main/resources/application.properties | 4 +- backend/src/main/resources/i18n/en-US.json | 23 -- .../main/resources/i18n/messages.properties | 0 .../resources/i18n/messages_en_US.properties | 21 ++ .../resources/i18n/messages_zh_CN.properties | 21 ++ backend/src/main/resources/i18n/zh-CN.json | 23 -- 9 files changed, 81 insertions(+), 309 deletions(-) create mode 100644 backend/src/main/java/io/metersphere/controller/HelloController.java delete mode 100644 backend/src/main/resources/i18n/en-US.json create mode 100644 backend/src/main/resources/i18n/messages.properties create mode 100644 backend/src/main/resources/i18n/messages_en_US.properties create mode 100644 backend/src/main/resources/i18n/messages_zh_CN.properties delete mode 100644 backend/src/main/resources/i18n/zh-CN.json diff --git a/backend/src/main/java/io/metersphere/controller/HelloController.java b/backend/src/main/java/io/metersphere/controller/HelloController.java new file mode 100644 index 0000000000..2263748feb --- /dev/null +++ b/backend/src/main/java/io/metersphere/controller/HelloController.java @@ -0,0 +1,21 @@ +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()); + } +} diff --git a/backend/src/main/java/io/metersphere/controller/LoginController.java b/backend/src/main/java/io/metersphere/controller/LoginController.java index 1b11a4abb5..62b3e8656e 100644 --- a/backend/src/main/java/io/metersphere/controller/LoginController.java +++ b/backend/src/main/java/io/metersphere/controller/LoginController.java @@ -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(""); } diff --git a/backend/src/main/java/io/metersphere/i18n/Translator.java b/backend/src/main/java/io/metersphere/i18n/Translator.java index c8556e1fd8..ace569512a 100644 --- a/backend/src/main/java/io/metersphere/i18n/Translator.java +++ b/backend/src/main/java/io/metersphere/i18n/Translator.java @@ -1,271 +1,24 @@ 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 IGNORE_KEYS = new HashSet<>(Arrays.asList("id", "password", "passwd")); - - private static Map 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 context = I18nManager.getI18nMap().get(lang.getDesc().toLowerCase()); - return translateObject(keys, context); - } - - // 单Key翻译 + /** + * 单Key翻译 + */ public static String get(String key) { - return get(getLang(), key); + return messageSource.getMessage(key, null, "Not Support Key", LocaleContextHolder.getLocale()); } - 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 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 map = (Map) javaObject; - - for (Map.Entry 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 collection = (Collection) 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 values = javaBeanSerializer.getFieldValuesMap(javaObject); - for (Map.Entry 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 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; - } - - private static String translateKey(String key, Map 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; } } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 9310563392..728e362036 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -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 diff --git a/backend/src/main/resources/i18n/en-US.json b/backend/src/main/resources/i18n/en-US.json deleted file mode 100644 index c5329f867f..0000000000 --- a/backend/src/main/resources/i18n/en-US.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "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 diff --git a/backend/src/main/resources/i18n/messages.properties b/backend/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000000..e69de29bb2 diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000000..634a2c073f --- /dev/null +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,21 @@ +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 diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000000..66e36e7c6a --- /dev/null +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,21 @@ +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=并发用户数超额 diff --git a/backend/src/main/resources/i18n/zh-CN.json b/backend/src/main/resources/i18n/zh-CN.json deleted file mode 100644 index 0884b07c0f..0000000000 --- a/backend/src/main/resources/i18n/zh-CN.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "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