springboot国际化多语言

news2024/11/17 0:24:02

1,新建国际化多语言文件

在resources目录下新建 messages.properties + 其他语言的文件

编辑messages.properties文件,下方从text切换到Resource Bundle ,即可对照着编辑多语言文件

(如果没有找到Resource Bundle,先在settings->plugins中安装Resource Bundle Editor)

2,配置文件添加配置

spring.messages.always-use-message-format=false

是否始终应用 MessageFormat 规则,甚至分析没有参数的消息。

默认是false

 

spring.messages.basename=messages

以逗号分隔的基名列表(实质上是完全限定的类路径位置),每个基名都遵循 ResourceBundle 约定,对基于斜杠的位置提供了宽松的支持。如果它不包含包限定符(例如“org. mypackage”),则将从类路径根目录解析它。

默认是messages,所以第一步中文件为messages.properties,也可根据实际定义其他名字。

 

spring.messages.cache-duration=1000

 加载的资源包文件缓存持续时间。如果未设置,捆绑包将永久缓存。如果未指定持续时间后缀,则将使用秒。

默认是null。

 

spring.messages.encoding=utf-8

 消息包编码。

默认是UTF-8

 

spring.messages.fallback-to-system-locale=true

 如果未找到特定区域设置的文件,是否回退到系统区域设置。如果关闭此功能,则唯一的回退将是默认文件(例如,basename “messages”的“messages. properties”)。

默认是true

 

spring.messages.use-code-as-default-message=false

 是否使用消息代码作为默认消息,而不是抛出“NoSuchMessageException”。建议仅在开发期间使用。

默认是false。

第一步中我们定义了一个参数叫test.i18n.message,如果我们使用的时候取名test.i18n.message123,只要是多语言文件中未定义的key,则该参数设置为false时,会报错。设置为true时,不会报错,由于找不到对应的key,则不替换该多语言字符。

3,设置上下文语言环境

在web请求中,两个地方会根据header中的参数设置语言环境:

org.springframework.web.filter.RequestContextFilter#initContextHolders

org.springframework.web.servlet.FrameworkServlet#initContextHolders

解析request中locale的地方:

org.apache.catalina.connector.Request#parseLocales

如果请求头中为携带语言参数的header为accept-language,则框架已自动帮我们做了解析,不用我们再写额外代码。

注意:参考了多个大公司国际化,没有公司将国际化相关的数据用accept-language传递(accept-language本身记录的是浏览器(我用的谷歌浏览器)的语言环境,可能是可以作为其他的业务数据,类似于收集用户数据等),而是存放在cookie中。

所以我们要定义一个参数,将国际化相关的数据存放在cookie中,请求后端时将该参数添加到header(单独定义一个header参数,或者将整个cookie传输)中传递到后端。

假设这里是单独定义了一个header参数:test-lang。

框架解析多语言环境时,使用的accept-language,所以我们要重写解析的方法,替换为我们自定义的header参数:test-lang。

新建一个request的包装类,在filter中包装原request,重写解析语言环境的方法。

import org.apache.tomcat.util.http.parser.AcceptLanguage;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;

/**
 * @Description i18n 国际化包装请求
 * @DATE 2024/4/6 22:45
 **/
public class I18nWrapperRequest extends HttpServletRequestWrapper {

    public I18nWrapperRequest(HttpServletRequest request) {
        super(request);
    }

    /**
     * Parse locales.
     */
    protected boolean localesParsed = false;

    /**
     * The preferred Locales associated with this Request.
     */
    protected final ArrayList<Locale> locales = new ArrayList<>();

    /**
     * The default Locale if none are specified.
     */
    protected static final Locale defaultLocale = Locale.getDefault();

    @Override
    public Locale getLocale() {

        if (!localesParsed) {
            parseLocales();
        }

        if (locales.size() > 0) {
            return locales.get(0);
        }

        return defaultLocale;
    }


    @Override
    public Enumeration<Locale> getLocales() {
        if (!localesParsed) {
            parseLocales();
        }

        if (locales.size() > 0) {
            return Collections.enumeration(locales);
        }
        ArrayList<Locale> results = new ArrayList<>();
        results.add(defaultLocale);
        return Collections.enumeration(results);
    }

    /**
     * Parse request locales.
     */
    protected void parseLocales() {

        localesParsed = true;

        // Store the accumulated languages that have been requested in
        // a local collection, sorted by the quality value (so we can
        // add Locales in descending order). The values will be ArrayLists
        // containing the corresponding Locales to be added
        TreeMap<Double, ArrayList<Locale>> locales = new TreeMap<>();

        Enumeration<String> values = ((HttpServletRequest) getRequest()).getHeaders("test-lang");

        while (values.hasMoreElements()) {
            String value = values.nextElement();
            parseLocalesHeader(value, locales);
        }

        // Process the quality values in highest->lowest order (due to
        // negating the Double value when creating the key)
        for (ArrayList<Locale> list : locales.values()) {
            for (Locale locale : list) {
                addLocale(locale);
            }
        }
    }

