diff --git a/backend/src/main/java/io/dataease/auth/api/DynamicMenuApi.java b/backend/src/main/java/io/dataease/auth/api/DynamicMenuApi.java index cc127f46d5..d25e0b8657 100644 --- a/backend/src/main/java/io/dataease/auth/api/DynamicMenuApi.java +++ b/backend/src/main/java/io/dataease/auth/api/DynamicMenuApi.java @@ -2,6 +2,7 @@ package io.dataease.auth.api; import io.dataease.auth.api.dto.DynamicMenuDto; +import io.dataease.controller.handler.annotation.I18n; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -16,6 +17,7 @@ public interface DynamicMenuApi { * @return */ @PostMapping("/menus") + @I18n List menus(); } diff --git a/backend/src/main/java/io/dataease/commons/constants/I18nConstants.java b/backend/src/main/java/io/dataease/commons/constants/I18nConstants.java index 97e192e590..71abfb6ea0 100644 --- a/backend/src/main/java/io/dataease/commons/constants/I18nConstants.java +++ b/backend/src/main/java/io/dataease/commons/constants/I18nConstants.java @@ -2,5 +2,5 @@ package io.dataease.commons.constants; public class I18nConstants { - public static final String LANG_COOKIE_NAME = "MS_USER_LANG"; + public static final String LANG_COOKIE_NAME = "DE_USER_LANG"; } diff --git a/backend/src/main/java/io/dataease/controller/I18nController.java b/backend/src/main/java/io/dataease/controller/I18nController.java index 9531317d0d..d6e37eab59 100644 --- a/backend/src/main/java/io/dataease/controller/I18nController.java +++ b/backend/src/main/java/io/dataease/controller/I18nController.java @@ -27,8 +27,6 @@ public class I18nController { @Value("${run.mode:release}") private String runMode; -// @Resource -// private UserService userService; @GetMapping("lang/change/{lang}") public void changeLang(@PathVariable String lang, HttpServletRequest request, HttpServletResponse response) { @@ -38,14 +36,13 @@ public class I18nController { LogUtil.error("Invalid parameter: " + lang); DEException.throwException(Translator.get("error_lang_invalid")); } -// userService.setLanguage(targetLang.getDesc()); Cookie cookie = new Cookie(I18nConstants.LANG_COOKIE_NAME, targetLang.getDesc()); cookie.setPath("/"); cookie.setMaxAge(FOR_EVER); response.addCookie(cookie); //重新登录 if ("release".equals(runMode)) { - Cookie f2cCookie = new Cookie("MS_SESSION_ID", "deleteMe"); + Cookie f2cCookie = new Cookie("DE_SESSION_ID", "deleteMe"); f2cCookie.setPath("/"); f2cCookie.setMaxAge(0); response.addCookie(f2cCookie); diff --git a/backend/src/main/java/io/dataease/controller/handler/ResultResponseBodyAdvice.java b/backend/src/main/java/io/dataease/controller/handler/ResultResponseBodyAdvice.java index 1796adb525..23e2166843 100644 --- a/backend/src/main/java/io/dataease/controller/handler/ResultResponseBodyAdvice.java +++ b/backend/src/main/java/io/dataease/controller/handler/ResultResponseBodyAdvice.java @@ -1,8 +1,17 @@ package io.dataease.controller.handler; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.serializer.JavaBeanSerializer; +import com.alibaba.fastjson.serializer.ObjectSerializer; +import com.alibaba.fastjson.serializer.SerializeConfig; import com.google.gson.Gson; +import io.dataease.commons.constants.I18nConstants; import io.dataease.controller.ResultHolder; +import io.dataease.controller.handler.annotation.I18n; import io.dataease.controller.handler.annotation.NoResultHolder; +import io.dataease.i18n.Translator; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; @@ -13,6 +22,10 @@ import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; +import java.lang.reflect.Array; +import java.util.Collection; +import java.util.Map; + /** * 统一处理返回结果集 */ @@ -35,6 +48,12 @@ public class ResultResponseBodyAdvice implements ResponseBodyAdvice { return o; } + //if true, need to translate + if (methodParameter.hasMethodAnnotation(I18n.class)) { + I18n i18n = methodParameter.getMethodAnnotation(I18n.class); + o = translate(o, i18n.value()); + } + if (!(o instanceof ResultHolder)) { if (o instanceof String) { return new Gson().toJson(ResultHolder.success(o)); @@ -44,4 +63,11 @@ public class ResultResponseBodyAdvice implements ResponseBodyAdvice { return o; } + + // i18n + private Object translate(Object obj, String type) { + return Translator.translateObject(obj); + } + + } diff --git a/backend/src/main/java/io/dataease/i18n/Translator.java b/backend/src/main/java/io/dataease/i18n/Translator.java index 6174323c6a..d725b44b29 100644 --- a/backend/src/main/java/io/dataease/i18n/Translator.java +++ b/backend/src/main/java/io/dataease/i18n/Translator.java @@ -1,12 +1,31 @@ package io.dataease.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.dataease.commons.utils.BeanUtils; +import io.dataease.commons.utils.LogUtil; +import io.dataease.exception.DataEaseException; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.text.StringSubstitutor; import org.springframework.context.MessageSource; import org.springframework.context.i18n.LocaleContextHolder; import javax.annotation.Resource; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; public class Translator { private static MessageSource messageSource; + private static final String JSON_SYMBOL = "\":"; + private static final HashSet IGNORE_KEYS = new HashSet<>(Arrays.asList("id", "password", "passwd")); + @Resource public void setMessageSource(MessageSource messageSource) { @@ -17,6 +36,117 @@ public class Translator { * 单Key翻译 */ public static String get(String key) { - return messageSource.getMessage(key, null, "Not Support Key: " + key, LocaleContextHolder.getLocale()); + System.out.println(LocaleContextHolder.getLocale()); + return messageSource.getMessage(key, null, key, LocaleContextHolder.getLocale()); } + + private static Object translateRawString(String key, String rawString) { + if (StringUtils.isBlank(rawString)) { + return rawString; + } + for (String ignoreKey : IGNORE_KEYS) { + if (StringUtils.containsIgnoreCase(key, ignoreKey)) { + return rawString; + } + } + + if (key != null) { + String desc = get(rawString); + if (StringUtils.isNotBlank(desc)) { + return desc; + } + } + return rawString; + } + + public static Object translateObject(Object 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); + return JSON.toJSONString(a); + } catch (Exception e) { + LogUtil.error("Failed to translate object: " + rawString, e); + e.printStackTrace(); + LogUtil.warn("Failed to translate object " + rawString + ". Error: " + ExceptionUtils.getStackTrace(e)); + return translateRawString(null, rawString); + } + + } else { + return translateRawString(null, rawString); + } + } + 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())); + } else { + map.put(entry.getKey(), translateRawString(entry.getKey().toString(), entry.getValue().toString())); + } + } else { + translateObject(entry.getValue()); + } + } + } + + } + + if (javaObject instanceof Collection) { + Collection collection = (Collection) javaObject; + for (Object item : collection) { + translateObject(item); + } + } + + 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)); + } + } + + 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()), String.class); + } else { + BeanUtils.setFieldValueByName(javaObject, entry.getKey(), translateRawString(entry.getKey(), entry.getValue().toString()), String.class); + } + } else { + translateObject(entry.getValue()); + } + } + } + } catch (Exception e) { + DataEaseException.throwException(e); + } + } + + return javaObject; + } catch (StackOverflowError stackOverflowError) { + try { + return JSON.parseObject(translateRawString(null, JSON.toJSONString(javaObject)).toString(), javaObject.getClass()); + } catch (Exception e) { + LogUtil.error("Failed to translate object " + javaObject.toString(), e); + return javaObject; + } + } + } + } diff --git a/backend/src/main/resources/i18n/messages_en_US.properties b/backend/src/main/resources/i18n/messages_en_US.properties index 3ac43e7a11..fe69987173 100644 --- a/backend/src/main/resources/i18n/messages_en_US.properties +++ b/backend/src/main/resources/i18n/messages_en_US.properties @@ -185,3 +185,39 @@ authsource_name_already_exists=Authentication source name already exists authsource_name_is_null=Authentication source name cannot be empty authsource_configuration_is_null=Authentication source configuration cannot be empty +个人信息=Personal Information +仪表盘=Panel +修改密码=Change Password +创建用户=Create User +创建组织=Create Organization +创建菜单=Create Menu +创建角色=Create Role +创建连接=Create Connection +删除用户=Delete User +删除组织=Delete Organization +删除菜单=Delete Menu +删除角色=Delete Role +删除连接=Delete Connection +参数管理=Parameter Management +数据源=Data Source +数据源表单=Data source form +数据集=Data Set +权限管理=Authority Management +校验连接=Verify Connection +模板管理=Template Management +用户管理=User Management +用户表单=User Form +系统管理=System management +组织管理=Organization management +组织表单=Organization Form +编辑用户=Edit User +编辑组织=Edit Organization +编辑菜单=Edit Menu +编辑角色=Edit Role +编辑连接=Edit Connection +菜单管理=Menu management +菜单表单=Menu Form +视图=View +角色管理=Role management +角色表单=Role Form +重置密码=Reset Password \ No newline at end of file diff --git a/backend/src/main/resources/i18n/messages_zh_CN.properties b/backend/src/main/resources/i18n/messages_zh_CN.properties index 87c7dd1353..9aa1574245 100644 --- a/backend/src/main/resources/i18n/messages_zh_CN.properties +++ b/backend/src/main/resources/i18n/messages_zh_CN.properties @@ -185,3 +185,40 @@ automation_exec_info=没有测试步骤,无法执行 authsource_name_already_exists=认证源名称已经存在 authsource_name_is_null=认证源名称不能为空 authsource_configuration_is_null=认证源配置不能为空 + +个人信息=个人信息 +仪表盘=仪表盘 +修改密码=修改密码 +创建用户=创建用户 +创建组织=创建组织 +创建菜单=创建菜单 +创建角色=创建角色 +创建连接=创建连接 +删除用户=删除用户 +删除组织=删除组织 +删除菜单=删除菜单 +删除角色=删除角色 +删除连接=删除连接 +参数管理=参数管理 +数据源=数据源 +数据源表单=数据源表单 +数据集=数据集 +权限管理=权限管理 +校验连接=校验连接 +模板管理=模板管理 +用户管理=用户管理 +用户表单=用户表单 +系统管理=系统管理 +组织管理=组织管理 +组织表单=组织表单 +编辑用户=编辑用户 +编辑组织=编辑组织 +编辑菜单=编辑菜单 +编辑角色=编辑角色 +编辑连接=编辑连接 +菜单管理=菜单管理 +菜单表单=菜单表单 +视图=视图 +角色管理=角色管理 +角色表单=角色表单 +重置密码=重置密码 diff --git a/backend/src/main/resources/i18n/messages_zh_TW.properties b/backend/src/main/resources/i18n/messages_zh_TW.properties index 4e9f9ffff4..8f3f6025f8 100644 --- a/backend/src/main/resources/i18n/messages_zh_TW.properties +++ b/backend/src/main/resources/i18n/messages_zh_TW.properties @@ -185,4 +185,40 @@ automation_exec_info=沒有測試步驟,無法執行 #authsource authsource_name_already_exists=認證源名稱已經存在 authsource_name_is_null=認證源名稱不能為空 -authsource_configuration_is_null=認證源配置不能為空 \ No newline at end of file +authsource_configuration_is_null=認證源配置不能為空 +个人信息=個人信息 +仪表盘=儀表盤 +修改密码=修改密碼 +创建用户=創建用戶 +创建组织=創建組織 +创建菜单=創建菜單 +创建角色=創建角色 +创建连接=創建鏈接 +删除用户=刪除用戶 +删除组织=刪除組織 +删除菜单=刪除菜單 +删除角色=刪除角色 +删除连接=删除鏈接 +参数管理=參數管理 +数据源=數據源 +数据源表单=數據源表單 +数据集=數據集 +权限管理=權限管理 +校验连接=校驗鏈接 +模板管理=模板管理 +用户管理=用戶管理 +用户表单=用戶表單 +系统管理=系統管理 +组织管理=組織管理 +组织表单=組織表單 +编辑用户=編輯用戶 +编辑组织=編輯組織 +编辑菜单=編輯菜單 +编辑角色=編輯角色 +编辑连接=編輯鏈接 +菜单管理=菜單管理 +菜单表单=表單管理 +视图=視圖 +角色管理=角色管理 +角色表单=角色表單 +重置密码=重置密碼 diff --git a/frontend/src/views/panel/list/PanelViewShow.vue b/frontend/src/views/panel/list/PanelViewShow.vue index 0659b34be9..cb51f0a28e 100644 --- a/frontend/src/views/panel/list/PanelViewShow.vue +++ b/frontend/src/views/panel/list/PanelViewShow.vue @@ -41,7 +41,7 @@ - {{ $t('panle.select_panel_from_left') }} + {{ $t('panel.select_panel_from_left') }}