spring-boot国际化i18n中英文实现

news2024/10/9 16:31:39

一、背景

接触到的项目,使用国际化越来越多,系统页面实现中英文环境,记录下,前端使用vue + vue-i8n

后端java自己封装

前端翻译对象:页面涉及到的所有按钮(包括新增、删除、导出、下载、导入、上一页、下一页等)、文本所有弹框提示(包括请输入内容、您确定要删除吗?、新增修改列名、列表头名、提交、取消、必填项不能为空等)总结为:所有页面定义的中文内容 切换为英文环境时 页面需切换英文。

后端翻译对象:因菜单采用动态菜单,故菜单翻译放到后端,字典数据,接口返回提示信息(操作成果、操作失败、原因)

此处前端自行百度,只记录后端部分

spring-boot  maven  此处只贴关键性代码  项目其他封装 代码 未粘贴

配置类



package com.cloud.framework.i18n;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

@ConditionalOnProperty(name = {"spring.messages.basename"})
@EnableConfigurationProperties({TranslatorProperties.class})
@Configuration
public class InternationalConfiguration extends AcceptHeaderLocaleResolver implements WebMvcConfigurer {
    @Autowired
    private TranslatorProperties translatorProperties;

    public InternationalConfiguration() {
    }

    @Bean
    public ResourceBundleMessageSource messageSource() {
        ResourceBundleMessageSource rs = new ResourceBundleMessageSource();
        rs.setDefaultEncoding(this.translatorProperties.getEncoding());
        rs.setBasenames(new String[]{this.translatorProperties.getBasename()});
        rs.setUseCodeAsDefaultMessage(true);
        rs.setCacheSeconds(this.translatorProperties.getCacheSeconds());
        return rs;
    }

    @Bean
    public Translator myTranslator(ResourceBundleMessageSource messageSource) {
        Translator result = new Translator(messageSource);
        result.setDefaultLang(this.translatorProperties.getDefaultLang());
        return result;
    }
}

 


package com.cloud.framework.i18n;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "spring.messages")
public class TranslatorProperties {
    private String encoding;
    private String basename;
    private int cacheSeconds;
    private boolean isClientLang;
    private String defaultLang;
    public TranslatorProperties() {
    }
    public String getEncoding() {
        return this.encoding;
    }

    public String getBasename() {
        return this.basename;
    }

    public int getCacheSeconds() {
        return this.cacheSeconds;
    }

    public boolean isClientLang() {
        return this.isClientLang;
    }

    public String getDefaultLang() {
        return this.defaultLang;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public void setBasename(String basename) {
        this.basename = basename;
    }

    public void setCacheSeconds(int cacheSeconds) {
        this.cacheSeconds = cacheSeconds;
    }

    public void setClientLang(boolean isClientLang) {
        this.isClientLang = isClientLang;
    }

    public void setDefaultLang(String defaultLang) {
        this.defaultLang = defaultLang;
    }


    protected boolean canEqual(Object other) {
        return other instanceof TranslatorProperties;
    }

    public TranslatorProperties(String encoding, String basename, int cacheSeconds, boolean isClientLang, String defaultLang) {
        this.encoding = encoding;
        this.basename = basename;
        this.cacheSeconds = cacheSeconds;
        this.isClientLang = isClientLang;
        this.defaultLang = defaultLang;
    }


}

翻译工具类


package com.cloud.framework.i18n;

import com.alibaba.fastjson.JSONObject;
import com.cloud.framework.cache.RedisUtils;
import com.cloud.framework.util.CodeStyleConvert;
import com.cloud.framework.web.SysContext;
import com.google.common.base.Preconditions;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.util.CollectionUtils;

public class Translator {
    private static final Logger log = LoggerFactory.getLogger(Translator.class);
    private static final String TIP = "mutli--lang--%s--%s";
    @Autowired
    private SysContext context;
    @Autowired
    private RedisUtils redisUtils;
    private ResourceBundleMessageSource messageSource;
    private String defaultLang;

    @Autowired
    Translator(ResourceBundleMessageSource messageSource) {
        this.messageSource = messageSource;
    }

