Page internationalization

Sometimes, our website will involve Chinese and English or even multi-language switch, this time we need to learn internationalization!

1. Preparation

First set the coding problem of properties in IDEA.Write an internationalization profile to extract the internationalization page messages that the page needs to display. We can go to the login page and see what configuration we need to write for internationalization!


2. Write configuration files

1. Create an i18N directory under resources to store the internationalization configuration files

What is I18n?

  • Similarly, the K8S

Create a login.properties file and a login_zh_CN. Properties file.

Three new configuration files are created to configure the language:

  • Login. properties: takes effect when no language is configured

  • Login_en_us. properties: Valid in English

  • Login_zh_CN. Properties: Valid in Chinese

The names are combinations of underscores: filename _ language _ country. Properties;

We find that IDEA automatically recognizes that we need to do international operations; The folder has changed!

After binding together, we want to add more over the language configuration, just in the large resource packRight-click to add to the binding configuration fileCan beThe following page pops up: Let’s add another English one;At this time only need to enter the name of the region can be created successfully, such as enter en_US, it will be automatically recognized, so much faster!


Then open the English or Chinese language configuration file and click on the Resource Bundle to enter the visual editing pageAfter entering the visual editing page, click the plus sign to add attributes. First, create a login.tip to represent the prompt on the home pageThen do the language configuration for the prompt in three cases respectively, and enter the corresponding input boxes (note: IDEA2020.1 may not save, it is recommended to write in the configuration file directly).Double-clicking opens atlogin.tipWe can find visual configuration is very convenient, you can configure 3 at once

Next, configure all the variables for the language to be converted (note: IDEA2020.1 may not save, it is recommended to write directly in the configuration file)Then open the three configuration files to check the text content, you can see that all the configuration is done

Then go to our configuration file;

The login. The properties: the default

Password = password login.remember= remember me login.tip= please login login.username= usernameCopy the code

English:

login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username
Copy the code

English:

Password = password login.remember= remember me login.tip= please login login.username= usernameCopy the code

OK, configuration file step done!


3. Check whether the configuration file takes effect

In the Spring in the program, the internationalization mainly through ResourceBundleMessageSource this class

Spring Boot by MessageSourceAutoConfiguration as we automatic configuration management component of internationalized resource file

