Skip to main content

Spring Boot i18n: Oppsettveiledning for internasjonalisering

Konfigurer MessageSource, opprett språkspesifikke properties-filer, fastsett språkinnstillingen og vis flerspråklige Thymeleaf-maler — automatiser deretter oversettelser med AI.

1

Legg til avhengigheter

Spring Boot Starter Web inkluderer automatisk konfigurasjon av MessageSource. Legg til Thymeleaf for serverrenderte i18n-maler, og validation-starteren for lokaliserte feilmeldinger.

Spring Boot konfigurerer automatisk en MessageSource-bean som leser fra messages.properties på classpath. Du trenger bare eksplisitt konfigurasjon hvis du vil tilpasse basename, tegnkoding eller mellomlagringsatferd.
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

Konfigurer MessageSource og LocaleResolver

Springs MessageSource laster oversettelser fra .properties-filer ved hjelp av basename-konvensjonen: messages.properties (standard), messages_de.properties (tysk), messages_ja.properties (japansk). Konfigurer en LocaleResolver for å bestemme hvilken språkinnstilling som skal brukes for hver forespørsel.

Oversettelsesfiler

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-konfigurasjon

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;
    }
}
Hvis oversettelser returnerer nøkkelnavnet i stedet for den oversatte teksten, er den vanligste årsaken feil basename. Standarden er «messages», som tilsvarer messages.properties på classpath. Hvis filene dine har andre navn eller ligger i en underkatalog, sett spring.messages.basename eksplisitt.

Valg av språkinnstilling

Konfigurer hvordan Spring bestemmer den aktive språkinnstillingen for hver forespørsel. CookieLocaleResolver bevarer brukerens valg på tvers av økter. LocaleChangeInterceptor lar brukere bytte språkinnstilling via en spørreparameter som ?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

Bruk oversettelser i kode

Få tilgang til oversatte meldinger i kontrollere via MessageSource-injeksjon, i Thymeleaf-maler med #{...}-syntaksen, og i REST-API-er ved hjelp av den automatisk løste Locale-parameteren.

Kontroller med 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-maler

Thymeleafs #{...}-uttrykk slår automatisk opp meldingsnøkler i .properties-filene dine. Send parametere med #{key(arg0, arg1)}-syntaksen. Malen bruker språkinnstillingen som LocaleResolver har valgt.

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>
Thymeleaf-uttrykk som #{greeting('World')} sender argumenter til MessageFormat. Den statiske teksten inni HTML-taggene fungerer som en reserveløsning når malen vises uten Spring — nyttig for designere som jobber direkte med malene.

Lokalisering av REST-API

For REST-API-er fastsetter Spring automatisk Locale fra Accept-Language-hodet. Injiser den som en metodeparameter og send den videre til MessageSource. Klienter bytter språk ved å sende ulike Accept-Language-hoder.

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-er bruker vanligvis AcceptHeaderLocaleResolver (headerbasert), mens webapper bruker CookieLocaleResolver (informasjonskapselbasert). Hvis du serverer begge fra samme app, bør du vurdere en tilpasset LocaleResolver som sjekker informasjonskapsler først og deretter faller tilbake til Accept-Language-headeren.

Bean Validation-meldinger

Spring løser automatisk valideringsmeldinger for begrensninger fra din MessageSource. Bruk plassholdere med krøllparenteser som {validation.name.required} i begrensningsannotasjonene dine, og definer oversettelsene i .properties-filene dine.

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

Håndter flertallsformer og variabler