    public String dataToLocale(String field, String msg) {
        String lang = this.initDefaultLang();
        String[] l = lang.split("_");
        Preconditions.checkArgument(l.length == 2, "error lang");
        String codeStyle = field.indexOf("i18n_") < 0 ? CodeStyleConvert.underscoreName(field) : field;
        log.info(String.format("mutli--lang--%s--%s", "CodeStyle", codeStyle));
        List<Object> items = this.redisUtils.lRange(String.format("language:%s", codeStyle), 0L, -1L);
        if (CollectionUtils.isEmpty(items)) {
            return msg;
        } else {
            Iterator var8 = items.iterator();

            JSONObject joItem;
            do {
                if (!var8.hasNext()) {
                    return msg;
                }

                Object item = var8.next();
                log.info(String.format("mutli--lang--%s--%s", "RedisItem", item.toString()));
                joItem = (JSONObject)item;
            } while(!joItem.containsKey("typeKey") || !joItem.get("typeKey").equals(msg + "_" + l[0]));

            return joItem.get("value").toString();
        }
    }

    private String initDefaultLang() {
        String lang = this.context.getLang();
        if (StringUtils.isEmpty(lang) && !StringUtils.isEmpty(this.defaultLang)) {
            lang = this.defaultLang;
        }

        return lang;
    }

    public String sysToLocale(String msg) {
        String lang = this.initDefaultLang();
        String[] l = lang.split("_");
        Preconditions.checkArgument(l.length == 2, "error lang");
        Locale locale = new Locale(l[0], l[1]);
        return this.messageSource.getMessage(msg, new Object[0], locale);
    }

    public String sysToLocale(String lang, String msg) {
        String[] l = lang.split("_");
        Preconditions.checkArgument(l.length == 2, "error lang");
        Locale locale = new Locale(l[0], l[1]);
        return this.messageSource.getMessage(msg, new Object[0], locale);
    }

    public String getDefaultLang() {
        return this.defaultLang;
    }

    public void setDefaultLang(String defaultLang) {
        this.defaultLang = defaultLang;
    }
}

META-INF 加载配置类

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cloud.framework.datasource.hbase.HBaseConfiguration

spring-boot配置文件 国际化默认语言配置  前端不传取默认  登录后语言记录符存redis 每次从redis取   切换语言时  修改redis存值

#国际化配置  defaultLang 默认语言  zh_CN 中文  en_US英文
messages:
   basename: i18n/messages
   encoding: UTF-8
   cacheSeconds: 0
   isClientLang: false
   defaultLang: zh_CN

配置资源文件

资源文件就是 key-value 对,每个资源文件中的 key 是不变的,但是value 随着不同的国家语言而改变。
如下图所示:提供了中文、英语俩种语言

英文

 

#public
PUBLIC_QUERY_SUCCESS=The query is successful
PUBLIC_QUERY_FAIL=The query fails

 中文

 

#public
PUBLIC_QUERY_SUCCESS=查询成功
PUBLIC_QUERY_FAIL=查询失败

 

测试

package com.cloud.user.controller;

import com.cloud.framework.bean.Result;
import com.cloud.framework.util.ResponseUtils;
import com.cloud.user.base.BaseResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;


/**
 * i18 国际化  中英文 翻译
 */
@RestController
@RequestMapping("/i18")
public class I18TransController extends BaseResource {

    /**
     *默认翻译
     */
    @GetMapping("/defaultTran")
    public Result<Object> defaultTran() {
        return ResponseUtils.make(Result.OK, sysToLocale("PUBLIC_QUERY_SUCCESS"));
    }

    /**
     * 模拟登录 前端 传翻译类型  根据前端传值进行翻译  zh_CN 中文  en_US英文
     * @param lang
     * @return
     */
    @GetMapping("/login")
    public Result<Object> login(@RequestParam(name = "lang") String lang) {
        String errMsg="PUBLIC_QUERY_SUCCESS";
        errMsg = sysToLocale(lang, errMsg);
        return ResponseUtils.make(Result.OK, errMsg);
    }


    /**
     * 根据字典存值翻译  比如 下拉框类型翻译
     * @return
     */
    @GetMapping("/tranByDictSelect")
    public Result<Object> tranByDictSelect() {
        //strategyCategoryReserve模拟数据库字典表 存的需要翻译的值
        String name="strategyCategoryReserve";//下拉框数据 i18n_value字段对应存值
        String transName = languageSwitch(name);
        return ResponseUtils.make(Result.OK, transName);
    }