In our IDEA, we view the following MessageSourceAutoConfiguration class

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {

	private static final Resource[] NO_RESOURCES = {};

	@Bean
	@ConfigurationProperties(prefix = "spring.messages")
	public MessageSourceProperties messageSourceProperties(a) {
		return new MessageSourceProperties();
	}

	@Bean
	public MessageSource messageSource(MessageSourceProperties properties) {
		ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
		if (StringUtils.hasText(properties.getBasename())) {
		   // He can set our Basenames basic name
			messageSource.setBasenames(StringUtils
			         // Then he will look for it from properties.getBasename(), our config file
					.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
		}
		if(properties.getEncoding() ! =null) {
			messageSource.setDefaultEncoding(properties.getEncoding().name());
		}
		messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
		Duration cacheDuration = properties.getCacheDuration();
		if(cacheDuration ! =null) {
			messageSource.setCacheMillis(cacheDuration.toMillis());
		}
		messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
		messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
		return messageSource;
	}
	/ /...
}
Copy the code

MessageSource ()

public MessageSource messageSource(MessageSourceProperties properties);
Copy the code

As you can see, it takes the MessageSourceProperties object, so let’s look at this class

public class MessageSourceProperties {

	/** * Comma-separated list of basenames (essentially a fully-qualified classpath * location), each following the ResourceBundle convention with relaxed support for * slash based locations. If it doesn't contain a package qualifier (such as * "org.mypackage"), it will be resolved from the classpath root. */
	private String basename = "messages";

	/** * Message bundles encoding. */
	private Charset encoding = StandardCharsets.UTF_8;
Copy the code

The class first declares a property basename, which defaults to messages;

We translate the notes:

	/** * Comma-separated list of basenames (essentially a fully-qualified classpath * location), each following the ResourceBundle convention with relaxed support for * slash based locations. If it doesn't contain a package qualifier (such as * "org.mypackage"), it will be resolved from the classpath root. */
Copy the code
  • Comma-separated list of base names (essentially fully qualified classpath locations)

  • Each follows the ResourceBundle convention and is easily supported at the location of the slash

  • If the package qualifier is not included (for example, “org.mypackage”), it will be resolved from the classpath root

It means:

  • If you do not specify in the SpringBoot configuration file. Separate the name of the internationalized resource file

  • By default, it goes to the classpath to find messages.properties as the internationalization resource file

Here we have customized the internationalization resource file, so we need to specify the name of our configuration file by adding the following configuration to the SpringBoot configuration file application.properties

# The real location of our configuration file
spring.messages.basename=i18n.login
Copy the code

I18n is the name of the folder where the resource is stored, and login is the basic name of the resource file.


4. Obtain the displayed internationalized value on the home page

Go to the page to obtain the value of internationalization, check the documentation of Thymeleaf, find the value of message: #{… }. Let’s go to the page to test:

IDEA and hints, very intelligent!

Use # {… } message expression, go to the home index. HTML to get the internationalized value, not in <>, use #[[#{}]]

<! DOCTYPEhtml>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>The login page</title>
		<! -- Bootstrap core CSS -->
		<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
		<! -- Custom styles for this template -->
		<link th:href="@{/css/signin.css}" rel="stylesheet">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only">Username</label>
			<input type="text" class="form-control" th:text="#{login.username}" placeholder="Username..." required="" autofocus="">
			<label class="sr-only">Password</label>
			<input type="password" class="form-control" th:text="#{login.password}" placeholder="Password..." required="">
			<div class="checkbox mb-3">
				<label>
          <input type="checkbox" value="remember-me" th:text="#{login.remember}">&nbsp;&nbsp;Remeember me
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.btn}">Sign in</button>
			<p class="mt-5 mb-3 text-muted">© 2020-2021</p>
			<a class="btn btn-sm">Chinese</a>
			<a class="btn btn-sm">English</a>
		</form>
	</body>
</html>
Copy the code

Restart the project, visit the home page, found that it has been automatically identified as Chinese!But we want better! Can automatically switch between Chinese and English according to the button!


5. Configure internationalization parsing to switch between Chinese and English

There is an internationalized Locale in Spring; There’s a parser in there called LocaleResolver (Get locale information object)!

Think: what does HTML lang=”en” or HTML lang=” en-us “mean

The HTML lang attribute is used to declare the language type,,,,,


<html lang="en"></html>/ / English<html lang="zh-CN"></html>/ / Chinese<html lang="ja"></html>/ / Japanese<html lang="en-US"></html>// American English<div lang="en">this is English .</div>/ / EnglishCopy the code

The lang attribute, written in the HTML tag, declares the language type of the current page, which is instructive for search engines, web page translation, and screen reading browsers.


1. Add a link to switch labels in Both Chinese and English

The login page is displayed in Chinese, and we can see two tags in the index.html page

<a class="btn btn-sm">Chinese</a>
<a class="btn btn-sm">English</a>
Copy the code

That corresponds to the viewSo how do we switch between Chinese and English through these two tags?

First add jump links and parameters to the two tags

<! Don't use the passed parameter here? Use the key = value -- -- >
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">Chinese</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
Copy the code

2. Customize the locale parser component

How to implement our custom locale parser? Let’s start by analyzing a wave of source code

There are two classes for internationalization in Spring:

  • Locale: indicates the region, each oneLocaleObjects represent a particular geographic, political, and cultural region
  • LocaleResolver: the locale parser

Start by searching WebMvcAutoConfiguration, where you can find localeResolver() about a method

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver(a) {
    // If the user is configured, the user is used
   if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
      return new FixedLocaleResolver(this.mvcProperties.getLocale());
   }
    // If the user is not configured, use the default
   AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
   localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
   return localeResolver;
}
Copy the code

This method is to get the LocaleResolver locale object parser:

  • If the user is configured, the user configured locale parser is used.
  • If not configured by the user, the default locale parser is used

We can see that the default locale parser isAcceptHeaderLocaleResolverObject, we click into the class to view the sourceYou can see that it inherits the LocaleResolver interface and implements locale resolution

Therefore, to implement the above custom internationalization resources, we simply need to write our own locale parser, inherit the LocaleResolver interface, and override its methods.

We created MyLocaleResolver under the Config package as our internationalization locale parser

We wrote the corresponding request jump in index.html

  • If you click the Chinese button, you go to the /index.html(l=’zh_CN’) page

  • If you click the English button, you go to the /index.html(l=’en_US’) page

<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}"< p style = "max-width: 100%; clear: both; min-height: 1emclass="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
Copy the code

So our custom locale parser, MyLocaleResolver, needs to handle these two link requests with parameters

package com.cy.config;

import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;


public class MyLocaleResolver implements LocaleResolver {

    // Parse the request
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        // Get the internationalization parameters in the request
        String language = request.getParameter("l");
        // The default locale
        Locale locale = Locale.getDefault();
        // If the requested link parameter is not empty, it carries an internationalization parameter
       if(! StringUtils.isEmpty(language)){/ / the split space
           String[] split = language.split("_");
           //zh_CN(language-region)
           locale = new Locale(split[0], split[1]);
       }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {}}Copy the code

In order for our regionalization information to work, we need to configure this component again! Add beans under your MvcConofig configuration class;

// Custom internationalized components take effect
@Bean
public LocaleResolver localeResolver(a) {
    return new MyLocaleResolver();
}
Copy the code

Let’s restart the project, visit, and find that clicking the button can achieve a successful switch!

Click the Chinese button to jump tohttp://localhost:8080/index.html?l=zh_CN, shown as Chinese

Click on theEnglishButton to jump tohttp://localhost:8080/index.html?l=en_US, shows in English: