如何将 Spotlight for Help 插入本地化的 macOS 应用程序?

How to insert Spotlight for Help into localized macOS applications?

我正在 macOS 上使用 Swing GUI 框架实现一个 Java 应用程序。使用 系统 外观和 屏幕 菜单栏时,Swing 会自动插入一个名为 搜索字段 Spotlight for Help进入第一个菜单栏标有"Help"的菜单:

System.setProperty("apple.laf.useScreenMenuBar", "true");

try {
  UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
  e.printStackTrace();
}

JFrame frame = new JFrame();
JMenuBar menuBar = new JMenuBar();
JMenu helpMenu = new JMenu("Help");
menuBar.add(helpMenu);
frame.setJMenuBar(menuBar);

由于我的应用程序是本地化的,所以英文字符串 "Help" 在其他语言环境中是不同的(例如 "Aide" 在法语中)。但在那些情况下,Swing 不会插入 Spotlight for Help,因为字符串不同:

解决方案

  1. Bundle the .class files and resources (image, sound, video, localization files, etc.) of your application in a .jar file with Oracle's Java Archive.
  2. Bundle your .jar file in an .app directory with Oracle's AppBundler (for Java 7+, which replaces the old Apple's JarBundler 对于 Java 6).
  3. 将应用程序应支持的每个语言环境的 Contents/Resources/<locale>.lproj 目录添加到 .app 目录(您可以让语言环境目录为空,因为本地化文件可能已经在 .jar 文件).
  4. 启动您的应用程序(双击 Finder 中的应用程序图标或在终端中键入 open <application>.app)。

将出现搜索字段 Spotlight for Help。

说明

我猜你是在直接执行 .class 文件(例如,从 IDE 或 .jar 文件,因为据我所知这应该可以工作。

尽管大多数消息来源都说,Swing 深深植根于系统调用,因此依赖于 OS 的许多功能,例如本例。理想情况下,这应该由方法 setHelpMenu(JMenu) but as you'll notice this has never been implemented.

涵盖

如果你先检查一下,你会注意到你的 JMenuBar and you have no control over that. If you try using AWT's MenuBar instead you'll see the behavior is exactly the same although, insterestingly enough, the method setHelpMenu(Menu) 中没有添加额外的组件它确实实现了,但如果菜单的名称与 [=24 不同,则不会添加搜索字段=].

此时我找到了一个解决方法,它将菜单标签设置为 "Help" 并在显示后(不要使用 ComponentListener.componentShown(ComponentEvent), this won't work, use AncestorListener.ancestorAdded(AncestorEvent))将菜单标签更改为本地化的标签。这会将搜索字段添加到帮助菜单。但是,搜索字段将以英文显示,并带有标签 "Search".

检查 API,很明显在 Swing 中此功能是 not implemented and fully relies on AWT. AWT on the other hand has partly implemented the native calls to the OS, but it's not wired to be invokable。达到这一点并知道搜索字段确实出现在我们的应用程序中,并且在 运行 和 Java 中的其他应用程序中它已正确本地化让我们暗示这是 OS 本身的特征(在这一点上我可能是错的,它确实是 AWT 在做肮脏的工作,但无法找到任何直接执行它的代码,尽管在 Objective C 中你可以定义任何代码)。

阅读有关 how to localize a Java application in MacOS 的文档,我们注意到:

  • 要求将应用程序捆绑在 .app 目录中并包含 Contents/Resources/<os-locale>.lproj 目录,以便 OS 识别 OS 支持的语言环境应用程序,因此需要一个标有 OS-localized "Help" 字符串的菜单,以便将 OS-localized 搜索字段添加到该菜单菜单;
  • 否则,OS 将应用程序视为 en_US 本地化,因此需要一个标有 en_US-本地化 "Help" 字符串的菜单,以便添加en_US- 将搜索字段本地化到该菜单。

现在您可以在终端中键入 open <application>.app,您的应用程序将在帮助菜单中添加 OS 本地化搜索字段。

请注意,Apple 有自己的机制来强制应用程序使用不同于 OS 语言环境的其他语言环境,并且它使用 -AppleLanguages 选项 (open <application>.app --args -AppleLanguages "(<locale>)")。 Language Switcher 实用程序在后台执行相同的操作。同样,适当的 Contents/Resources/<locale>.lproj 目录应该存在,否则 OS 会将应用程序视为 en_US 本地化。

你如何make an .app directory from the .class files and resources (image, sound, video, localization files, etc.) of your application is beyond the scope of this question because it varies depending on the platform you're using, but Oracle provides the Java Archive (to make the intermediary .jar file) and AppBundler(创建.app目录)实用程序。

截图

此屏幕截图中的 OS 已本地化为西班牙语,但该应用程序已本地化为法语,因为它是使用 -AppleLanguages "(fr)" 选项启动的。

我刚刚找到了另一种方法。无需在.app目录中添加空Contents/Resources/<locale>.lproj目录,只需在.app目录的Contents/Info.plist文件中添加这两行(键值对)即可:

<key>CFBundleAllowMixedLocalizations</key>
<true />

制作 .app 包的新方法是使用 Oracle 的 JavaPackager 命令行实用程序,它是 J.D.K 的一部分。它会生成一个 .app 目录,其中 Contents/Info.plist 默认具有以上两行(无需在命令行中将键值对作为 javapackager 的选项传递)。并使用 open <application>.app --args -AppleLanguages "(<locale>)" 命令强制另一个语言环境 实际上 与 Oracle 的 JavaPackager 生成的 <application>.app 目录一起工作,与 Oracle 的 AppBundler 生成的目录相反。