Spring Boot i18n: Vejledning til opsætning af internationalisering
Konfigurer MessageSource, opret landestandardspecifikke properties-filer, fastlæg landestandarder og gengiv flersprogede Thymeleaf-skabeloner — automatiser derefter oversættelser med AI.
Tilføj afhængigheder
Spring Boot Starter Web leveres med automatisk konfiguration af MessageSource. Tilføj Thymeleaf til servergengivne i18n-skabeloner og valideringsstarteren til lokaliserede fejlmeddelelser.
<!-- pom.xml — Spring Boot Starter Web includes MessageSource auto-config -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Thymeleaf for server-side rendered templates with i18n -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Validation (for localized error messages) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>Konfigurer MessageSource og LocaleResolver
Springs MessageSource indlæser oversættelser fra .properties-filer efter konventionen for basisnavne: messages.properties (standard), messages_de.properties (tysk), messages_ja.properties (japansk). Konfigurer en LocaleResolver for at afgøre, hvilken landestandard der skal bruges til hver anmodning.
Oversættelsesfiler
# src/main/resources/messages.properties (default / English)
nav.home=Home
nav.about=About
nav.settings=Settings
greeting=Hello, {0}!
cart.itemCount={0,choice,0#No items|1#1 item|1<{0,number} items}
error.notFound=Page not found
error.serverError=Something went wrong. Please try again.Konfiguration af MessageSource
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@Configuration
public class I18nConfig {
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource source =
new ReloadableResourceBundleMessageSource();
source.setBasename("classpath:messages");
source.setDefaultEncoding("UTF-8");
source.setCacheSeconds(3600); // reload interval in dev
return source;
}
// Wire MessageSource into Bean Validation
@Bean
public LocalValidatorFactoryBean validator(MessageSource messageSource) {
LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
bean.setValidationMessageSource(messageSource);
return bean;
}
}Fastlæggelse af landestandard
Konfigurer, hvordan Spring fastlægger den aktive landestandard for hver anmodning. CookieLocaleResolver gemmer brugerens valg på tværs af sessioner. LocaleChangeInterceptor giver brugerne mulighed for at skifte landestandard via en forespørgselsparameter som ?lang=de.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import java.util.Locale;
@Configuration
public class LocaleConfig implements WebMvcConfigurer {
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver resolver = new CookieLocaleResolver("lang");
resolver.setDefaultLocale(Locale.ENGLISH);
resolver.setCookieMaxAge(3600 * 24 * 365); // 1 year
return resolver;
}
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang"); // ?lang=de switches locale
return interceptor;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}Brug oversættelser i kode
Få adgang til oversatte meddelelser i controllere via injektion af MessageSource, i Thymeleaf-skabeloner med syntaksen #{...} og i REST-API'er med den automatisk fastlagte Locale-parameter.
Controller med MessageSource
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.Locale;
@Controller
public class HomeController {
private final MessageSource messageSource;
public HomeController(MessageSource messageSource) {
this.messageSource = messageSource;
}
@GetMapping("/")
public String home(Model model, Locale locale) {
// Spring injects the resolved Locale automatically
String greeting = messageSource.getMessage(
"greeting",
new Object[]{"World"},
locale
);
model.addAttribute("greeting", greeting);
return "home";
}
}Thymeleaf-skabeloner
Thymeleaf's #{...}-udtryk finder automatisk meddelelsesnøgler i dine .properties-filer. Overfør parametre med syntaksen #{key(arg0, arg1)}. Skabelonen bruger den landestandard, som din LocaleResolver har fastlagt.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="#{nav.home}">Home</title>
</head>
<body>
<!-- Simple message lookup -->
<h1 th:text="#{greeting('World')}">Hello, World!</h1>
<!-- Navigation with i18n -->
<nav>
<a href="/" th:text="#{nav.home}">Home</a>
<a href="/about" th:text="#{nav.about}">About</a>
<a href="/settings" th:text="#{nav.settings}">Settings</a>
</nav>
<!-- Parameterized messages -->
<p th:text="#{cart.itemCount(3)}">3 items</p>
<!-- Language switcher -->
<div>
<a th:href="@{/(lang=en)}">English</a>
<a th:href="@{/(lang=de)}">Deutsch</a>
<a th:href="@{/(lang=ja)}">日本語</a>
</div>
<!-- Conditional text based on locale -->
<p th:if="${#locale.language == 'ja'}"
th:text="#{greeting('ユーザー')}">
こんにちは、ユーザーさん!
</p>
</body>
</html>Lokalisering af REST-API'er
For REST-API'er fastlægger Spring automatisk Locale ud fra Accept-Language-headeren. Injicer den som en metodeparameter og overfør den til MessageSource. Klienter skifter sprog ved at sende forskellige Accept-Language-headere.
import org.springframework.context.MessageSource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Locale;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class ApiController {
private final MessageSource messageSource;
public ApiController(MessageSource messageSource) {
this.messageSource = messageSource;
}
@GetMapping("/greeting/{name}")
public ResponseEntity<Map<String, String>> greeting(
@PathVariable String name,
Locale locale) { // Resolved from Accept-Language header
String msg = messageSource.getMessage(
"greeting", new Object[]{name}, locale
);
return ResponseEntity.ok(Map.of("message", msg));
}
// curl -H "Accept-Language: de" localhost:8080/api/greeting/Max
// → {"message": "Hallo, Max!"}
}Meddelelser fra Bean Validation
Spring finder automatisk meddelelser om valideringsbegrænsninger i din MessageSource. Brug pladsholdere med krøllede parenteser som {validation.name.required} i dine begrænsningsannoteringer og definer oversættelserne i dine .properties-filer.
import jakarta.validation.constraints.*;
public class CreateUserRequest {
@NotBlank(message = "{validation.name.required}")
@Size(min = 2, max = 50, message = "{validation.name.size}")
private String name;
@Email(message = "{validation.email.invalid}")
private String email;
}
// In messages.properties:
// validation.name.required=Name is required
// validation.name.size=Name must be between {min} and {max} characters
// validation.email.invalid=Please enter a valid email address
//
// In messages_de.properties:
// validation.name.required=Name ist erforderlich
// validation.name.size=Name muss zwischen {min} und {max} Zeichen lang sein
// validation.email.invalid=Bitte geben Sie eine gültige E-Mail-Adresse einHåndter flertalsformer og variabler
Spring bruger java.text.MessageFormat til interpolation og flertalsformer. ChoiceFormat-mønstret håndterer grundlæggende flertalsregler, men fuld understøttelse af ICU-flertalsregler (arabisk har 6 former, russisk har 3) kræver ICU4J-biblioteket.
# MessageFormat plural syntax in messages.properties
# Uses java.text.ChoiceFormat — NOT ICU plural rules
cart.itemCount={0,choice,0#No items|1#1 item|1<{0,number} items}
# For more complex plurals, use ICU4J:
# 1. Add dependency: com.ibm.icu:icu4j
# 2. Use ICUMessageSource instead of ResourceBundleMessageSource
#
# Then you can write ICU-style plurals:
# cart.items={count, plural, one {# item} other {# items}}
# Variables with MessageFormat:
welcome.message=Welcome, {0}! You have {1,number} new {1,choice,1#notification|1<notifications}.
order.total=Order total: {0,number,currency}
event.date=Event date: {0,date,long}Automatiser oversættelser
Når din i18n-opsætning er færdig, kan du oversætte dine .properties-filer med AI. Bed din AI-assistent i din IDE om at oversætte kildefilen eller brug i18n Agent CLI i din CI/CD-pipeline.
# Translate your .properties files with AI
# In your IDE, ask your AI assistant:
> Translate src/main/resources/messages.properties to German, Japanese, and Spanish
✓ messages_de.properties created (1.2s)
✓ messages_ja.properties created (1.5s)
✓ messages_es.properties created (1.1s)
# Or use the CLI in CI/CD:
npx i18n-agent translate src/main/resources/messages.properties --lang de,ja,esAutomatiser oversættelseskvaliteten
Konfigurationsfri opsætning med spring-locale-chain
spring-locale-chain er en Spring Boot-starter med åben kildekode, der automatisk konfigurerer LocaleResolver, LocaleChangeInterceptor og validering af understøttede landestandarder gennem én enkelt afhængighed. Definer dine understøttede landestandarder i application.yml, så håndterer biblioteket resten.
<!-- Add spring-locale-chain for zero-config locale resolution -->
<dependency>
<groupId>io.github.i18n-agent</groupId>
<artifactId>spring-locale-chain</artifactId>
<version>1.0.0</version>
</dependency>Anbefalet filstruktur
my-spring-app/
├── src/main/
│ ├── java/com/example/
│ │ ├── config/
│ │ │ ├── I18nConfig.java # MessageSource bean
│ │ │ └── LocaleConfig.java # LocaleResolver + interceptor
│ │ ├── controller/
│ │ │ └── HomeController.java # Uses MessageSource
│ │ └── MyApplication.java
│ └── resources/
│ ├── messages.properties # Default (English)
│ ├── messages_de.properties # German
│ ├── messages_ja.properties # Japanese
│ ├── messages_es.properties # Spanish
│ ├── application.yml # Spring config
│ └── templates/
│ └── home.html # Thymeleaf with #{...}
├── pom.xml
└── build.gradleAlmindelige faldgruber
Ikke-ASCII-tegn vises som ulæselige tegn
ChoiceFormat fungerer ikke med ikke-engelske flertalsformer
Ændringer i oversættelser vises ikke
Uventet fallback til JVM-landestandarden
Prøv i18n Agent nu
Slip din oversættelsesfil her
JSON, YAML, PO, XML, CSV, Markdown, Properties
eller klik for at vælge en fil
Målsprog
Fallback af landestandard med spring-locale-chain
Når en oversættelsesnøgle mangler i en regional landestandard som pt-BR, springer Spring Boot direkte til standardlandestandarden i stedet for først at kontrollere den overordnede landestandard pt.
<!-- Maven -->
<dependency>
<groupId>ai.i18nagent</groupId>
<artifactId>spring-locale-chain</artifactId>
</dependency># application.yml
locale-chain:
fallbacks:
pt-BR:
- pt
- en
zh-Hant-HK:
- zh-Hant
- zh
- enSe vores guide til fallback af landestandarder for at få den komplette liste over understøttede frameworks og 75 indbyggede kæder. Learn more →