EzyPlatform quản lý đa ngôn ngữ thế nào?
Back To BlogsEzyPlatform được thừa hưởng từ EzyHTTP
Bản thân EzyPlatform không thực sự cung cấp thuật toán và các thành phần để quản lý đa ngôn ngữ mà nó được thừa hưởng từ EzyHTTP.
EzyPlatform chỉ đơn giản là cung cấp đường dẫn đến thư mục resources/messages
của thành phần của các plugin hay theme mà nó quản lý cho EzyHTTP sau đó sử dụng các lớp của EzyHTTP để đọc messages và trả về cho EzyHTTP.
Có một điều thú vị ở đây là EzyPlatform lại không điều khiển EzyPlatform, nghĩa là không trực tiếp gọi đến EzyHTTP mà cài đặt một giao diện có tên MessageProvider, đây là một trong những ứng dụng thú vị của Đảo ngược điều khiển - IoC.
Quá trình các message đa ngôn ngữ được đưa vào quản lý
Các tập tin message sẽ ở dạng key value, ví dụ:
copy_url=Copy URL cpu_usage=CPU usage search_result.title=Search Result server_error.title=Server Error
snake_case
hoặc dot.case
cho thống nhất.Đối với các ngôn ngữ khác nhau sẽ lưu ở các file có dạng messages_[mã ngôn ngữ].properties ví dụ:
- messages_vi.properties: dành cho tiếng Việt.
- messages_zh.properties: dành cho tiếng Trung.
Mặc định thì sẽ lấy các các message ở tập tin messages.properties
. Nếu không tìm thấy tin nhắn nào thì giá trị sẽ được lấy bằng cách chuyển đổi từ key sang value, ví dụ hello world
sẽ được chuyển thành Hello World
.
Các tập tin messages sẽ bắt buộc phải đặt trong thư mục resources/messages
của các plugin hay theme.
Các bước để đưa message vào quản lý sẽ như sau:
- Vì admin và web tồn tại độc lập nên các message cũng được quản lý độc lập.
- EzyPlatform sẽ cung cấp đường dẫn của thư mục
resources/messages
của thành phần hiện tại là admin web. - EzyPlatform sử dụng lớp MessageReader của EzyHTTP để đọc toàn bộ các messages của các ngôn ngữ.
- EzyPlatform duyệt qua toàn bộ các plugin và theme đã được kích hoạt và cung cấp đường dẫn đến thư mục
resources/messages
của các plugin hay theme này và lại sử dụngMessageReader
để đọc. - Cuối cùng là tổng hợp thành một
Map<String, Properties>
giữa ngôn ngữ và các message để trả lại cho EzyHTTP. - EzyHTTP sẽ đưa các message vào quản lý.
Bạn có thể tham khảo mã nguồn của lớp AbstractMessageProvider
để biết chi tiết hơn các bước:
@AllArgsConstructor public abstract class AbstractMessageProvider implements MessageProvider { private final FileSystemManager fileSystemManager; private static final String MESSAGES_FOLDER = "resources/messages"; @Override public Map<String, Properties> provide() { String ezyplatformHomePath = fileSystemManager.getEzyHomePathString(); Map<String, Properties> answer = new HashMap<>(); TargetType targetType = getInclusiveTargetType(); readAndAppendMessages( answer, Paths.get( ezyplatformHomePath, targetType.getName(), MESSAGES_FOLDER ) ); ModuleType[] moduleTypes = getInclusiveModuleTypes(); Map<ModuleType, List<String>> modulesMap = getInclusiveModulesMapByModuleTypes( moduleTypes ); for (ModuleType moduleType : moduleTypes) { List<String> modules = modulesMap.getOrDefault( moduleType, Collections.emptyList() ); for (String module : modules) { readAndAppendMessages( answer, Paths.get( ezyplatformHomePath, moduleType.getTargetFolder(), module, MESSAGES_FOLDER ) ); } } return answer; } private void readAndAppendMessages( Map<String, Properties> messages, Path messageFolder ) { if (!Files.exists(messageFolder)) { return; } MessageReader messageReader = MessageReader.getDefault(); Map<String, Properties> map = messageReader.read( messageFolder.toString() ); for (Map.Entry<String, Properties> e : map.entrySet()) { String lang = e.getKey(); messages .computeIfAbsent(lang, k -> new Properties()) .putAll(e.getValue()); } } protected abstract TargetType getInclusiveTargetType(); protected abstract ModuleType[] getInclusiveModuleTypes(); protected abstract Map<ModuleType, List<String>> getInclusiveModulesMapByModuleTypes( ModuleType[] moduleTypes ); }
Bên trong EzyHTTP quản lý đã ngôn ngữ thế nào?
Cũng rất đơn giản thôi như bạn vừa thấy, EzyHTTP sẽ tổng hợp tất cả các message từ các MessageProvider
và đưa vào một Map<String, Properties>
duy nhất ánh xạ giữa ngôn ngữ và các message, mã nguồn tổng hợp sẽ kiểu thế này:
private Map<String, Properties> collectMessages() { Map<String, Properties> answer = new HashMap<>(); mergeAnswerMessages(answer, readMessages()); for (MessageProvider provider : messageProviders) { mergeAnswerMessages(answer, provider.provide()); } return answer; }
Khi bạn sử dụng một key và một ngôn ngữ, EzyHTTP sẽ lục tìm trong map
cho bạn, nếu không thấy thì nó sẽ lấy trong các message mặc định, nếu không thấy nữa thì nó sẽ chuyển đổi message từ key cho bạn.
Tổng kết
Quản lý đa ngôn ngữ thông qua các tập tin messages.properties đối với các nhà phát triển tương đối đơn giản. Tuy nhiên ẩn sau đó là các kỹ thuật phức tạp để tổ chức và lấy ra được đúng giá trị của key mà bạn truyền vào. Mình sẽ dành các bài khác để nói về cách sử dụng và các chi tiết sâu xa hơn trong việc quản lý đa ngôn ngữ trong EzyPlatform nhé.