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

文章介绍了如何在SpringBoot后端结合Java实现国际化,使用ResourceBundleMessageSource和自定义配置类处理翻译对象,如菜单和接口提示信息。前端使用Vue和vue-i18n处理页面内容的中英文切换。同时,文章提到了数据库字典表的翻译缓存策略,并提供了相关控制器方法的示例。
摘要由CSDN通过智能技术生成

一、背景

接触到的项目,使用国际化越来越多,系统页面实现中英文环境,记录下,前端使用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

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

 

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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值