Backend

99 Ngày Spring — Ngày 68: i18n trong Spring

SSite Admin
2 tháng 10, 2026 2 phút đọc 6 lượt xem
99 Ngày Spring — Ngày 68: i18n trong Spring

i18n là cách chọn thông điệp theo locale mà không nhân bản logic nghiệp vụ. Spring cung cấp MessageSource cho bản dịch và LocaleResolver cho ngôn ngữ của request. Với API, cần quyết định rõ nguồn locale, fallback và trường nào được dịch; error code máy đọc nên giữ ổn định.

i18n trong Spring

1. MessageSource và bundle

Spring Boot có thể cấu hình message bundle qua spring.messages.basename. Đặt cùng key trong messages.properties và messages_vi.properties, dùng UTF-8 trong nguồn. Khi gọi getMessage, truyền mã, tham số và locale tường minh ở ranh giới API; key thiếu cần có cách xử lý rõ thay vì vô tình lộ key cho người dùng.

# application.properties
spring.messages.basename=messages
# messages_vi.properties
booking.dateRange.invalid=Ngày kết thúc phải sau ngày bắt đầu

2. Lấy locale của request

AcceptHeaderLocaleResolver đọc Accept-Language; CookieLocaleResolver giữ lựa chọn từ cookie. Chọn một nguồn chính và locale mặc định, tránh lúc dịch thông điệp dùng header còn định dạng ngày dùng cookie. LocaleContextHolder tiện trong request hiện tại, nhưng dữ liệu gắn luồng không tự sang @Async.

@Bean
LocaleResolver localeResolver() {
    var resolver = new AcceptHeaderLocaleResolver();
    resolver.setDefaultLocale(Locale.forLanguageTag("vi"));
    return resolver;
}

3. Dịch lỗi validation

Custom constraint ngày 67 có message key trong dấu ngoặc nhọn. Cấu hình nguồn thông điệp thống nhất cho Bean Validation và ứng dụng, rồi kiểm tra bằng hai request có Accept-Language khác nhau. Trả code như BOOKING_DATE_RANGE cố định, còn detail dịch theo locale; client có thể dựa vào code thay vì dò chuỗi.

String detail = messages.getMessage(
    "booking.dateRange.invalid", null, locale);
problem.setProperty("code", "BOOKING_DATE_RANGE");
problem.setDetail(detail);

4. Fallback và định dạng

Không phải mọi locale đều có bản dịch. Chọn ngôn ngữ mặc định nhất quán và test key thiếu. Số, tiền tệ và ngày cần formatter theo locale, không chỉ thay chuỗi. Ghi nhận locale đã chọn trong response khi API có contract đa ngôn ngữ; không dịch enum hoặc mã dùng trong tích hợp.

  • Test vi, en, thiếu header và key không tồn tại.

  • Dịch detail cho người đọc; giữ code cho máy xử lý.

i18n tốt có một nguồn locale rõ ràng, key ổn định và fallback được kiểm tra. Ngày 69 đưa code lỗi, ProblemDetail và correlation ID thành một hợp đồng chung.

Tài liệu đối chiếu

  • https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-servlet/localeresolver.html

  • https://docs.spring.io/spring-boot/3.5/reference/features/internationalization.html

S

Site Admin

Engineer and writer. Building things with TypeScript and distributed systems.

Bình luận (0)

Bạn cần đăng nhập bằng Google để bình luận.

Hãy là người bình luận đầu tiên.

Bài viết liên quan

99 Ngày Java — Ngày 68: Virtual threads trên Java 21

Phân biệt virtual và platform thread, chọn tác vụ chờ I/O và nhận diện structured concurrency còn preview.

2 thg 10, 20262 phút4
99 Ngày Spring — Ngày 67: Custom validation

Tự viết Bean Validation constraint, kiểm tra liên trường và trả lỗi gắn đúng field.

2 thg 10, 20262 phút7
99 Ngày Java — Ngày 67: Concurrent collections

ConcurrentHashMap, CopyOnWriteArrayList và BlockingQueue: chọn theo kiểu truy cập và giới hạn tải.

2 thg 10, 20262 phút5