Skip to main content

Spring Boot i18n: vodnik za nastavitev internacionalizacije

Nastavite MessageSource, ustvarite datoteke z lastnostmi za posamezne področne nastavitve, razrešujte področne nastavitve in upodabljajte večjezične predloge Thymeleaf, nato pa avtomatizirajte prevode z umetno inteligenco.

1

Dodajte odvisnosti

Spring Boot Starter Web že vključuje samodejno konfiguracijo MessageSource. Dodajte Thymeleaf za strežniško upodobljene predloge i18n in začetni paket za preverjanje veljavnosti za lokalizirana sporočila o napakah.

Spring Boot samodejno nastavi gradnik MessageSource, ki bere datoteko messages.properties na razredni poti. Izrecno konfiguracijo potrebujete le, če želite prilagoditi osnovno ime, kodiranje ali predpomnjenje.
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

Nastavite MessageSource in LocaleResolver

Springov MessageSource nalaga prevode iz datotek .properties po dogovoru o osnovnem imenu: messages.properties (privzeto), messages_de.properties (nemščina), messages_ja.properties (japonščina). Nastavite LocaleResolver, da določite področne nastavitve za posamezno zahtevo.

Prevajalske datoteke

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.

Konfiguracija MessageSource

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;
    }
}
Če prevod namesto prevedenega besedila vrne ime ključa, je najpogostejši vzrok napačno osnovno ime. Privzeta vrednost je 'messages', ki se nanaša na datoteko messages.properties na razredni poti. Če so Vaše datoteke poimenovane drugače ali so v podmapi, izrecno nastavite spring.messages.basename.

Razreševanje področnih nastavitev

Nastavite, kako Spring določi aktivne področne nastavitve za posamezno zahtevo. CookieLocaleResolver ohrani uporabnikovo izbiro med sejami. LocaleChangeInterceptor uporabnikom omogoča preklapljanje področnih nastavitev s poizvedbenim parametrom, kot je ?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

Uporabite prevode v kodi

Do prevedenih sporočil v krmilnikih dostopajte z vbrizgavanjem MessageSource, v predlogah Thymeleaf s skladnjo #{...}, v vmesnikih REST API pa s samodejno razrešenim parametrom Locale.

Krmilnik z 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";
    }
}

Predloge Thymeleaf

Thymeleafov izraz #{...} samodejno razreši ključe sporočil iz Vaših datotek .properties. Parametre posredujte s skladnjo #{key(arg0, arg1)}. Predloga uporabi področne nastavitve, ki jih razreši Vaš LocaleResolver.

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>
Izrazi Thymeleaf, kot je #{greeting('World')}, posredujejo argumente razredu MessageFormat. Statično besedilo znotraj oznak HTML je nadomestna vsebina pri ogledu predloge brez Springa, kar je uporabno za oblikovalce, ki neposredno urejajo predloge.

Lokalizacija vmesnika REST API

Spring za vmesnike REST API samodejno razreši Locale iz glave Accept-Language. Vbrizgajte ga kot parameter metode in ga posredujte MessageSource. Odjemalci preklapljajo med jeziki tako, da pošiljajo različne glave Accept-Language.

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!"}
}
Vmesniki REST API običajno uporabljajo AcceptHeaderLocaleResolver (na podlagi glave), spletne aplikacije pa CookieLocaleResolver (na podlagi piškotka). Če oboje zagotavljate iz iste aplikacije, razmislite o lastnem LocaleResolver, ki najprej preveri piškotke, nato pa uporabi glavo Accept-Language.

Sporočila preverjanja veljavnosti gradnikov

Spring samodejno razreši sporočila omejitev preverjanja veljavnosti iz Vašega MessageSource. V pripisih omejitev uporabite označbe v zavitih oklepajih, kot je {validation.name.required}, prevode pa določite v datotekah .properties.

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

Obravnavajte množinske oblike in spremenljivke