Spring bruker java.text.MessageFormat for interpolasjon og flertallsformer. ChoiceFormat-mønsteret håndterer grunnleggende flertallsregler, men for full ICU-flertallsstøtte (arabiskens 6 former, russiskens 3) må du legge til ICU4J-biblioteket.

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 er ikke det samme som ICU-flertallsregler. Det bruker numeriske intervaller (0#, 1#, 1<) i stedet for CLDR-kategorier (zero, one, two, few, many, other). For språk med komplekse flertallsregler som arabisk, polsk eller russisk er ChoiceFormat utilstrekkelig — bruk ICU4Js MessageFormat i stedet.

Automatiser oversettelser

Når i18n-oppsettet ditt er fullført, kan du oversette .properties-filene dine ved hjelp av AI. I IDE-en din kan du be AI-assistenten om å oversette kildefilen, eller bruke i18n Agent CLI i CI/CD-pipelinen din.

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
Oversett trinnvis — når du legger til nye nøkler i messages.properties, oversett bare de nye nøklene i stedet for å regenerere alle språkfilene. Dette bevarer eventuelle manuelt kvalitetssikrede oversettelser i eksisterende filer.

Automatiser oversettelseskvalitet

Fang opp manglende nøkler og ødelagte plassholdere før de driftsettes med i18n-validate. Test brukergrensesnittet ditt med pseudo-oversettelser ved hjelp av i18n-pseudo før de virkelige oversettelsene er klare.

Nullkonfigurasjon med spring-locale-chain

spring-locale-chain er en Spring Boot-starter med åpen kildekode som automatisk konfigurerer LocaleResolver, LocaleChangeInterceptor og validering av støttede språkinnstillinger gjennom én enkelt avhengighet. Definer de støttede språkinnstillingene i application.yml, så håndterer biblioteket resten.

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>

Anbefalt filstruktur

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

Vanlige fallgruver

Ikke-ASCII-tegn vises som rot

Java .properties-filer bruker som standard ISO-8859-1-tegnkoding, ikke UTF-8. Tegn som umlyd (ü) eller CJK-tegn vises som rot. Løsning: sett spring.messages.encoding=UTF-8 i application.yml, eller bruk Unicode-escapetegn som \u00FC i .properties-filene dine. Spring Boots ReloadableResourceBundleMessageSource bruker UTF-8 som standard, men det gjør ikke ResourceBundleMessageSource.

ChoiceFormat feiler for flertallsformer utenom engelsk

Javas ChoiceFormat ({0,choice,0#|1#|1<}) støtter bare numeriske intervaller — det kan ikke uttrykke CLDR-flertallskategorier som 'few' eller 'many'. Språk som arabisk (6 former), polsk (3 former) og russisk (3 former) trenger ICU4J for korrekt flertallsbøying. Ikke anta at ChoiceFormat håndterer alle språk.

Oversettelsesendringer vises ikke

ResourceBundleMessageSource mellomlagrer ressurspakker på ubestemt tid som standard. Under utvikling kan du bruke ReloadableResourceBundleMessageSource med cacheSeconds=0 for å se endringer uten omstart. I produksjon bør du sette en fornuftig mellomlagringsvarighet (f.eks. 3600 sekunder) for å balansere ytelse og oppdateringshastighet.

Uventet tilbakefall til JVM-locale

Som standard faller Spring tilbake til JVM-ens standardinnstilling for språk (Locale.getDefault()), ikke messages.properties-filen din. Sett spring.messages.fallback-to-system-locale=false i application.yml for alltid å bruke standardressurspakken. Ellers vil en server med JVM-språket satt til 'fr' vise fransk i stedet for engelsk når en nøkkel mangler for den forespurte språkinnstillingen.

Prøv i18n Agent nå

Slipp oversettelsesfilen din her

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

eller klikk for å bla gjennom

Målspråk

Ingen registrering krevesUmiddelbart estimat

Språkfallback med spring-locale-chain

Når en oversettelsesnøkkel mangler for en regional språkinnstilling som pt-BR, hopper Spring Boot rett til standardspråket i stedet for først å sjekke det overordnede språket 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

Se guiden vår for språkfallback for den fullstendige listen over støttede rammeverk og 75 innebygde kjeder. Learn more →

Ofte stilte spørsmål