Skip to main content

Spring Boot i18n: internacionalizācijas iestatīšanas pamācība

Konfigurējiet MessageSource, izveidojiet lokalizācijām specifiskus properties failus, atrisiniet lokalizācijas un atveidojiet daudzvalodu Thymeleaf veidnes, pēc tam automatizējiet tulkošanu ar MI.

1

Pievienot atkarības

Spring Boot Starter Web uzreiz ietver MessageSource automātisko konfigurāciju. Pievienojiet Thymeleaf serverī atveidotām i18n veidnēm un validācijas sākuma pakotni lokalizētiem kļūdu ziņojumiem.

Spring Boot automātiski konfigurē MessageSource komponentu, kas nolasa messages.properties no klašu ceļa. Skaidra konfigurācija vajadzīga tikai tad, ja vēlaties pielāgot bāzes nosaukumu, kodējumu vai kešošanas uzvedību.
pom.xml
<!-- 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>
2

Konfigurēt MessageSource un LocaleResolver

Spring MessageSource ielādē tulkojumus no .properties failiem pēc bāzes nosaukuma nosacījuma: messages.properties (noklusējums), messages_de.properties (vācu), messages_ja.properties (japāņu). Konfigurējiet LocaleResolver, lai noteiktu katram pieprasījumam izmantojamo lokalizāciju.

Tulkošanas faili

messages.properties
# 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.

MessageSource konfigurācija

I18nConfig.java
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;
    }
}
Ja tulkota teksta vietā tulkojumi atgriež atslēgas nosaukumu, visbiežākais iemesls ir nepareizs bāzes nosaukums. Noklusējums ir 'messages', kas atbilst messages.properties klašu ceļā. Ja faili nosaukti citādi vai atrodas apakšdirektorijā, skaidri iestatiet spring.messages.basename.

Lokalizācijas atrisināšana

Konfigurējiet, kā Spring nosaka aktīvo lokalizāciju katram pieprasījumam. CookieLocaleResolver saglabā lietotāja izvēli starp sesijām. LocaleChangeInterceptor ļauj lietotājiem pārslēgt lokalizācijas ar pieprasījuma parametru, piemēram, ?lang=de.

LocaleConfig.java
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());
    }
}
3

Izmantot tulkojumus kodā

Kontrolleros piekļūstiet tulkotiem ziņojumiem ar MessageSource injicēšanu, Thymeleaf veidnēs — ar #{...} sintaksi, bet REST API — izmantojot automātiski atrisināto Locale parametru.

Kontrolleris ar MessageSource

HomeController.java
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 veidnes

Thymeleaf izteiksme #{...} automātiski atrisina ziņojumu atslēgas no .properties failiem. Nododiet parametrus ar sintaksi #{key(arg0, arg1)}. Veidne izmanto LocaleResolver atrisināto lokalizāciju.

home.html
<!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>
Tādas Thymeleaf izteiksmes kā #{greeting('World')} nodod argumentus MessageFormat. Statiskais teksts HTML tagos kalpo kā atkāpšanās variants, skatot veidni bez Spring — tas noder dizaineriem, kas strādā tieši ar veidnēm.

REST API lokalizācija

REST API gadījumā Spring automātiski atrisina Locale no galvenes Accept-Language. Injicējiet to kā metodes parametru un nododiet MessageSource. Klienti pārslēdz valodu, sūtot dažādas Accept-Language galvenes.

ApiController.java
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!"}
}
REST API parasti izmanto uz galvenēm balstītu AcceptHeaderLocaleResolver, bet tīmekļa lietotnes — uz sīkfailiem balstītu CookieLocaleResolver. Ja abus apkalpojat no vienas lietotnes, apsveriet pielāgotu LocaleResolver, kas vispirms pārbauda sīkfailus un tad atkāpjas uz galveni Accept-Language.

Bean validācijas ziņojumi

Spring automātiski atrisina validācijas ierobežojumu ziņojumus no MessageSource. Ierobežojumu anotācijās izmantojiet figūriekavu vietturus, piemēram, {validation.name.required}, un definējiet tulkojumus .properties failos.

Bean Validation i18n
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 ein
4

Apstrādāt daudzskaitli un mainīgos

Spring interpolācijai un daudzskaitlim izmanto java.text.MessageFormat. ChoiceFormat modelis apstrādā daudzskaitļa pamatkārtulas, taču pilnam ICU daudzskaitļa atbalstam (6 arābu formām, 3 krievu formām) pievienojiet ICU4J bibliotēku.