    /**
     * 根据字典存值翻译  菜单翻译
     * @return
     */
    @GetMapping("/tranByDictMenu")
    public Result<Object> tranByDictMenu() {
        //jurisdiction 模拟数据库字典表 存的需要翻译的值
        String name="jurisdiction";//菜单数据 i18n_value字段对应存值
        String typeKey="i18n_menu_name";//菜单数据 i18n_value字段对应存值
        String transName = languageSwitch(typeKey,name);
        return ResponseUtils.make(Result.OK, transName);
    }

}

 

启动项目时需把字典数据加入缓存  只贴关键性代码

package com.cloud.user;

import com.alibaba.fastjson.JSONObject;
import com.cloud.framework.cache.RedisUtils;
import com.cloud.framework.util.SpringContextUtils;
import com.cloud.user.entity.db1.XbDictionary;
import com.cloud.user.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.Arrays;
import java.util.List;

@SpringBootApplication
@Slf4j
public class CloudUserApplication implements CommandLineRunner {

    private final ApplicationContext appContext;

    private final TestService testService;

    private final RedisUtils redisUtils;

    public CloudUserApplication(ApplicationContext appContext, TestService testService, RedisUtils redisUtils) {
        this.appContext = appContext;
        this.testService = testService;
        this.redisUtils = redisUtils;
    }


    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(CloudUserApplication.class, args);
        SpringContextUtils.setApplicationContext(context);
    }

    @Override
    public void run(String... args) throws Exception {
        String[] beans = appContext.getBeanDefinitionNames();
        Arrays.sort(beans);
        for (String bean : beans) {
            System.out.println(bean);
        }
        // 初始化字典表数据到redis 翻译时候从redis取
        redisDicCache();

    }

    /**
     * 存储结构  字典数据存储类型 key:value
     * 一级  root:TypeKey
     * 二级  父级TypeKey:二级TypeKey
     * 三级  二级TypeKey:三级TypeKey
     * 翻译数据 存储类型为list
     * language:二级TypeKey   下拉框数据 language:i18n_value   菜单数据language:i18n_menu_name
     */
    public void redisDicCache() {
        List<XbDictionary> dicList = testService.findAll();
        List<XbDictionary> list = testService.findParentIdisNull();
        //redisUtils.removePattern("language:*");
        for (XbDictionary item : list) {
            //若字典为一级记为root:TypeKey
            String pTypeKey = item.getTypeKey();
            //redisUtils.set("root" + ":" + pTypeKey, item);
            log.info("一级pTypeKey:{},item:{}", pTypeKey, item);
            for (XbDictionary dic : dicList) {
                if (item.getId().equals(dic.getParentId())) {
                    String typeKeyTwo = dic.getTypeKey();
                    log.info("一级{}二级{}:typeKeyTwo:{},dic:{}", pTypeKey, typeKeyTwo, dic);
                    //redisUtils.set(pTypeKey + ":" + typeKeyTwo, dic);
                    for (XbDictionary dictionary : dicList) {
                        String typeKeyThree = dictionary.getTypeKey();
                        if (!typeKeyTwo.equals(typeKeyThree) &&
                                typeKeyThree.contains(typeKeyTwo)) {
                            // redisUtils.set(typeKeyTwo + ":" + typeKeyThree, dictionary);
                            log.info("二级{}三级{}:typeKeyThree:{},dictionary:{}", typeKeyTwo, typeKeyThree, dictionary);
                        }
                        if (typeKeyTwo.contains("i18n_") && dic.getId().equals(dictionary.getParentId())) {
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put("id", dictionary.getId());
                            jsonObject.put("name", dictionary.getName());
                            jsonObject.put("parentId", dictionary.getParentId());
                            jsonObject.put("typeKey", dictionary.getTypeKey());
                            jsonObject.put("value", dictionary.getI18nValue());
                            //  redisUtils.lPush("language:" + dic.getTypeKey(), jsonObject);
                            log.info("翻译数据typeKey{},数据:{}", "language:" + dic.getTypeKey(), jsonObject);
                        }
                    }
                }
            }
        }
    }


}

