springboot国际化多语言

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,重写解析语言环境的方法。(这里也可以重写org.springframework.web.servlet.LocaleResolver类。包装request,在过滤器以及以后的阶段都可以正确读取到多语言环境;重写LocaleResolver,是在过滤器与拦截器之间的阶段设置多语言环境,只能在拦截器以及以后的阶段读取到多语言环境)

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)手动抛出异常信息

注入org.springframework.context.MessageSource,将异常信息转成对应的语言后返回。

2)validation框架抛出异常信息

使用{},将定义的多语言key括起来,框架自动接入了定义的多语言环境,即可自动返回对应的语言。

(to be continued...)

参考:

『SpringBoot』如何配置国际化_springboot国际化-CSDN博客

SpringBoot实现动态数据国际化_springboot国际化动态加载-CSDN博客

Validator校验框架使用i18n国际化_public validator validator(resourcebundlemessageso-CSDN博客

SpringBoot校验框架Validation、统一异常处理及项目的国际化_springboot 国际化 异常-CSDN博客

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot提供了一个方便的方式来支持国际化和多语言。下面是一些简单的步骤来实现它: 1. 在 `src/main/resources` 目录下创建一个文件夹 `i18n`,并在其中创建一个 `messages.properties` 文件,存储默认的文本信息。 2. 在 `messages.properties` 文件中添加需要国际化的文本信息,例如: ``` greeting=Hello, World! ``` 3. 创建其他语言的属性文件,例如 `messages_zh.properties`,并在其中添加相应的文本信息,例如: ``` greeting=你好,世界! ``` 4. 在 Spring Boot 的配置文件 `application.properties` 中添加以下配置: ``` spring.messages.basename=i18n/messages spring.messages.fallback-to-system-locale=false ``` `spring.messages.basename` 属性告诉 Spring Boot 从哪个文件夹加载属性文件。在这个例子中,我们指定了 `i18n/messages`,这意味着 Spring Boot 将加载 `messages.properties` 和 `messages_*.properties` 文件。 `spring.messages.fallback-to-system-locale` 属性告诉 Spring Boot 是否应该回退到系统语言环境。在这个例子中,我们将其设置为 `false`,这意味着如果没有找到匹配的语言环境,Spring Boot 将使用 `messages.properties` 中的默认值。 5. 在代码中使用 `MessageSource` 来获取文本信息。例如: ```java @Autowired private MessageSource messageSource; public String getGreeting(String lang) { Locale locale = new Locale(lang); return messageSource.getMessage("greeting", null, locale); } ``` 在这个例子中,我们使用 `MessageSource` 来获取 `greeting` 属性的值。我们还指定了语言环境,以便 `MessageSource` 可以查找相应的属性文件。如果没有找到匹配的属性文件,`MessageSource` 将返回默认值。 在这个例子中,我们假设 `lang` 参数将是一个标准的语言代码,例如 `en` 或 `zh`。您可以根据自己的需要更改此代码。 这些是实现 Spring Boot 国际化和多语言的基本步骤。当您运行应用程序时,Spring Boot 将自动加载相应的属性文件,并根据用户的语言环境返回相应的文本信息

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值