Spring za vstavljanje vrednosti in množinske oblike uporablja java.text.MessageFormat. Vzorec ChoiceFormat obravnava osnovna pravila za množinske oblike, za popolno podporo množinskim oblikam ICU (6 oblik v arabščini, 3 v ruščini) pa dodajte knjižnico ICU4J.

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 ni enak pravilom za množinske oblike ICU. Namesto kategorij CLDR (zero, one, two, few, many, other) uporablja številske razpone (0#, 1#, 1<). Za jezike z zapletenimi pravili za množinske oblike, kot so arabščina, poljščina ali ruščina, ChoiceFormat ne zadošča – uporabite MessageFormat iz ICU4J.

Avtomatizirajte prevode

Ko je nastavitev i18n končana, prevedite datoteke .properties z umetno inteligenco. V svojem razvojnem okolju prosite pomočnika z umetno inteligenco, naj prevede izvorno datoteko, ali pa v cevovodu CI/CD uporabite vmesnik ukazne vrstice i18n Agent.

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
Prevajajte postopoma – ko v messages.properties dodate nove ključe, prevedite samo njih in ne ustvarjajte znova vseh datotek za področne nastavitve. Tako ohranite obstoječe prevode, ki jih je pregledal človek.

Avtomatizirajte zagotavljanje kakovosti prevodov

Z orodjem i18n-validate odkrijte manjkajoče ključe in okvarjene označbe, preden dosežejo uporabnike. Preden so pravi prevodi pripravljeni, preizkusite uporabniški vmesnik s psevdoprevodi, ustvarjenimi z orodjem i18n-pseudo.

Nastavitev brez konfiguracije s spring-locale-chain

spring-locale-chain je odprtokodni začetni paket za Spring Boot, ki z eno odvisnostjo samodejno nastavi LocaleResolver, LocaleChangeInterceptor in preverjanje podprtih področnih nastavitev. Podprte področne nastavitve določite v application.yml, knjižnica pa poskrbi za vse drugo.

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>

Priporočena struktura datotek

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

Pogoste pasti

Znaki zunaj nabora ASCII so prikazani napačno

Datoteke Java .properties privzeto uporabljajo kodiranje ISO-8859-1 in ne UTF-8. Znaki, kot so preglasi (ü) ali znaki CJK, so zato prikazani napačno. Rešitev: v application.yml nastavite spring.messages.encoding=UTF-8 ali v datotekah .properties uporabite ubežna zaporedja Unicode, kot je \u00FC. Spring Bootov ReloadableResourceBundleMessageSource privzeto uporablja UTF-8, ResourceBundleMessageSource pa ne.

ChoiceFormat ne deluje pravilno pri neangleških množinskih oblikah

Javin ChoiceFormat ({0,choice,0#|1#|1<}) podpira samo številske razpone in ne more izraziti množinskih kategorij CLDR, kot sta 'few' ali 'many'. Jeziki, kot so arabščina (6 oblik), poljščina (3 oblike) in ruščina (3 oblike), za pravilno izbiro množinskih oblik potrebujejo ICU4J. Ne predpostavljajte, da ChoiceFormat podpira vse jezike.

Spremembe prevodov niso vidne

ResourceBundleMessageSource privzeto predpomni svežnje za nedoločen čas. Med razvojem uporabite ReloadableResourceBundleMessageSource z nastavitvijo cacheSeconds=0, da bodo spremembe vidne brez ponovnega zagona. V produkciji nastavite razumno trajanje predpomnjenja (npr. 3600 sekund), da uravnotežite zmogljivost in hitrost posodabljanja.

Nepričakovana uporaba področnih nastavitev JVM

Spring privzeto uporabi področne nastavitve JVM (Locale.getDefault()) in ne Vaše datoteke messages.properties. V application.yml nastavite spring.messages.fallback-to-system-locale=false, da se vedno uporabi privzeti sveženj. Sicer bo strežnik s področnimi nastavitvami JVM, nastavljenimi na 'fr', ob manjkajočem ključu v zahtevanih področnih nastavitvah prikazal francoščino namesto angleščine.

Preizkusite i18n Agent zdaj

Spustite prevajalsko datoteko sem

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

ali kliknite za izbiro

Ciljni jeziki

Registracija ni potrebnaTakojšnja ocena

Nadomestne področne nastavitve s spring-locale-chain

Ko v regionalnih področnih nastavitvah, kot je pt-BR, manjka prevajalski ključ, Spring Boot takoj uporabi privzete področne nastavitve, namesto da bi najprej preveril nadrejene področne nastavitve 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

Celoten seznam podprtih ogrodij in 75 vgrajenih verig najdete v našem vodniku po nadomestnih področnih nastavitvah. Learn more →

Pogosta vprašanja