前言

Dropwizard官方文档并没有提供国际化的模块,所以只能自己加。Spring的MessageResource用的很顺手,所以copy过来。

Easy i18n

在整合Dropwizard的时候,多语言貌似只能通过jdk自带的ResourceBundle拿数据。其实也就够了,但在开发过程中发现需要缓存,需要解析占位符等。代码越写越多,显然不是仅仅一个调用就完事的。写的差不多的时候突然觉得和spring context里的message source结构类似。于是,放弃维护已经开始变的复杂的逻辑,直接使用spring。

但选取dropwizard的时候就是摒弃了spring,再拿过来也不好玩了。干脆,抽取Spring context项目的MessageResource相关代码,重写封装了一个library: https://github.com/Ryan-Miao/easy-i18n, 欢迎star。

easy-i18n还是和在Spring项目中相同。

首先,引入依赖,由于github项目的library已经有仓库去维护了,就没费心思放到maven和jcenter了,直接从github上拉取。类库地址为:

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

引入

<dependency>
<groupId>com.github.Ryan-Miao</groupId>
<artifactId>easy-i18n</artifactId>
<version>1.0</version>
</dependency>

简单使用

#情形一 只有一个Resource Bundle

在resources下新建i18n/messages.properties以及i18n/messages_zh_CN.properties. demo位置:l4dropwizard

然后,调用方法如下:

@Test
public void testI18n(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.addBasenames("i18n/messages");
messageSource.setDefaultEncoding("UTF-8"); String index = messageSource.getMessage("index", null, Locale.US);
System.out.println(index);
}

#情形二 我有多个Resource Bundle

实际项目中,由于产品分类,有时候需要创建多个Resource Bundle,这时候也简单,只要创建多个ResourceBundleMessageSource来读取翻译即可。


public void testI18n2(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.addBasenames("i18n/messages");
messageSource.setDefaultEncoding("UTF-8"); String index = messageSource.getMessage("index", null, Locale.US);
System.out.println(index); ResourceBundleMessageSource messageSource2 = new ResourceBundleMessageSource();
messageSource.addBasenames("i18n/messages2");
messageSource.setDefaultEncoding("UTF-8"); String second = messageSource.getMessage("second", null, Locale.US);
System.out.println(second);
}

#情形三 我有多个Resource Bundle但读取翻译的时候我想一起

有时候,想要读取翻译,可能翻译文件在不同的Resource Bundle,但我指向用一个接口去调用。这时候,做法时候在这几个Resource Bundle的里面添加命名空间,即key要在这几个Resource Bundle里唯一,而不仅仅是本文件唯一。

然后,


public void testI18n2(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.addBasenames("i18n/messages", "i18n/messages2");
messageSource.setDefaultEncoding("UTF-8"); String index = messageSource.getMessage("index", null, Locale.US);
System.out.println(index);
}

这种做法,会一次从两个Resource Bundle里寻找翻译,找到即返回。因此,如果有相同的key,将导致只有第一个生效。

#情形4

没有了,你翻译要那么复杂吗。

更多用法,参考测试类:ResourceBundleMessageSourceTest

Demo source

https://github.com/Ryan-Miao/l4dropwizard

本文是基于dropwizard入门之上的演进。

确保依赖都是最新的,或者自行解决版本冲突,比如jackson不同版本之间的类有所不同。

引入easy-i18n

repository url

<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

引入

<dependency>
<groupId>com.github.Ryan-Miao</groupId>
<artifactId>easy-i18n</artifactId>
<version>1.0</version>
</dependency>

添加Resource Bundle

resources下新增文件夹i18n, 依次添加几个Resource Bundle。具体做法是,在文件夹i18n右键 -> new -> Resource Bundle, 然后选择想要支持的语言。比如美国en_US,简体中文zh_CN

新建MessageService

创建一个Util来处理翻译功能。

com.test.domain.service.IMessageService

package com.test.domain.service;

import java.text.MessageFormat;
import java.util.List;
import java.util.Locale; /**
* The Message translation service
* Created by Ryan Miao on 11/23/17.
*/
public interface IMessageService { /**
* Get translation by message key.
*
* @param key The message key in the properties
* @return the translated message
*/
String getMessage(String key, Locale locale); /**
* Get translation by message key and compose it with variables.
* Note that the variable would be injected by {@link MessageFormat}
*
* @param key The message key in the properties
* @param args The variables to inject into the message.
* @return the translated message.
*/
String getMessage(String key, List<String> args, Locale locale);
}

