Docs

Documentation versions (currently viewingVaadin 24)
Documentation translations (currently viewingChinese)

本页面内容通过机器翻译自官方文档,原文见 http://vaadin.com/docs。翻译内容可能包含错误、不准确或表述不当之处。Vaadin 不保证翻译内容的准确性、可靠性或时效性,也不就其进行任何明示或暗示的保证。

本地化

使用 I18NProvider 实现本地化与翻译字符串。

要使用本地化与翻译字符串,应用只需将翻译属性文件放置在类路径下的目录 vaadin-i18n 下,且以前缀 translations 命名(例如,src/main/resources/vaadin-i18n/translations.properties)。

当在应用中使用本地化、请求翻译,或首次使用 I18NProvider 时,会检查 vaadin-i18n 文件夹资源是否包含任何 translations.propertiestranslations_[langcode].properties 文件。可用的属性文件中的所有语种代码会被收集,并作为提供的 locale 添加到 DefaultI18NProvider 中。

文件 translations.properties 是默认的翻译文件,会用于任何没有特定翻译文件的 Locale。locale 翻译文件的命名方式如 translations_fi_FI.propertiestranslations_de.properties。自动的 Locale 创建支持一到三部分(例如,translations_language_country_variant.properties)。

Note
DefaultI18NProvider 从 Vaadin Flow 24.3 版本开始可用。如需在更早版本中使用,需要自行实现 I18NProvider,具体请参见 定义 I18n Provider 属性 部分。

新会话的 Locale 选择

初始 locale 的确定方式为将 I18NProvider 提供的 locale 与来自客户端初始响应中的 Accept-Language 头进行匹配。

如果找到完全匹配(即语言与国家都匹配),则直接使用。否则仅尝试匹配语言。如果都未找到,则 locale 会被设置为 I18NProvider.getProvidedLocales() 返回列表中的第一个“支持”的 locale。如果该列表为空,则使用 Locale.getDefault()

在应用中使用本地化

在应用中实现国际化需结合使用 I18NProvider,并在 locale 变更时更新翻译内容。

为简化开发,实现本地化文本控制的应用类可实现 LocaleChangeObserver 接口,以接收 locale 变更相关事件。当组件被挂载(attached)时(但在 onAttach() 调用之前),导航时也会通知该 observer。导航中的任何 URL 参数都会设置,以便用于判断状态。

Source code
Java
public class LocaleObserver extends Div implements LocaleChangeObserver {

    @Override
    public void localeChange(LocaleChangeEvent event) {
        setText(getTranslation("my.translation", getUserId()));
    }
}

未实现 LocaleChangeObserver 时使用本地化

Source code
I18NProvider(未实现 LocaleChangeObserver
public class MyLocale extends Div {

    public MyLocale() {
        setText(getTranslation("my.translation", getUserId()));
    }
}

定义 I18n Provider 属性

如果要使用功能比默认实现更丰富的自定义 I18N provider,应用只需实现 I18NProvider 并在属性 i18n.provider 中指定其全限定类名。

Note
对 Spring 项目而言,如果自定义 provider 作为类型为 I18NProvider 的 Bean,则无需设置此属性。

可以通过命令行作为系统属性、在 web.xml 文件中作为 Servlet 初始化参数,或通过 @WebServlet 注解设置 i18n.provider 属性。

作为系统属性时,参数名称需带 vaadin 前缀,例如:

Source code
terminal
mvn jetty:run -Dvaadin.i18n.provider=com.vaadin.example.ui.TranslationProvider

使用注解时,servlet 类可如下定义:

Source code
Java
@WebServlet(urlPatterns = "/*", name = "slot", asyncSupported = true, loadOnStartup = 1,
   initParams = { @WebInitParam(name = "i18n.provider", value = "com.vaadin.example.ui.TranslationProvider") })
public class ApplicationServlet extends VaadinServlet {
}

如果更愿意在 web.xml 文件中配置,则可以这样设置:

Source code
XML
<?xml version="1.0" encoding="UTF-8"?>
<web-app
  id="WebApp_ID" version="3.0"
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

  <servlet>
    <servlet-name>myservlet</servlet-name>
    <servlet-class>
        com.vaadin.flow.server.VaadinServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>

    <init-param>
      <param-name>i18n.provider</param-name>
      <param-value>com.vaadin.example.ui.TranslationProvider</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>myservlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

如果您使用的是 Spring,可将 I18NProvider 作为一个 bean 提供。在这种情况下,只需通过 @Component 注解您的实现类即可,使其可作为 Spring bean 被使用。Spring 附加组件如果检测到它可用会自动使用该实现。请参考示例教程项目中的 SimpleI18NProvider.java

使用 I18NProvider 进行翻译

本示例中启用了芬兰语和英语,芬兰语为默认语言,如果用户客户端未指定英语为可接受语言则使用芬兰语。语言 .properties 文件以 "translate" 开头命名:例如,默认文件为 translate.properties,还有 translate_fi_FI.propertiestranslate_en_GB.properties

这里通过类加载器加载翻译属性文件,因此应将其放在类路径下,例如放在 resources 文件夹中。对于默认的 Maven 配置,应为 src/main/resources

Source code
I18NProvider 实现示例
public class TranslationProvider implements I18NProvider {

    public static final String BUNDLE_PREFIX = "translate";

    public final Locale LOCALE_FI = new Locale("fi", "FI");
    public final Locale LOCALE_EN = new Locale("en", "GB");

    private List<Locale> locales = Collections
            .unmodifiableList(Arrays.asList(LOCALE_FI, LOCALE_EN));

    @Override
    public List<Locale> getProvidedLocales() {
        return locales;
    }

    @Override
    public String getTranslation(String key, Locale locale, Object... params) {
        if (key == null) {
            LoggerFactory.getLogger(TranslationProvider.class.getName())
                    .warn("Got lang request for key with null value!");
            return "";
        }

        final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_PREFIX, locale);

        String value;
        try {
            value = bundle.getString(key);
        } catch (final MissingResourceException e) {
            LoggerFactory.getLogger(TranslationProvider.class.getName())
                    .warn("Missing resource", e);
            return "!" + locale.getLanguage() + ": " + key;
        }
        if (params.length > 0) {
            value = MessageFormat.format(value, params);
        }
        return value;
    }
}

