<返回更多

JAVA 实现多语言

2023-02-01    so贝塔
加入收藏

 

国际化是产品、应用程序或文档内容的设计和开发,它可以为不同文化、地区或语言的目标受众轻松实现本地化。国际化(Internationalization)通常用英文写成 i18n,其中 18 是英文单词中 i 和 n 之间的字母数。

任何一个面向全世界的软件都会面临多语言国际化的问题,尤其是跨境电商行业,在做自研系统必不可少的要实现多语言功能,就是在数据展示给用户之前,替换成用户可识别的语言,这里以spring i18n 国际化来介绍一下。

SpringBoot下Application.yml

basename:以逗号分隔的基名列表(本质上是一个完全限定的类路径位置),每个基名都遵循 ResourceBundle 约定,对基于斜杠的位置提供宽松的支持,它将从类路径根目录解析。

cache-duration:加载的资源包文件缓存的持续时间。如果没有设置,捆绑包将被永久缓存。如果没有指定持续时间后缀,将使用秒。

spring:
  # 资源信息
  messages:
    encoding: utf-8
    # 国际化资源文件路径(配置文件路径),多模块也可以用逗号分隔
    basename: i18n/messages

将异常信息写入i18n资源文件

messages.properties

exception.name.can.not.null=exception name can not null,the name is {0}
exception.insert=exception insert

messages_zh_CN.properties

exception.name.can.not.null=用户名不能为空,用户名为:{0}
exception.insert=新增异常

工具类 I18nUtils

@Component
@Slf4j
public class I18nUtils {
    
    // 如果当前bean不加@Component注解,则messageSource无法注入,始终为null
    private static MessageSource messageSource;

    @Autowired
    public void setMessageSource(MessageSource messageSource) {
        I18nUtils.messageSource = messageSource;
    }

    /**
     * 解析code对应的信息进行返回,如果对应的code不能被解析则抛出异常NoSuchMessageException
     *
     * @param code 需要进行解析的code,对应资源文件中的一个属性名
     * @param args 当对应code对应的信息不存在时需要返回的默认值
     * @return 国际化翻译值
     */
    public static String i18n(String code, Object... args) {
        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
    }

    /**
     * 解析code对应的信息进行返回,如果对应的code不能被解析则返回默认信息defaultMessage。
     *
     * @param code 需要进行解析的code,对应资源文件中的一个属性名
     * @param defaultMessage 当对应code对应的信息不存在时需要返回的默认值
     * @param args 需要用来替换code对应的信息中包含参数的内容,如:{0},{1,date},{2,time}
     * @return 对应的Locale
     */
    public static String i18nOrDefault(String code, String defaultMessage, Object... args) {
        return messageSource.getMessage(code, args, defaultMessage, LocaleContextHolder.getLocale());
    }

    /**
     * 因为i18n方法如果获取不到对应的键值,会抛异常NoSuchMessageException
     * 本方法是对i18n方法的封装。当报错时并不抛出异常,而是返回source
     *
     * @param source 模板
     * @param args   参数
     * @return 返回I18n(正常结束)或者source(抛出异常)
     * @see #i18n(String, Object...)
     */
    @NonNull
    public static String tryI18n(@NonNull String source, @NonNull Object... args) {
        String res;
        try {
            res = i18n(source, args);
        } catch (Exception ignored) {
            res = source;
        }
        return res;
    }
}

自定义异常

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    @ExceptionHandler(CommonException.class)
    public ApiResponse<Object> handleCommonException(CommonException e) {
        log.error(e.getMessage(), e);
        return new ApiResponse<>(-1,"error",e.getMessage());
    }
}

应用

@Service
public class UserService {

    @Resource
    private UserDao userDao;

    public void insertUser(UserQo userQo){
        UserEntity userEntity = userDao.findByName(userQo.getName());
        if(Objects.nonNull(userEntity)){
            // i18n带有参数
            String name = userQo.getName();
            throw new CommonException("exception.name.can.not.null",name);
        }
        userEntity = new UserEntity();
        BeanUtils.copyProperties(userQo,userEntity);
        userEntity.setCreateTime(new Date());
        int count = userDao.insert(userEntity);
        if(count==1){
            // i18n不带有参数
            throw new CommonException("exception.insert");
        }
    }
}

结论

这里只是简单的演示了 spring i18n 的功能,可以满足一些简单场景的需求,可以适当扩展,比如:如果使用了 nacos 等配置中心,则需要去注册中心手动拉取 i18n 的 properties 文件内容,并加载到应用程序的内存里。

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>