Skip to main content

Spring Boot i18n: अंतर्राष्ट्रीयकरण सेटअप ट्यूटोरियल

MessageSource कॉन्फ़िगर करें, लोकेल-विशिष्ट प्रॉपर्टीज़ फ़ाइलें बनाएँ, लोकेल निर्धारित करें और बहुभाषी Thymeleaf टेम्पलेट रेंडर करें — फिर AI से अनुवाद स्वचालित करें।

1

डिपेंडेंसी जोड़ें

Spring Boot Starter Web में MessageSource का ऑटो-कॉन्फ़िगरेशन पहले से शामिल होता है। सर्वर पर रेंडर होने वाले i18n टेम्पलेट के लिए Thymeleaf और स्थानीयकृत त्रुटि संदेशों के लिए validation starter जोड़ें।

Spring Boot अपने आप एक MessageSource bean कॉन्फ़िगर करता है, जो classpath पर मौजूद messages.properties से संदेश पढ़ता है। यदि आप basename, encoding या caching व्यवहार को कस्टमाइज़ करना चाहते हैं, तभी आपको स्पष्ट कॉन्फ़िगरेशन की आवश्यकता होगी।
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

MessageSource और LocaleResolver कॉन्फ़िगर करें

Spring का MessageSource basename परंपरा का उपयोग करके .properties फ़ाइलों से अनुवाद लोड करता है: messages.properties (डिफ़ॉल्ट), messages_de.properties (जर्मन), messages_ja.properties (जापानी)। हर अनुरोध के लिए किस लोकेल का उपयोग करना है, यह निर्धारित करने के लिए LocaleResolver कॉन्फ़िगर करें।

अनुवाद फ़ाइलें

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 कॉन्फ़िगरेशन

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;
    }
}
यदि अनुवादित टेक्स्ट के बजाय key का नाम लौटता है, तो सबसे आम कारण गलत basename होता है। डिफ़ॉल्ट basename 'messages' है, जो classpath पर मौजूद messages.properties से मैप होता है। यदि आपकी फ़ाइलों के नाम अलग हैं या वे किसी सबडायरेक्टरी में हैं, तो spring.messages.basename को स्पष्ट रूप से सेट करें।

लोकेल निर्धारण

कॉन्फ़िगर करें कि Spring हर अनुरोध के लिए सक्रिय लोकेल कैसे निर्धारित करे। CookieLocaleResolver सभी सेशन में यूज़र की पसंद बनाए रखता है। LocaleChangeInterceptor यूज़र को ?lang=de जैसे query parameter से लोकेल बदलने देता है।

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

कोड में अनुवादों का उपयोग करें

controllers में MessageSource injection के माध्यम से, Thymeleaf templates में #{...} syntax के साथ और REST APIs में अपने आप निर्धारित होने वाले Locale parameter का उपयोग करके अनुवादित संदेश प्राप्त करें।

MessageSource वाला Controller

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 टेम्पलेट

Thymeleaf का #{...} expression आपकी .properties फ़ाइलों से message keys अपने आप निर्धारित करता है। #{key(arg0, arg1)} syntax से parameters पास करें। टेम्पलेट आपके 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>
#{greeting('World')} जैसे Thymeleaf expressions, MessageFormat को arguments पास करते हैं। HTML tags के अंदर मौजूद static text, Spring के बिना टेम्पलेट देखते समय fallback के रूप में काम करता है — यह सीधे टेम्पलेट पर काम करने वाले डिज़ाइनरों के लिए उपयोगी है।

REST API स्थानीयकरण

REST APIs के लिए Spring, Accept-Language header से Locale अपने आप निर्धारित करता है। इसे method parameter के रूप में inject करें और MessageSource को पास करें। अलग-अलग Accept-Language headers भेजकर clients भाषा बदल सकते हैं।

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 APIs आम तौर पर AcceptHeaderLocaleResolver (header-आधारित) का उपयोग करते हैं, जबकि web apps CookieLocaleResolver (cookie-आधारित) का उपयोग करते हैं। यदि आप दोनों को एक ही app से उपलब्ध कराते हैं, तो ऐसा custom LocaleResolver उपयोग करने पर विचार करें जो पहले cookies जाँचे और फिर fallback के रूप में Accept-Language header का उपयोग करे।

Bean Validation संदेश

Spring आपके MessageSource से validation constraint messages अपने आप निर्धारित करता है। अपने constraint annotations में {validation.name.required} जैसे curly-brace placeholders का उपयोग करें और अनुवादों को अपनी .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

बहुवचन और वेरिएबल संभालें