    /**
     * Parse accept-language header value.
     *
     * @param value   the header value
     * @param locales the map that will hold the result
     */
    protected void parseLocalesHeader(String value, TreeMap<Double, ArrayList<Locale>> locales) {

        List<AcceptLanguage> acceptLanguages;
        try {
            acceptLanguages = AcceptLanguage.parse(new StringReader(value));
        } catch (IOException e) {
            // Mal-formed headers are ignore. Do the same in the unlikely event
            // of an IOException.
            return;
        }

        for (AcceptLanguage acceptLanguage : acceptLanguages) {
            // Add a new Locale to the list of Locales for this quality level
            Double key = Double.valueOf(-acceptLanguage.getQuality()); // Reverse the order
            locales.computeIfAbsent(key, k -> new ArrayList<>()).add(acceptLanguage.getLocale());
        }
    }

    /**
     * Add a Locale to the set of preferred Locales for this Request. The first added Locale will be the first one
     * returned by getLocales().
     *
     * @param locale The new preferred Locale
     */
    public void addLocale(Locale locale) {
        locales.add(locale);
    }

}
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Description 国际化过滤器
 * @DATE 2024/4/6 23:00
 **/
@WebFilter("/**")
@Component
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class I18nFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(new I18nWrapperRequest(request), response);
    }
}

4,返回多语言

目前是在报错信息中需要返回多语言,报错分为两种:

1)手动抛出异常信息

2)validation框架抛出异常信息

首先,我们需要

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

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

相关文章

学习 MongoDB:打开强大的数据库技术大门

一、基本概念 MongoDB 是一个基于分布式文件存储的文档数据库&#xff0c;由 C 语言编写。它旨在为 Web 应用提供可扩展的高性能数据存储解决方案。 相信MySQL我们非常的熟悉&#xff0c;那么MySQL的表结构与MongoDB的文档结构进行类比的话可能更好理解MongoDB。 MySQL的数据…

Spyder无法载入(load)或者闪退问题

在Anaconda prompt中直接输入spyder&#xff0c;报错如下 Traceback (most recent call last):File "C:\Users\user\.conda\envs\KB\Scripts\spyder-script.py", line 10, in sys.exit(main())File "C:\Users\user\.conda\envs\KB\lib\site-packages\spyder\a…

baseline SE SP YI是什么?

SE、SP和YI是评估分类模型性能时常用的几个统计指标&#xff0c;特别是在医学影像处理、疾病诊断等领域&#xff0c;这些指标帮助了解模型对于正负类样本的识别能力。 SE (Sensitivity)&#xff0c;也称为真正率&#xff08;True Positive Rate, TPR&#xff09;或召回率&#…

泛型(java学习)

目录 1.泛型介绍&#xff1a; 2.泛型的好处&#xff1a; 3.泛型的语法 4.泛型的细节 5.自定义泛型 6.自定义泛型接口 8.泛型的继承和通配符 1.泛型介绍&#xff1a; 1&#xff09;泛型又称参数化类型&#xff0c;解决数据类型的安全性问题。 2&#xff09;在类声明或实例…

5.3 用栈翻转数组,动态规划求斐波那契数列

5.3 用栈翻转数组&#xff0c;动态规划求斐波那契数列 1. 用栈翻转数组 assume cs:code,ds:data,ss:stack data segmentarr dw 1111h,2222h,3333h,4444h,5555h,6666h,7777h,8888hres db 800 dup(0) data endsstack segmentdb 100 dup(0) stack endscode segmentstart:mov ax,…

计算机视觉入门:开启图像理解之旅

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

【算法篇】三道题理解算法思想——认识BFS

BFS&#xff08;宽搜&#xff09; 宽度优先遍历和深度优先遍历组成了大家熟悉的搜索算法&#xff0c;这两种算法也是蓝桥杯之类竞赛题的常考思想&#xff0c;正巧马上蓝桥杯临近&#xff0c;博主也是刷了很多BFS相关的题型&#xff0c;在这篇文章中会从力扣上选取三道简单的宽搜…

小象超市(原美团买菜) 的大屏图表

文章目录 概要技术细节技术名词解释小结 概要 20203年12月1日&#xff0c;美团旗下自营零售品牌“美团买菜”升级为全新品牌“小象超市”。 &#xff0c;“小象超市”坚持美团自营零售模式&#xff0c;通过在社区设立的集存储、分拣、配送为一体的便民服务站&#xff0c;为社区…