实现类com.test.domain.service.impl.MessageService

package com.test.domain.service.impl;

import com.miao.easyi18n.support.ResourceBundleMessageSource;
import com.test.domain.service.IMessageService; import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Locale; /**
* Created by Ryan Miao on 11/23/17.
*/
@Singleton
public class MessageService implements IMessageService{ private final ResourceBundleMessageSource messageSource; @Inject
public MessageService(ResourceBundleMessageSource messageSource) {
this.messageSource = messageSource;
} @Override
public String getMessage(String key, Locale locale) {
return messageSource.getMessage(key, null, locale);
} @Override
public String getMessage(String key, List<String> args, Locale locale) {
return messageSource.getMessage(key, args.toArray(), locale);
}
}

在IoC中提供ResourceBundleMessageSource

由于ResourceBundleMessageSource是公共组件,需要单独提取出来,并使用单例模式创建。关于IoC的配置,参阅dropwizard中添加DI

ConfigurationModule中:

package com.test.domain.ioc.module;

import com.miao.easyi18n.support.ResourceBundleMessageSource;
import com.test.configuration.HelloWorldConfiguration;
import dagger.Module;
import dagger.Provides; import javax.inject.Singleton; /**
* Created by Ryan Miao on 11/20/17.
*/
@Module
public class ConfigurationModule {
private final HelloWorldConfiguration configuration; public ConfigurationModule(HelloWorldConfiguration configuration) {
this.configuration = configuration;
} @Provides
@Singleton
HelloWorldConfiguration helloWorldConfiguration(){
return configuration;
} @Singleton
@Provides
ResourceBundleMessageSource resourceBundleMessageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.addBasenames("i18n/messages", "i18n/messages2", "i18n/otherGroup");
messageSource.setDefaultEncoding("UTF-8"); return messageSource;
}
}

这里,关于Resource Bundle的位置没有单独提出来,后面可以放到HelloWorldConfiguration,提到配置文件中。

测试

在dagger中,接口和实现类的绑定只能通过手动声明。因此,绑定IMessageService

@Singleton
@Provides
IMessageService messageService(MessageService messageService){
return messageService;
}

创建测试Resource, com.test.domain.resource.LocalResource

package com.test.domain.resource;

import com.codahale.metrics.annotation.Timed;
import com.google.common.collect.ImmutableMap;
import com.test.domain.entiry.GithubUser;
import com.test.domain.service.IMessageService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses; import javax.inject.Inject;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.Locale;
import java.util.Map; /**
* Test localization
* Created by Ryan Miao on 11/23/17.
*/
@Api("/local")
@Path("/local")
@Produces(MediaType.APPLICATION_JSON)
public class LocalResource { private final IMessageService messageService; @Inject
public LocalResource(IMessageService messageService) {
this.messageService = messageService;
} @GET
@Timed
@Path("/{key}")
@ApiOperation(value = "Get github user profile.", notes = "There should be the note.")
@ApiResponses({
@ApiResponse(code = 401, message = "Valid credentials are required to access this resource."),
@ApiResponse(code = 400, message = "Params not valid."),
@ApiResponse(code = 500, message = "Something wrong from the server."),
@ApiResponse(code = 200, message = "Success.", response = GithubUser.class)
})
public Map<String, String> getIndex(
@PathParam("key") final String index,
@HeaderParam("Accept-Language") @Valid
@NotNull(message = "cannot be null.")
@Pattern(regexp = "([a-z]{2}-[A-Z]{2})", message = "pattern should like zh-CN, en-US.")
final String language
) {
final Locale locale = Locale.forLanguageTag(language);
final String message = messageService.getMessage(index, locale);
return ImmutableMap.of(index, message);
}
}

结果



