Trong thời đại toàn cầu hóa, việc xây dựng ứng dụng web hỗ trợ đa ngôn ngữ không chỉ là một lợi thế cạnh tranh mà còn là yếu tố thiết yếu để tiếp cận và phục vụ người dùng từ khắp nơi trên thế giới. I18n mang đến giải pháp hoàn hảo để xây dựng các ứng dụng web đa ngôn ngữ một cách dễ dàng và hiệu quả. ## 1. Khái niệm Internationalization (i18n) là quá trình thiết kế và phát triển một ứng dụng phần mềm sao cho nó có thể dễ dàng thích nghi với các ngôn ngữ, khu vực và văn hóa khác nhau mà không cần thay đổi mã nguồn cốt lõi. "i" là chữ cái đầu, "n" là chữ cái cuối của từ "Internationalization", "18" biểu thị số chữ cái ở giữa (từ chữ thứ 2 đến chữ thứ 18). Cho phép ứng dụng hỗ trợ nhiều ngôn ngữ Ví dụ: tiếng Anh, tiếng Việt, tiếng Pháp. Đáp ứng các định dạng địa phương ngày tháng, tiền tệ, v.v.. Tăng tính tiếp cận và trải nghiệm người dùng trên toàn cầu. ## 2. Sử dụng trong tệp HTML - Tạo các tệp ngôn ngữ `message_.properties` trong thư mục `src/main/resources/messages`. Lưu ý tệp `messages.properties` sẽ là tệp mặc định và bằng tiếng anh. locale đây là một khu vực địa lý hoặc văn hóa cụ thể. Nó thường là một ký hiệu ngôn ngữ được theo sau bởi một ký hiệu quốc gia, phân biệt nhau bởi dấu gạch dưới. Ví dụ: en_US biểu diễn English locale cho US Tên ngôn ngữ được ký hiệu bằng 2 chữ cái thông qua bảng [sau](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) - Sử dụng `[[#{message_key}]]` nếu trong phương pháp thẻ, ngoài ra còn có thể sử dụng `th:="#{message_key}"` Ví dụ: `[[#{message_key}]]`, `` - Nếu khóa thông báo của bạn là một biến, bạn có thể sử dụng `[[#{${tên_biến}}]]` bên trong thẻ hoặc `${tên_biến}` bên trong thuộc tính. - Nếu khóa thông báo của bạn có tham số ví dụ `hello=Hello {0} {1}` bạn có thể sử dụng bên trong thẻ: `[[${#messages.msg('message_key', value0, value1)}]]`hoặc bên trong thuộc tính: `${#messages.msg('message_key', value0, value1)}` - Nếu bạn muốn chuyển đổi thông báo thành chữ thường, bạn có thể sử dụng bên trong thẻ: `[[${#strings.toLowerCase(#messages.msg('message_key'))}]]` hoặc bên trong thuộc tính: `${#strings.toLowerCase(#messages.msg('message_key'))}` -Đối với các thông báo có định dạng HTML, bạn có thể sử dụng thuộc tính `th:utext` ví dụ: `

` Bạn có thể tham khảo tài liệu Thymeleaf để biết thêm [chi tiết](https://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf.html#using-texts) ## 3. Sử dụng trong JavaScript - Đối với admin, chúng ta cần sử dụng bên trong thẻ ` ``` - Đối với web, chúng ta cũng cần sử dụng bên trong thẻ ` ``` ## 4. Ví dụ ![15.png](/api/v1/media/c8e055a5f5bcfc1ebfdfc9c153280470dc23495adaf9087a34697c7ac603bc1d.png) - Người dùng truy cập URL http://localhost:8080/login Hành động: Gửi yêu cầu GET đến /login. Xử lý: LoginController.loginGet được gọi. Nhận tham số lang (mặc định = "en") và error (mặc định = rỗng). Trả về View: Template: user-login.html. Biến: lang (ngôn ngữ), error (có lỗi hay không). Kết quả: Trang đăng nhập hiển thị với ngôn ngữ mặc định (tiếng Anh). - Người dùng chuyển đổi ngôn ngữ Hành động: Nhấp vào liên kết "Tiếng Việt" (/login?lang=vi) hoặc "English" (/login?lang=en). Xử lý: Yêu cầu GET mới được gửi với tham số lang. LoginController.loginGet cập nhật locale dựa trên lang. Trả về View với template user-login.html và ngôn ngữ mới. Kết quả: Trang đăng nhập được làm mới với ngôn ngữ đã chọn VD: "Đăng nhập" thay vì "Login". - Thêm các dependency cần thiết ```java org.thymeleaf thymeleaf 3.1.2.RELEASE com.tvd12 ezyhttp-server-thymeleaf 1.3.7 com.tvd12 ezyhttp-server-core 1.3.7 com.tvd12 ezyhttp-server-boot 1.3.7 ``` - Tạo file `messages_en.properties` và `file messages_vi.properties` trong thư mục `src/main/resources/messages` ![16.png](/api/v1/media/fdcb561ece35b5852050f75c5f0a167d938ff484d9bb07f18b3b61d5d4ec0b57.png) File `messages_en.properties` ``` login=Login username=Username username.placeholder=Enter your username password=Password password.placeholder=Enter your password login.button=Login login.language.en=English login.language.vi=Tiếng Việt login.error=Invalid username or password ``` File `file messages_vi.properties` ``` login=Đăng nhập username=Tên người dùng username.placeholder=Nhập tên người dùng password=Mật khẩu password.placeholder=Nhập mật khẩu login.button=Đăng nhập login.language.en=English login.language.vi=Tiếng Việt login.error=Tên người dùng hoặc mật khẩu không đúng ``` - Tạo trang user-login.html ``` Login

Login

Invalid username or password
``` - Tạo LoginController.java ``` package org.hello.controller; import com.tvd12.ezyhttp.server.core.annotation.Controller; import com.tvd12.ezyhttp.server.core.annotation.DoGet; import com.tvd12.ezyhttp.server.core.annotation.DoPost; import com.tvd12.ezyhttp.server.core.annotation.RequestParam; import com.tvd12.ezyhttp.server.core.view.Redirect; import com.tvd12.ezyhttp.server.core.view.View; @Controller public class LoginController { @DoGet("/login") public View loginGet( @RequestParam(value = "lang", defaultValue = "en") String language, @RequestParam(value = "error", defaultValue = "") String error) { return View.builder() .locale(language) .template("user-login") .addVariable("lang", language) .addVariable("error", !error.isEmpty()) .build(); } @DoPost("/login") public Redirect loginPost( @RequestParam("username") String username, @RequestParam("password") String password, @RequestParam(value = "lang", defaultValue = "en") String language) { if ("admin".equals(username) && "password".equals(password)) { return Redirect.to("/book-store/books"); } else { return Redirect.to("/login?lang=" + language + "&error=1"); } } } ``` - Khởi chạy ứng dụng và truy cập `http://localhost:8080/login` ![17.png](/api/v1/media/cf3b431ea809f8f73e9d21d7783c1c6839330ab19404a38af5ff541c6f66154d.png) ![18.png](/api/v1/media/ca573e97d732d9bfc9461b1c269c077c4c4ff11dae5762cd2fef7f6ca2b7a9df.png) ## 5. Tóm lại Trên đây là những thông tin liên quan đến đa ngôn ngữ Internationalization| i18n . Hy vọng với những chia sẻ trên đây giúp bạn nắm được đặc điểm và ứng dụng.