跳至主要内容

本地化 25.10

在 ChatGPT 中打开

实现 LocaleObserver 接口的组件会在语言环境变化时自动接收通知。这使得 UI 元素能够更新其文本、格式和其他特定于语言环境的内容,而无需手动协调。

LocaleObserver 接口

LocaleObserver.java
@FunctionalInterface
public interface LocaleObserver extends Serializable {
void onLocaleChange(LocaleEvent event);
}

当组件实现此接口时,webforJ 会自动:

  • 在创建时注册组件以接收语言环境变化事件
  • 在销毁时注销组件
  • 每当语言环境变化时调用 onLocaleChange()

此注册过程在组件生命周期中发生。

处理翻译

当调用 onLocaleChange() 时,组件会接收到新的语言环境。如何加载和应用翻译取决于开发者。常见的方法包括:

  • 使用 Java ResourceBundle 和属性文件
  • 数据库查询翻译
  • 自定义翻译提供者
  • 简单情况的硬编码映射

此示例使用 ResourceBundle,它将翻译存储在属性文件中:

messages.properties        # 后备/默认
messages_en.properties # 英语
messages_de.properties # 德语

属性文件包含键值对:

messages_en.properties
app.title=Mailbox
menu.inbox=Inbox
messages_de.properties
app.title=Postfach
menu.inbox=Posteingang

更改语言环境

使用 App.setLocale() 来更改应用程序语言环境。这会触发对所有注册观察者的通知:

App.setLocale(Locale.GERMAN);
App.setLocale(Locale.forLanguageTag("fr"));

一种典型的实现可能使用下拉菜单或选择组件:

ChoiceBox languageSelector = new ChoiceBox();
languageSelector.add("en", "English");
languageSelector.add("de", "Deutsch");
languageSelector.add("fr", "Français");

languageSelector.onSelect(e -> {
String lang = (String) e.getSelectedItem().getKey();
Locale newLocale = Locale.forLanguageTag(lang);

App.setLocale(newLocale);
});

当用户选择一种语言时,App.setLocale() 会触发,所有实现了 LocaleObserver 的组件都会接收到更新。

实现观察者

当组件实现 LocaleObserver 时,需要处理两种情况:使用当前语言环境的初始渲染和在语言环境变化时的更新。以下示例通过一个显示本地化文本和链接的组件演示此模式。

该组件存储需要翻译更新的元素的引用。构造时,它加载当前语言环境的翻译。当语言环境变化时,onLocaleChange() 被触发,允许组件重新加载翻译并更新其显示的文本。

TranslationService.java
import com.webforj.App;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;

@Service
public class TranslationService {
private final MessageSource messageSource;

public TranslationService(MessageSource messageSource) {
this.messageSource = messageSource;
}

public String get(String key) {
return messageSource.getMessage(key, null, App.getLocale());
}
}
Explore.java
public class Explore extends Composite<FlexLayout> implements LocaleObserver {
private final TranslationService i18n;
private FlexLayout self = getBoundComponent();
private H3 titleElement;
private Anchor anchor;
private String titleKey;

public Explore(TranslationService i18n, String titleKey) {
this.i18n = i18n;
this.titleKey = titleKey;

self.addClassName("explore-component");
self.setStyle("margin", "1em auto");
self.setDirection(FlexDirection.COLUMN);
self.setAlignment(FlexAlignment.CENTER);
self.setMaxWidth(300);
self.setSpacing(".3em");

Img img = new Img(String.format("ws://explore/%s.svg", titleKey), "mailbox");
img.setMaxWidth(250);

String translatedTitle = i18n.get("menu." + titleKey.toLowerCase());
titleElement = new H3(translatedTitle);

anchor = new Anchor("https://docs.webforj.com/docs/components/overview", i18n.get("explore.link"));
anchor.setTarget("_blank");

self.add(img, titleElement, anchor);
}

@Override
public void onLocaleChange(LocaleEvent event) {
titleElement.setText(i18n.get("menu." + titleKey.toLowerCase()));
anchor.setText(i18n.get("explore.link"));
}
}

该组件存储显示翻译内容的元素引用(titleElementanchor)。翻译在构造函数中使用当前语言环境加载。当语言环境变化时,onLocaleChange() 仅更新需要翻译的文本。

生命周期管理

该框架通过组件生命周期钩子自动处理观察者注册:

  • 创建时:实现 LocaleObserver 的组件会在 LocaleObserverRegistry 中注册
  • 销毁时:组件会注销以防止内存泄漏

每个应用实例维护其自己的观察者注册表。此自动管理意味着:

  • 无需手动调用注册/注销
  • 不会因销毁的组件而导致内存泄漏
  • 线程安全的并发通知
每个应用的注册表

每个应用实例维护其自己的观察者注册表。在一个应用中注册的观察者不会接收到同一 JVM 中其他应用的通知。

LocaleEvent

传递给 onLocaleChange()LocaleEvent 提供:

方法返回描述
getLocale()Locale设置的新语言环境
getSource()Object接收到事件的组件
@Override
public void onLocaleChange(LocaleEvent event) {
Locale newLocale = event.getLocale();
Object source = event.getSource();

// 使用新语言环境更新组件
ResourceBundle bundle = ResourceBundle.getBundle("messages", newLocale);
updateUI(bundle);
}