使用dropwizard(6)-国际化-easy-i18n的更多相关文章

  1. Java国际化(i18n)

    Java国际化(i18n) 最近在做一个网站国际化的功能.用Java做开发,使用spring+velocity. Java提供了对i18n的支持,spring对其做了集成,可以很方便的配置.主要思想就 ...

  2. 国际化支持(I18N)

    本章译者:@nixil 使用国际化支持(I18N)能够使你的应用根据用户所在地区的不同选择不同的语言.下面介绍如何在引用中使用国际化. 只允许使用UTF-8 Play只支持UTF-8一种字符编码.这是 ...

  3. java框架篇---Struts2 本地化/国际化(i18n)

    国际化(i18n)是规划和实施的产品和服务,使他们能很容易地适应特定的本地语言和文化的过程中,这个过程被称为本地化.国际化的过程有时也被称为翻译或本地化启用.国际化是缩写i18n,因为我和两端用n字打 ...

  4. 【转】jQuery之前端国际化jQuery.i18n.properties

    jQuery之前端国际化jQuery.i18n.properties 基于jQuery.i18n.properties 实现前端页面的资源国际化 jquery-i18n-properties

  5. java框架篇---Struts2 本地化/国际化(i18n)(转)

    源地址:https://www.cnblogs.com/oumyye/p/4368453.html 国际化(i18n)是规划和实施的产品和服务,使他们能很容易地适应特定的本地语言和文化的过程中,这个过 ...

  6. [Ruby on Rails系列]4、专题:Rails应用的国际化[i18n]

    1. 什么是internationalization(i18n)? 国际化,英文简称i18n,按照维基百科的定义:国际化是指在设计软件,将软件与特定语言及地区脱钩的过程.当软件被移植到不同的语言及地区 ...

  7. jQuery之前端国际化jQuery.i18n.properties

    jQuery.i18n.properties是一款轻量级的jQuery国际化插件,能实现Web前端的国际化. 国际化英文单词为:Internationalization,又称i18n,"i& ...

  8. Chrome浏览器扩展开发系列之十八:扩展的软件国际化chrome.i18n API

    i18n是internationalization 的简写,这里将讨论软件国际化的问题.熟悉软件国际化的朋友应该知道,软件国际化要求,页面中所有用户可见的字符串都必须置于资源属性文件中.资源属性文件中 ...

  9. jQuery之前端国际化jQuery.i18n.properties[转]

    http://www.ibm.com/developerworks/cn/web/1305_hezj_jqueryi18n/ jQuery.i18n.properties是一款轻量级的jQuery国际 ...

随机推荐

  1. 51nod 1510 最小化序列 | DP 贪心

    题目描述 现在有一个长度为n的数组A,另外还有一个整数k.数组下标从1开始. 现在你需要把数组的顺序重新排列一下使得下面这个的式子的值尽可能小. ∑|A[i]−A[i+k]| 特别的,你也可以不对数组 ...

  2. DOS命令(系统错误5,拒绝访问)的解决方法

    在用DOS命令启动MySQL服务时,出现(系统错误5,拒绝访问)的错误提示,这是由于我们操作的权限不足造成的,需要以管理员身份启动,解决问题方法如下: 1."Windows+S"- ...

  3. 阻塞队列BlockingQueue

    BlockingQueue最终会有四种状况,抛出异常.返回特殊值.阻塞.超时,下表总结了这些方法: 抛出异常 特殊值 阻塞 超时 插入 add(e) offer(e) put(e) offer(e, ...

  4. OOAD-设计模式(三)之创建型设计模式(5种)

    前言 前面介绍了OOAD的基础知识,现在我们来详细的说明一下GOF设计模式中的23种模式,希望大家能够学到东西! 一.工厂方法模式(Factory Method) 1.1.工厂方法模式概述 工厂方法模 ...

  5. LeetCode 628. Maximum Product of Three Numbers (最大三数乘积)

    Given an integer array, find three numbers whose product is maximum and output the maximum product. ...

  6. [译]ASP.NET Core 2.0 本地文件操作

    问题 如何在ASP.NET Core 2.0中受限地访问本地目录和文件信息? 答案 新建一个空项目,修改Startup类,添加访问本地文件所需的服务: public void ConfigureSer ...

  7. expected single matching bean but found 2

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'acc ...

  8. 笔记-JDBC和commons-dbutils

    1.前言 玩过Java web的人应该都接触过JDBC,正是有了它,Java程序才能轻松地访问数据库.JDBC很多人都会,但是为什么我还要写它呢?我曾经一度用烂了JDBC,一度认为JDBC不过如此,后 ...

  9. SIP简介,第1部分:SIP初探

    说明:以下内容来着之前下载的一份文档,现将概念部分摘录在BLog,完成文档将放在文件中. SIP简介,第1部分:SIP初探 时间:2006-04-07作者:Emmanuel Proulx浏览次数: 2 ...

  10. (转)Spark JAVA RDD API

    对API的解释: 1.1 transform l  map(func):对调用map的RDD数据集中的每个element都使用func,然后返回一个新的RDD,这个返回的数据集是分布式的数据集 l   ...