支持从右到左(RTL)模式

Vaadin 组件对从右到左的语言有内置支持,组件在该模式下可以直接使用。但如需让应用同时支持从左到右和从右到左模式,您需要做少许调整。

参照前述示例,假如您的应用现在也已翻译为例如阿拉伯语这样的从右到左语言。除了 按照 I18NProvider 示例进行配置 外,还可在主布局中添加如下代码:

Source code
Java
public class MainLayout extends VerticalLayout {

    public MainLayout() {
        // ...
        final UI ui = UI.getCurrent();
        if (ui.getLocale().getLanguage() == "ar") {
            ui.setDirection(Direction.RIGHT_TO_LEFT);
        }
    }
}

如 locale 的变更仅根据客户端传来的 Accept-Language 决定,则此方法生效。但若用户可在应用设置页面指定语言,则主布局应实现 LocaleChangeObserver 接口。这样可以在 locale 变更时收到通知,然后对文本方向作出相应处理:

Source code
Java
public class MainLayout extends VerticalLayout implements LocaleChangeObserver {

    @Override
    public void localeChange(LocaleChangeEvent event) {
        if (event.getLocale().getLanguage() == "ar") {
            event.getUI().setDirection(Direction.RIGHT_TO_LEFT);
        } else {
            event.getUI().setDirection(Direction.LEFT_TO_RIGHT);
        }
    }
}

前端项目

若为纯前端应用,要设置从右到左模式,可直接指定 document.dir = 'rtl'

添加从右到左支持

如果您有自定义元素,或应用有自定义样式,需要为它们手动添加从右到左支持。

首先,如果您的元素继承自 Vaadin 的 ElementMixin,无需做任何更改。否则,可以让该元素继承自它或仅继承 DirMixin(即 DirMixin 位于 @vaadin/component-base 包中)。

Source code
JavaScript
import { PolymerElement } from '@polymer/polymer/polymer-element.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';

class MyElement extends DirMixin(PolymerElement) {}

DirMixin 会注册元素以响应文档级的 dir 属性变化,并与元素自身的 dir 属性进行同步。这对于在 CSS 和 JS 中根据文本方向设置状态非常有用。

其次,请确保您的样式针对从右到左模式做了调整。例如,如果针对 :host 定义了如下 padding 值:

Source code
CSS
:host {
    padding-right: 1em;
    padding-left: 2em;
}

您可能还需要为从右到左模式定义如下样式:

Source code
CSS
:host([dir="rtl"]) {
    padding-right: 2em;
    padding-left: 1em;
}

第三,还应检查样式中的 paddingmargintext-alignfloattransform 等设置。如果您的自定义元素无需兼容老旧浏览器,可以用*CSS 逻辑属性*替换部分属性。参见 MDN web documentation 获取完整 CSS 逻辑属性列表及浏览器支持说明。Flex 和 Grid 容器一般由浏览器自动处理,无需额外操作。更多内容请参阅此 全面的 RTL 样式指南

如需帮助调整样式以支持 RTL,可使用 RTLCSS 工具。可直接粘贴原始样式,让工具自动生成适用于各元素的代码。

若元素使用图标或 Unicode 符号表示方向(如返回按钮),则需要为 RTL 模式使用正确的图标或符号。

如有键盘交互(例如用箭头键在元素间切换),建议根据 dir 属性动态决定方向,例如:

Source code
JavaScript
// 代码中的某处
const dirIncrement = this.getAttribute('dir') === 'rtl' ? -1 : 1;

switch (event.key) {
    // ...
    case 'ArrowLeft':
        idx = currentIdx - dirIncrement;
        break;
    case 'ArrowRight':
        idx = currentIdx + dirIncrement;
        break;
    // ...
}

依赖 JavaScript 计算尺寸、位置、水平滚动的自定义元素,也可能需针对 RTL 做适配。

如有可视化测试,建议新增或更新现有测试,以便也能在 RTL 模式下运行。

722E7AE4-191E-4DE8-90F1-CAE8AE6CD3DF