postman访问   默认值配置的英文en_US

 配置的改为中文  zh_CN

根据前端传值 进行翻译

http://localhost:9000/i18/login?lang=zh_CN

 根据数据库字典表存值翻译  对应前端下拉框

 

  根据数据库字典表存值翻译  对应前端菜单

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/190987.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

相控阵天线分析综合、设计与测试

目录概述HFSS特殊曲线天线建模直线阵列天线特性和阵列因子&#xff08;方向图乘积定理、波束扫描&#xff09;非规则直线阵列天线&#xff08;稀布阵列、稀疏阵列、平方率分布阵列&#xff09;直线阵列天线低副瓣综合&#xff08;切比雪夫、泰勒分布、SinZ-Z和Villeneuve分布&a…

2023-java面试最新总结

1. Java中的原始数据类型都有哪些&#xff0c;它们的大小及对应的封装类是什么&#xff1f; boolean boolean数据类型非true即false。这个数据类型表示1 bit&#xff0c;但是它的大小并没有精确定义。 《Java虚拟机规范》中如是说&#xff1a;“虽然定义了boolean这种数据类型…

胡歌官宣生女,胡椒粉们真为他高兴,人生最顶级的能力是【涅槃重生】的力量

今天刷到胡歌官宣生女&#xff0c;胡歌当父亲了&#xff0c;真为他高兴。恭喜老胡&#xff01;&#x1f389;作为十多年胡椒粉&#xff0c;连夜录制了这个视频&#xff08;抖音视频号&#xff1a;【小伍说_523的作品】胡歌官宣生女&#xff0c;十几年的胡椒粉真替他高兴&#x…

Unity二

一、脚本的创建 可以在project视图中的Assets文件夹中右键创建一个C#脚本&#xff0c;可以将脚本分类放在不同的文件夹中&#xff0c;或者点击游戏对象后在Inspector视图中找到最下方的添加组件按钮&#xff0c;然后点击新建脚本即可。若在project视图中创建的脚本&#xff0c…

详解HTTP请求行

请求行格式 request-linemethod SP request targe SP HTTP-version CRLFrequest-target 有四种格式 origin-formabsolute-path&#xff1a;向原服务器&#xff0c;也就是实际响应内容的服务器发起请求的&#xff0c;path为空时&#xff0c;必须传递 /absolute-formabsolute…

应用性能监控对系统慢访问分析案例

背景 某港口综合管控系统是其主要的业务系统&#xff0c;最近发现用户反馈出现访问响应慢的情况。 该港口已部署NetInside流量分析系统&#xff0c;使用流量分析系统提供实时和历史原始流量。本次分析重点针对综合管控业务系统性能进行分析&#xff0c;以供安全取证、性能分析…

C# 国际化问题之CultureInfo(小数点的不同一些欧洲国家习惯使用,而非.)

前言 在公司做的桌面软件在国内以及亚美洲地区都能正常使用&#xff0c;结果到了俄罗斯客户那边软件就根本打不开&#xff0c;不能正常使用。 文章目录定位问题分析问题找解决方案总结定位问题 经定位排查&#xff0c;最终发现是俄罗斯的浮点数不是用小数点&#xff0c;而是用…

网赚 美金 Neobux注册操作完整教程

neobux是点击网赚即时支付&#xff08;Instant pay&#xff09;型的创始网站&#xff0c;同时也是点击网赚类网站中信誉最高、实力最强&#xff0c;会员最多、最稳定的。Neobux官网 https://www.neobux.com/?rxyadmin账户注册1.点击官网地址进入neobux主站&#xff0c;点击右上…

【正点原子FPGA连载】第二十五章设备树下的LED驱动实验 摘自【正点原子】DFZU2EG_4EV MPSoC之嵌入式Linux开发指南

1&#xff09;实验平台&#xff1a;正点原子MPSoC开发板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id692450874670 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十五章设备树…

BUUCTF[GXYCTF2019]Ping Ping Ping 1