关于16:9和4:3的有关知识,看这篇文章就差不多了

序言 在你拍照或录制视频之前,你需要考虑使用哪个纵横比。最常见的两种纵横比是16:9和4:3,但哪一种最适合你? 16:9的纵横比最适合视频,因为宽度比高度宽78%,这使你更容易在水平方向上适应更多画面,同时优化视频以适应现代屏幕。 同时,4:3的纵横比更适合摄影,因为宽度…

书籍《笔记的方法》读后感

读完《笔记的方法》有几周的时间&#xff0c;书里有些记录的内容&#xff0c;觉得非常有价值的&#xff0c;自己的观点&#xff0c;当下读书&#xff0c;其实并没有那么高大尚&#xff0c;就是存粹陶冶下情操&#xff0c;读书还是有一定作用的&#xff0c;毕竟看书只能慢慢来&a…

【PDF-XSS攻击】Java项目-上传文件-解决PDF文件XSS攻击

文章目录 背景解决pdfbox依赖控制器代码PdfUtils工具类 验证最后源码参考 背景 上传xss-pdf造成存储型xss因为在浏览器直接预览的PDF&#xff0c;而不是预览&#xff0c;所以安全部门认为会有XSS漏洞 解决 安全部门修复建议 1、根据白名单的标签和属性对数据进行过滤&#…

C++后端程序员如何在缺乏相关外包项目中寻找赚取外快的途径

作为一位专业的C后端程序员&#xff0c;你拥有扎实的技术功底和丰富的编程经验&#xff0c;然而在寻求外包项目的道路上&#xff0c;可能时常会发现市场上的项目并不都与C直接相关。但这并不意味着你就无法利用自己的技能来获取额外收入。本文将为你揭示一些即使在当前环境下&a…

力扣热题100_链表_138_随机链表的复制

文章目录 题目链接解题思路解题代码 题目链接 138. 随机链表的复制 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&a…

【算法】动态规划练习(一)

目录 1137. 第 N 个泰波那契数 分析 代码 面试题 08.01. 三步问题 分析 代码 746. 使用最小花费爬楼梯 分析 代码 泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2 给你整数 n&#xff0c;请返回第 n 个泰波…

软件测试人员如何避免成为“背锅侠”

作为一名软件测试工程师&#xff0c;我们的角色可以算是“战场上的后勤”&#xff0c;战役的胜败和所有团队人员都息息相关。 但是难免碰到战役失败后&#xff0c;很多团队互相推脱的局面&#xff0c;而测试人员就是所有团队中的弱势群体&#xff0c;自然是首当其冲的背锅侠&a…

34.Python从入门到精通—Python3 正则表达式检索和替换

34.从入门到精通&#xff1a;Python3 正则表达式检索和替换 repl 参数是一个函数 正则表达式对象 正则表达式修饰符 - 可选标志 正则表达式模式* 正则表达式实例 检索和替换repl 参数是一个函数正则表达式对象正则表达式修饰符 - 可选标志正则表达式模式*正则表达式实例 检索和…

JAVA并发编程(一)

JAVA并发编程&#xff08;一&#xff09; 1.1JAVA线程API 1.1.1currentThread package com.lisus2000.thread;/** * 当前线程 * */ public class Test07 extends Thread {public Test07() {System.out.println("new Test07()......" Thread.currentThread().getNa…

全网短剧搜索前端源码开源分享可改自己的接口

全网短剧搜索前端源码 内含7000短剧资源(不支持在线播放&#xff09; 源码全开源&#xff0c;可以修改成自己的接口 178、226、347行修改 源码免费下载地址抄笔记 (chaobiji.cn)https://chaobiji.cn/

HarmonyOS实战开发-如何实现蓝牙设备发现、配对、取消配对功能。

介绍 蓝牙技术是一种无线数据和语音通信开放的全球规范&#xff0c;它是基于低成本的近距离无线连接&#xff0c;为固定和移动设备建立通信环境的一种特殊的近距离无线技术连接。本示例通过ohos.bluetooth 接口实现蓝牙设备发现、配对、取消配对功能。实现效果如下&#xff1a…

小秦网站部署上线

叮&#xff5e;您有一份消息&#xff0c;请注意查收&#xff01; 小秦个人网站终于上线了&#xff1a; 网站主要有&#xff1a;免费听歌、看小姐姐、AI女友、留言板等功能&#xff0c;建议收藏、收藏、再收藏、重要事情说三遍&#xff01;&#xff01;&#xff01; 网站&#x…