Spring interpolation और बहुवचन के लिए java.text.MessageFormat का उपयोग करता है। ChoiceFormat pattern सामान्य बहुवचन नियमों को संभालता है, लेकिन संपूर्ण ICU plural support (अरबी के 6 रूप, रूसी के 3 रूप) के लिए ICU4J library जोड़ें।

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, ICU plural rules के समान नहीं है। यह CLDR categories (zero, one, two, few, many, other) के बजाय numeric ranges (0#, 1#, 1<) का उपयोग करता है। अरबी, पोलिश या रूसी जैसी जटिल बहुवचन नियमों वाली भाषाओं के लिए ChoiceFormat पर्याप्त नहीं है — इसके बजाय ICU4J के MessageFormat का उपयोग करें।

अनुवाद स्वचालित करें

अपना i18n सेटअप पूरा करने के बाद AI का उपयोग करके अपनी .properties फ़ाइलों का अनुवाद करें। अपने IDE में अपने AI assistant से source file का अनुवाद करने के लिए कहें या अपनी CI/CD pipeline में i18n Agent CLI का उपयोग करें।

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
अनुवाद क्रमिक रूप से करें — messages.properties में नई keys जोड़ने पर सभी locale files दोबारा बनाने के बजाय केवल नई keys का अनुवाद करें। इससे मौजूदा फ़ाइलों में मानव द्वारा जाँचे गए अनुवाद सुरक्षित रहते हैं।

अनुवाद की गुणवत्ता स्वचालित रूप से सुनिश्चित करें

i18n-validate से रिलीज़ से पहले गायब keys और खराब placeholders पकड़ें। वास्तविक अनुवाद उपलब्ध होने से पहले i18n-pseudo से pseudo-translations का उपयोग करके अपने UI का परीक्षण करें।

spring-locale-chain के साथ बिना कॉन्फ़िगरेशन के शुरुआत करें

spring-locale-chain एक open-source Spring Boot starter है, जो एक ही dependency से LocaleResolver, LocaleChangeInterceptor और supported-locale validation को अपने आप कॉन्फ़िगर करता है। application.yml में अपने समर्थित locales परिभाषित करें और बाकी काम library संभाल लेगी।

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>

सुझाई गई फ़ाइल संरचना

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

आम समस्याएँ

Non-ASCII वर्ण विकृत टेक्स्ट के रूप में दिखाई देते हैं

Java की .properties फ़ाइलें डिफ़ॉल्ट रूप से UTF-8 के बजाय ISO-8859-1 encoding का उपयोग करती हैं। umlauts (ü) या CJK characters जैसे वर्ण विकृत टेक्स्ट के रूप में रेंडर होते हैं। समाधान: application.yml में spring.messages.encoding=UTF-8 सेट करें या अपनी .properties फ़ाइलों में \u00FC जैसे Unicode escapes का उपयोग करें। Spring Boot का ReloadableResourceBundleMessageSource डिफ़ॉल्ट रूप से UTF-8 का उपयोग करता है, लेकिन ResourceBundleMessageSource नहीं करता।

गैर-अंग्रेज़ी बहुवचनों के साथ ChoiceFormat काम नहीं करता

Java का ChoiceFormat ({0,choice,0#|1#|1<}) केवल numeric ranges का समर्थन करता है — यह 'few' या 'many' जैसी CLDR plural categories व्यक्त नहीं कर सकता। अरबी (6 रूप), पोलिश (3 रूप) और रूसी (3 रूप) जैसी भाषाओं में सही pluralization के लिए ICU4J आवश्यक है। यह न मानें कि ChoiceFormat सभी भाषाओं को संभाल सकता है।

अनुवाद में किए गए बदलाव दिखाई नहीं देते

ResourceBundleMessageSource डिफ़ॉल्ट रूप से bundles को अनिश्चित काल तक cache करता है। development के दौरान, restart किए बिना बदलाव देखने के लिए cacheSeconds=0 के साथ ReloadableResourceBundleMessageSource का उपयोग करें। production में performance और update speed के बीच संतुलन बनाए रखने के लिए उचित cache duration (जैसे 3600 seconds) सेट करें।

अनपेक्षित रूप से JVM Locale का fallback उपयोग होता है

डिफ़ॉल्ट रूप से Spring आपकी messages.properties फ़ाइल के बजाय JVM के default locale (Locale.getDefault()) का fallback के रूप में उपयोग करता है। हमेशा default bundle का उपयोग करने के लिए application.yml में spring.messages.fallback-to-system-locale=false सेट करें। अन्यथा, यदि server का JVM locale 'fr' पर सेट है, तो माँगे गए locale में कोई key गायब होने पर अंग्रेज़ी के बजाय फ़्रेंच दिखाई देगी।

i18n Agent अभी आज़माएँ

अपनी अनुवाद फ़ाइल यहाँ छोड़ें

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

या ब्राउज़ करने के लिए क्लिक करें

लक्षित भाषाएँ

साइन अप की ज़रूरत नहींतुरंत अनुमान

spring-locale-chain के साथ Locale Fallback

जब pt-BR जैसे regional locale में कोई translation key गायब होती है, तो Spring Boot पहले parent locale pt को जाँचने के बजाय सीधे default locale पर चला जाता है।

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

समर्थित frameworks और पहले से मौजूद 75 chains की पूरी सूची के लिए हमारी Locale Fallback Guide देखें। Learn more →

अक्सर पूछे जाने वाले प्रश्न