题目 http://06590c75-6f53-45ea-b42d-b2034e4cd98e.node4.buuoj.cn:81/ 解题过程 1.尝试ping一下127.0.0.1 http://06590c75-6f53-45ea-b42d-b2034e4cd98e.node4.buuoj.cn:81/?ip127.0.0.1 2.尝试查看当前目录下的内容 http://06590c75-6f53-45ea-b42d-b2034e4cd98e.node…

vue项目采用vue-cli-plugin-cesium 插件集成cesium

市面上的前端框架中&#xff0c;VueCesium 可谓是最佳搭档&#xff0c;一般做 Cesium B 端产品的公司都会使用 Vue&#xff0c;所以后续内容都将基于 Vue通常情况下&#xff0c;我们要在 Vue 中使用 Cesium&#xff0c;首先要安装 Cesium&#xff0c;然后要在 vue-cli 的 webpa…

涂鸦发布蓝牙子设备框架,让智能家居快速实现毫秒级配网速度

如果有人问智能家居行业应用最广的协议是什么&#xff1f;蓝牙一定是选项之一。体积小便于集成、功耗低、全球适用等特征&#xff0c;让蓝牙设备被大范围应用。在消费侧则更关心的问题是&#xff1a;设备的配网速度、成功率以及设备连接的稳定性。 所以&#xff0c;市场要找到…

26对称矩阵及正定性

一、知识概要 本节从对称矩阵的特征值&#xff0c;特征向量入手&#xff0c;介绍对称矩阵在我们之前学习的一些内容上的特殊性质。并借此引出了正定矩阵。 二、对称矩阵 正如我们之前学习的很多特殊矩阵一样&#xff08;如马尔科夫矩阵&#xff09;&#xff0c;对称矩阵也有…

字符串流stringstream--<sstream>

字符串流stringstream流详解 一.stringstream是C提供的一个字符串流&#xff0c;与iostream和fstream的操作方法类似&#xff0c;只是功能不同。要使用字符串流必须包含其头文件<sstream>。 #include<sstream> 二.stringstream字符串流通常用来做数据转换&#x…

python-闭包知识点

目录标题1、函数参数2、闭包3、闭包的使用4、闭包内修改外部变量1、函数参数 def fun01():print(func01 is show) #fun01() 会输出打印结果 print(fun01)#输出&#xff1a;<function ox11....地址> #函数名存放的是函数所在空间的地址fun02 fun01 #函数名也可以像普通…

中国电子学会2021年12月份青少年软件编程Scratch图形化等级考试试卷三级真题(含答案)

青少年软件编程&#xff08;图形化&#xff09;等级考试试卷&#xff08;三级&#xff09; 分数&#xff1a;100 题数&#xff1a;38 一、单选题(共 25 题&#xff0c;共 50 分) 执行下列程序&#xff0c;屏幕上可以看到几只小猫&#xff1f;&#xff08;B &#xff09;(2…

奇怪的一些

1、请求200 但是请求回来的是html 网络里会写 200OK from disk cache 这个时候需要清除浏览器缓存 2、base64 引入失败 找一个js文件直接引入 require is not defined import Base64 from ‘***’ https://blog.csdn.net/u011383596/article/details/116712729 3、promise prom…

dataworks插入,分组,排序,关联语句

– 向表中插入数据 – insert into/overwrite table 表名 values (…),(…),…; – insert into/overwrite table 表名 select …; – 创建样例表 create table if not exists temp_test_xsxx_30( xh string comment ‘学号’, xm string comment ‘姓名’, xb string comment…

C++初阶--map和set

目录 关联式容器 set set的模板参数列表 set的构造 set的使用 multiset map map的模板参数 map的构造 map的容量与元素访问 map的使用 multimap 底层结构 AVL树 节点的定义 实现 图解 红黑树 性质 节点的定义 实现 图解​ 红黑树模拟实现STL中的map和set MyMap.h MySet.…

windows系统使用Freeglut+glew库编写opengl程序(Mingw)

Freeglut glut是opengl实用工具集,由Mark Kilgrad所写。可以用来显示窗体,管理用户输入,字体,图像等操作,现在已经停止维护了,它的3.7版本是苹果电脑操作系统Mac OS 10.8(又名“美洲狮”)的opengl实用工具库的框架基础 使用更新的Freeglut替代glut,Freeglut是由Pawel…