preface
The first time you hear the word internationalization, it sounds pretty lofty.
Internationalization What exactly is it?Copy the code
The purpose of internationalization is to enable the same project to run in different regions. Simply put, text or prompt messages on a page can change with the locale.
How is internationalization implemented?Copy the code
Here are the following steps:
- Language saving and switching
- Getting internationalization data
- Unified processing returns the result
The specific implementation
Language saving and switching
To save and switch languages, you need to implement LocaleResolver and LocaleChangeInterceptor. As follows:
@Slf4j
@Configuration
public class I18nConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver(a) {
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
localeResolver.setDefaultLocale(Locale.CHINA);
return localeResolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor(a) {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(localeChangeInterceptor()); }}Copy the code
-
LocaleResolver is used to store languages, where information about languages is stored in cookies, so an off-the-shelf implementation, CookieLocaleResolver, is used. If you need to store the language in Session, use SessionLocaleResolver.
-
LocaleChangeInterceptor is an interceptor used to switch languages. If there is a lang parameter in the request, the language is switched based on that value. The interceptor is placed in the interceptor chain by implementing WebMvcConfigurer’s addInterceptors method.
After implementation, let’s test:
@RestController
@RequestMapping("/language")
public class LanguageController extends BaseController {
@ApiOperation("Switch languages")
@PostMapping("/change")
public ApiResult<String> changeLanguage(@RequestParam(name = "lang") @ApiParam(name = "lang", value = "Language", required = true) String lang) {
// The LocaleChangeInterceptor is already switched, so no action is required here
return getLanguage();
}
@ApiOperation("Get current language")
@GetMapping
public ApiResult<String> getLanguage(a) {
Locale locale = LocaleContextHolder.getLocale();
returnApiResult.success(locale.toString()); }}Copy the code
Call switching language interface: curl -x POST “http://localhost:8080/language/change? lang=en_US”
You can see the language information in the Cookie:
Calls to GET the current language interface: curl -x GET “http://localhost:8080/language” – H “accept: * / *”
The return result can be obtained:
{
"code": 200."data": "en_US"."message": "Success"
}
Copy the code
So far, we have successfully implemented the language save and switch.
The following implementation according to the language to obtain the corresponding internationalization data.
Getting internationalization data
To get the internationalization data, you first need to add the internationalization file. The default file name is messages*.properties, or you can change the file name by setting spring.messages.basename=messages. /resources/i18n/
Store data as key-value pairs in a file.
Default value: messages.properties
Success =API call success fail=API call failureCopy the code
Messages_en_us.properties
success=success
fail=fail
Copy the code
messages_en_us.properties
Success =API call success fail=API call failureCopy the code
I have the internationalization data, I have the language, how do I get the current language data?
Here use ResourceBundleMessageSource file to parse the internationalization, as follows:
@Slf4j
@Configuration
public class I18nConfig{
@Bean
public ResourceBundleMessageSource messageSource(a) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding("UTF-8");
returnmessageSource; }}Copy the code
When data is needed, direct injection is used:
@RestController
@RequestMapping("/message")
public class MessageController {
@Autowired
private MessageSource messageSource;
@ApiOperation("Success")
@GetMapping("/success")
public ApiResult<String> success(a) {
// Get the current language
Locale locale = LocaleContextHolder.getLocale();
// Get the internationalization data according to the Code value and language
String message = messageSource.getMessage(ResultCode.SUCCESS.getMessage(), null, locale);
return new ApiResult<>(ResultCode.SUCCESS.getCode(), null, message);
}
@ApiOperation("Failure")
@GetMapping("/fail")
public ApiResult<String> failure(a) {
Locale locale = LocaleContextHolder.getLocale();
String message = messageSource.getMessage(ResultCode.FAIL.getMessage(), null, locale);
return new ApiResult<>(ResultCode.SUCCESS.getCode(), null, message); }}Copy the code
- LocaleContextHolder.getLocale(); Get the current language
- messageSource.getMessage(); Getting internationalization data
Here we use ResultCode:
@Getter
@AllArgsConstructor
public enum ResultCode {
SUCCESS(200."success"),
FAIL(500."fail");
private Integer code;
private String message;
}
Copy the code
At this point, we can successfully obtain the internationalized data.
However, every request needs to be called. Don’t you think it’s a hassle?
Programmers are not just Ctrl+C and Ctrl+V. Internationalization is usually invoked when the prompt is returned to the front end, and we can solve this problem by uniformly processing the returned results.
Unified processing returns the result
In the article “Uniform base Class, Interface, return object design”, it is agreed that the interface return object is ApiResult, then we just need to intercept the return value, and then unified internationalization can be.
By annotating @ControllerAdvice and implementing the ResponseBodyAdvice interface, we call the beforeBodyWrite method before the data is returned, where we convert the code value into international data. As follows:
@ControllerAdvice
public class ApiResultAdvice implements ResponseBodyAdvice<ApiResult> {
@Autowired
private MessageSource messageSource;
@Override
public boolean supports(MethodParameter returnType, Class
> converterType) {
return returnType.getParameterType().isAssignableFrom(ApiResult.class);
}
@Override
public ApiResult beforeBodyWrite(ApiResult body, MethodParameter returnType, MediaType selectedContentType, Class
> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Locale locale = LocaleContextHolder.getLocale();
String message = messageSource.getMessage(body.getMessage(), null, locale);
body.setMessage(message);
returnbody; }}Copy the code
So once you do that, you don’t need to do it in the Controller.
Call switching language interface: curl -x POST “http://localhost:8080/language/change? lang=en_US”
The result is as follows:
{
"code": 200."data": "en_US"."message": "success"
}
Copy the code
At this point, we are internationalized and do not need to make much change to the previous code. All you need to do is change the original prompt information and other data into the Code value, and then configure the Code value in the internationalization file.
conclusion
First, the LocaleResolver and LocaleChangeInterceptor are used to save and switch languages.
The internationalized data is then read through MessageSource.
Finally, the interface implements uniform handling of returned results by annotating @controllerAdvice and implementing ResponseBodyAdvice.
At this point, the multi-internationalization implementation is complete, and it is as simple to use as possible, with as few changes to the previous code as possible.
Thanks for reading, and if it helps, just click a like!
The source code
Github.com/zhuqianchan…
Review past
- Build backend frameworks from scratch – keep updating