如何使用 Eclipse 国际化 OSGi 应用程序?

lea*_*iro 5 java eclipse osgi localization internationalization

我正在尝试使用“OSGi 方式”国际化 OSGi 应用程序,但尚未取得进展。我所说的OSGi 方式是指使用框架为其提供的功能。我之前已经国际化过 Java 应用程序,但我想知道如何将其作为OSGi应用程序来实现。

\n\n

我创建了这个简单的演示[GitHub repo],其目的是创建一个捆绑包,该捆绑包在激活后将记录一条消息,在停用后将记录另一条消息。

\n\n

项目结构:

\n\n
src\n   |- org.example.i18n\n                     |- SimpleLoggingComponent   // where the actual strings are\n                     |- SimpleLogService\n                     |- SimpleLogServiceImpl\nMETA-INF\n   |- MANIFEST.MF\nOSGI-INF\n   |- org.example.i18n.SimpleLoggingComponent\n   |- org.example.i18n.SimpleLogServiceImpl\nbuild.properties\n
Run Code Online (Sandbox Code Playgroud)\n\n

SimpleLoggingComponent源码

\n\n
@Component\npublic class SimpleLoggingComponent {\n\n    private SimpleLogService simpleLogService;\n\n    @Reference\n    public void bindLogger(SimpleLogService logService) {\n        this.simpleLogService = logService;\n    }\n\n    public void unbindLogger(SimpleLogService logService) {\n        this.simpleLogService = null;\n    }\n\n    @Activate\n    public void activate() {\n        if (simpleLogService != null) {\n            simpleLogService.log("Yee ha, I\'m logging!"); // <-- need this message internationalized\n        }\n    }\n\n    @Deactivate\n    public void deactivate() {\n        if (simpleLogService != null) {\n            simpleLogService.log("Done, I\'m finishing logging!"); // <-- need this message internationalized\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

目前,字符串已固定在代码中,我希望能够将它们国际化。假设支持英语和西班牙语。

\n\n

稍后我计划通过Fragment Bundles添加对更多语言的支持,因此该解决方案应该可以通过这种方式进行扩展。

\n\n
\n\n

我已阅读所有这些内容,但没有找到任何一致的内容对我有帮助。

\n\n\n\n

此外,OSGi 联盟教程存档OSGi enRoute均不包含任何相关内容。

\n\n

环境:

\n\n\n\n

PS:我确信这不是一项复杂的任务,只是我还没有找到任何有用的(对我来说)有关它的文档。

\n

lea*_*iro 4

理论知识

本地化1

捆绑本地化条目共享一个通用的基本名称。为了查找潜在的本地化条目,需要添加下划线 ('_' \u005F) 以及多个后缀,并用另一个下划线分隔,最后附加后缀.properties。后缀在 中定义java.util.Locale。后缀的顺序必须是:

  • 语言

  • 国家

  • 变体

例如,以下文件提供英语、荷兰语(比利时和荷兰)和瑞典语的清单翻译。

OSGI-INF/l10n/bundle_en.properties
OSGI-INF/l10n/bundle_nl_BE.properties
OSGI-INF/l10n/bundle_nl_NL.properties
OSGI-INF/l10n/bundle_sv.properties
Run Code Online (Sandbox Code Playgroud)

清单本地化2

本地化值存储在包内的属性资源中。捆绑包本地化属性文件的默认基本名称是OSGI-INF/l10n/bundle. Bundle -Localization清单标头可用于覆盖本地化文件的默认基本名称。该位置相对于束和束片段的根。

本地化条目包含本地化信息的键/值条目。包清单中的所有标头都可以本地化。但是,框架必须始终使用具有框架语义的标头的非本地化版本。

可以使用以下语法将本地化密钥指定为包清单标头的值:

header-value ::= '%'text
text ::= < any value which is both a valid manifest headervalue
   and a valid property key name >
Run Code Online (Sandbox Code Playgroud)

例如,考虑以下捆绑清单条目:

Bundle-Name: %acme bundle
Bundle-Vendor: %acme corporation
Bundle-Description: %acme description
Bundle-Activator: com.acme.bundle.Activator
Acme-Defined-Header: %acme special header
Run Code Online (Sandbox Code Playgroud)

用户定义的标头也可以本地化。本地化键中的空格是明确允许的。

前面的示例清单条目可以通过清单本地化条目中的以下条目进行本地化OSGI-INF/l10n/bundle.properties

# bundle.properties
acme\ bundle=The ACME Bundle
acme\ corporation=The ACME Corporation
acme\ description=The ACME Bundle provides all of the ACME\ services
acme\ special\ header=user-defined Acme Data
Run Code Online (Sandbox Code Playgroud)

在实践中

1.首先,让我们创建捆绑文件,其中将包含键/值对。在这种情况下,英语语言 ( bundle.properties) 的默认语言之一和西班牙语语言 ( bundle_es.properties)的默认语言之一

...
OSGI-INF
   |- l10n
        |- bundle.properties
        |- bunlde_es.properties
   |- ...
Run Code Online (Sandbox Code Playgroud)

...其中将包含我们之前硬编码的字符串值。

#bundle.properties
startMessage = Yeah ha, I'm logging!
endMessage = Done, I'm finishing logging!

#bundle_es.properties
startMessage = Si, Estoy registrando logs!
endMessage = Terminado, He concluido de registrar logs!
Run Code Online (Sandbox Code Playgroud)

2.现在让我们创建一个实用程序组件,它将帮助我们根据区域设置获取与每个键关联的值。

src
   ...
   |- org.example.i18n.messages
                              |- MessageProvider
                              |- MessagesProviderImpl
   ...
Run Code Online (Sandbox Code Playgroud)

有两个文件:接口和实际实现,其中包含获取键/值对的逻辑。

public interface MessageProvider {
    String get(String key);
}

@Component
public class MessagesProviderImpl implements MessageProvider {
    private BundleLocalization bundleLocalization;
    private LocaleProvider localeProvider;
    private ResourceBundle resourceBundle;

    @Reference
    public void bindBundleLocalization(BundleLocalization bundleLocalization) {
        this.bundleLocalization = bundleLocalization;
    }

    @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC)
    public void bindLocaleProvider(LocaleProvider localeProvider) {
        this.localeProvider = localeProvider;
        setResourceBundle()
    }

    /*unbind methods omitted*/

    @Activate
    public void activate() {
        setResourceBundle();
    }

    @Override
    public String get(String key) {
        return resourceBundle.getString(key);
    }

    private String getLocale() {
        return localeProvider != null ? localeProvider.getLocale().toString() : Locale.getDefault().toString();
    }

    private void setResourceBundle() {
        resourceBundle = bundleLocalization.getLocalization(FrameworkUtil.getBundle(getClass()), getLocale());
    }
}
Run Code Online (Sandbox Code Playgroud)

3.使用MessageProvider中的组件SimpleLoggingComponent

@Component
public class SimpleLoggingComponent {

    /*previously code omitted for brevity*/

    private MessageProvider messages;

    @Reference
    public void bindMessageProvider(MessageProvider messageProvider) {
        messages = messageProvider;
    }

    /*unbind methods omitted*/

    @Activate
    public void activate() {
        simpleLogService.log(messages.get("startMessage")); // <- use now the key: startMessage
    }

    @Deactivate
    public void deactivate() {
        simpleLogService.log(messages.get("endMessage")); // <- use now the key: endMessage
    }
}
Run Code Online (Sandbox Code Playgroud)

使用自定义语言启动应用程序

在“参数”选项卡上,使用运行时参数-nl来实现此目的,例如-nl en

参数 -nl 设置为英语的运行配置图像:<code>-nl en</code>


参考

完整源代码