MessageFormat Plurals
# 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}
ChoiceFormat nav tas pats, kas ICU daudzskaitļa kārtulas. Tas izmanto skaitliskus diapazonus (0#, 1#, 1<), nevis CLDR kategorijas (zero, one, two, few, many, other). Valodām ar sarežģītām daudzskaitļa kārtulām, piemēram, arābu, poļu vai krievu, ChoiceFormat nav pietiekams — izmantojiet ICU4J MessageFormat.

Automatizēt tulkošanu

Kad i18n iestatīšana ir pabeigta, tulkojiet .properties failus ar MI. IDE lūdziet MI asistentam iztulkot avota failu vai izmantojiet i18n Agent CLI CI/CD konveijerā.

Terminal
# 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,es
Tulkojiet pakāpeniski — pievienojot messages.properties jaunas atslēgas, tulkojiet tikai tās, nevis ģenerējiet visus lokalizācijas failus no jauna. Tas saglabā esošajos failos cilvēku pārskatītos tulkojumus.

Automatizēt tulkojumu kvalitāti

Ar i18n-validate pirms izlaišanas atrodiet trūkstošās atslēgas un bojātos vietturus. Kamēr īstie tulkojumi vēl nav gatavi, pārbaudiet UI ar i18n-pseudo pseidotulkojumiem.

Bez konfigurēšanas ar spring-locale-chain

spring-locale-chain ir atvērtā pirmkoda Spring Boot sākuma pakotne, kas ar vienu atkarību automātiski konfigurē LocaleResolver, LocaleChangeInterceptor un atbalstīto lokalizāciju validāciju. Definējiet atbalstītās lokalizācijas application.yml, un bibliotēka paveiks pārējo.

pom.xml
<!-- 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>

Ieteicamā failu struktūra

Project Structure
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.gradle

Biežākās kļūdas

Rakstzīmes ārpus ASCII tiek rādītas nesalasāmi

Java .properties failu noklusējuma kodējums ir ISO-8859-1, nevis UTF-8. Tādas rakstzīmes kā umlauti (ü) vai CJK rakstzīmes tiek rādītas nesalasāmi. Risinājums: application.yml iestatiet spring.messages.encoding=UTF-8 vai .properties failos izmantojiet Unicode atsoļa sekvences, piemēram, \u00FC. Spring Boot ReloadableResourceBundleMessageSource noklusējuma kodējums ir UTF-8, bet ResourceBundleMessageSource — nav.

ChoiceFormat nedarbojas daudzskaitlim ārpus angļu valodas

Java ChoiceFormat ({0,choice,0#|1#|1<}) atbalsta tikai skaitliskus diapazonus — tas nevar izteikt tādas CLDR daudzskaitļa kategorijas kā 'few' vai 'many'. Tādām valodām kā arābu (6 formas), poļu (3 formas) un krievu (3 formas) pareizam daudzskaitlim vajadzīgs ICU4J. Neuzskatiet, ka ChoiceFormat apstrādā visas valodas.

Tulkojumu izmaiņas neparādās

Pēc noklusējuma ResourceBundleMessageSource komplektus kešo bezgalīgi. Izstrādes laikā izmantojiet ReloadableResourceBundleMessageSource ar cacheSeconds=0, lai redzētu izmaiņas bez restartēšanas. Produkcijas vidē iestatiet saprātīgu keša ilgumu (piemēram, 3 600 sekundes), lai līdzsvarotu veiktspēju un atjaunināšanas ātrumu.

Negaidīta atkāpšanās uz JVM lokalizāciju

Pēc noklusējuma Spring atkāpjas uz JVM noklusējuma lokalizāciju (Locale.getDefault()), nevis messages.properties failu. application.yml iestatiet spring.messages.fallback-to-system-locale=false, lai vienmēr izmantotu noklusējuma komplektu. Citādi serveris ar JVM lokalizāciju 'fr' rādīs franču, nevis angļu valodu, ja pieprasītajā lokalizācijā trūkst atslēgas.

Izmēģiniet i18n Agent tūlīt

Nometiet tulkošanas failu šeit

JSON, YAML, PO, XML, CSV, Markdown, Properties

vai noklikšķiniet, lai izvēlētos

Mērķa valodas

Reģistrācija nav vajadzīgaTūlītēja tāme

Lokalizācijas atkāpšanās ar spring-locale-chain

Ja reģionālajā lokalizācijā, piemēram, pt-BR, trūkst tulkojuma atslēgas, Spring Boot uzreiz pāriet uz noklusējuma lokalizāciju, nevis vispirms pārbauda vecāklokalizāciju pt.

Terminal
<!-- Maven -->
<dependency>
  <groupId>ai.i18nagent</groupId>
  <artifactId>spring-locale-chain</artifactId>
</dependency>
Configuration
# application.yml
locale-chain:
  fallbacks:
    pt-BR:
      - pt
      - en
    zh-Hant-HK:
      - zh-Hant
      - zh
      - en

Pilnu atbalstīto sistēmu sarakstu un 75 iebūvētās ķēdes skatiet mūsu lokalizāciju atkāpšanās ceļvedī. Learn more →

Bieži uzdotie jautājumi