eclipse RCP中的plugin.properties机制

时间:2009-03-23 12:52:48

标签: java plugins rcp fragment

我的项目包含多个插件,每个插件都包含plugin.properties文件,其中包含近20个翻译。 MANIFEST.MF文件定义存储外部插件字符串的属性文件的名称。

Bundle-Localization: plugin

我定义的插件名称如

%plugin.name

Eclipse将在运行时搜索plugin.properties文件中的“%plugin.name”。

哪个类读出了MANIFEST.MF Bundle-Localization条目,并且在“plugin.properties”文件中搜索了带有起始'%'后缀的字符串?

我想以这种方式找到并修补这些类,我可以先查看一些其他目录/文件中的“%plugin.name”标识符。使用这些新机制,我可以在我的产品中添加片段并覆盖“plugin.properties”文件中的单行,而无需更改原始插件。 通过这些机制,我可以通过添加不同的片段为多个客户创建构建过程。片段包括他们想要更改的客户名称和特殊字符串。

我想这样做,因为片段机制只将文件添加到原始插件。当插件中存在“plugin.properties”文件时,将忽略片段“plugin.properties”文件。

更新1:

方法

class ManifestLocalization{
...
protected ResourceBundle getResourceBundle(String localeString) {
}
...
}

返回给定语言环境字符串的属性文件的ResourceBundle。 当有人知道我现在可以先查看片段以获取资源路径时,请发布它。

更新2:

ManifestLocalization类中的方法

    private URL findInResolved(String filePath, AbstractBundle bundleHost) {

        URL result = findInBundle(filePath, bundleHost);
        if (result != null)
            return result;
        return findInFragments(filePath, bundleHost);
    }

搜索属性文件并对其进行缓存。翻译可以从缓存文件中获取。问题是,整个文件是缓存的而不是单个翻译。

解决方案是首先读取片段文件,而不是读取bundle文件。当两个文件都存在时,将它们合并到一个文件中,并将新属性文件写入磁盘。返回新属性文件的URL,以便新的propetries文件可以缓存。

5 个答案:

答案 0 :(得分:3)

虽然我得到的信息有误......但我有完全相同的问题。该插件未激活两次,我无法访问片段Bundle-Localization键。

我希望我的所有语言翻译都在plugin.properties中(我知道这是不受欢迎的,但管理单个文件要容易得多。)

我(一半)使用

解决了这个问题
public void populate(Bundle bundle) {
    String localisation = (String) bundle.getHeaders().get("Bundle-Localization");
    Locale locale = Locale.getDefault();

    populate(bundle.getEntry(getFileName(localisation)));
    populate(bundle.getEntry(getFileName(localisation, locale.getLanguage())));
    populate(bundle.getEntry(getFileName(localisation, locale.getLanguage(), locale.getCountry())));
    populate(bundle.getResource(getFileName("fragment")));
    populate(bundle.getResource(getFileName("fragment", locale.getLanguage())));
    populate(bundle.getResource(getFileName("fragment", locale.getLanguage(), locale.getCountry())));
}

并简单地调用我的片段本地化文件名'fragment.properties'。

这不是特别优雅,但它有效。

顺便说一下,要从片段中获取需要getResource的文件,似乎片段文件在类路径上,或者仅在使用getResource时搜索。

如果某人有更好的方法,请纠正我。

一切顺利,

标记。

答案 1 :(得分:1)

/**
 * The Hacked NLS (National Language Support) system.
 * <p>
 * Singleton.
 * 
 * @author mima
 */
public final class HackedNLS {
    private static final HackedNLS instance = new HackedNLS();

    private final Map<String, String> translations;

    private final Set<String> knownMissing;

    /**
     * Create the NLS singleton. 
     */
    private HackedNLS() {
        translations = new HashMap<String, String>();
        knownMissing = new HashSet<String>();
    }

    /**
     * Populates the NLS key/value pairs for the current locale.
     * <p>
     * Plugin localization files may have any name as long as it is declared in the Manifest under
     * the Bundle-Localization key.
     * <p>
     * Fragments <b>MUST</b> define their localization using the base name 'fragment'.
     * This is due to the fact that I have no access to the Bundle-Localization key for the
     * fragment.
     * This may change.
     * 
     * @param bundle The bundle to use for population.
     */
    public void populate(Bundle bundle) {
        String baseName = (String) bundle.getHeaders().get("Bundle-Localization");

        populate(getLocalizedEntry(baseName, bundle));
        populate(getLocalizedEntry("fragment", bundle));
    }

    private URL getLocalizedEntry(String baseName, Bundle bundle) {
        Locale locale = Locale.getDefault();
        URL entry = bundle.getEntry(getFileName(baseName, locale.getLanguage(), locale.getCountry()));
        if (entry == null) {
            entry = bundle.getResource(getFileName(baseName, locale.getLanguage(), locale.getCountry()));
        }
        if (entry == null) {
            entry = bundle.getEntry(getFileName(baseName, locale.getLanguage()));
        }
        if (entry == null) {
            entry = bundle.getResource(getFileName(baseName, locale.getLanguage()));
        }
        if (entry == null) {
            entry = bundle.getEntry(getFileName(baseName));
        }
        if (entry == null) {
            entry = bundle.getResource(getFileName(baseName));
        }
        return entry;
    }

    private String getFileName(String baseName, String...arguments) {
        String name = baseName;
        for (int index = 0; index < arguments.length; index++) {
            name += "_" + arguments[index];
        }
        return name + ".properties";
    }

    private void populate(URL resourceUrl) {
        if (resourceUrl != null) {
            Properties props = new Properties();
            InputStream stream = null;
            try {
                stream = resourceUrl.openStream();
                props.load(stream);
            } catch (IOException e) {
                warn("Could not open the resource file " + resourceUrl, e);
            } finally {
                try {
                    stream.close();
                } catch (IOException e) {
                    warn("Could not close stream for resource file " + resourceUrl, e);
                }
            }
            for (Object key : props.keySet()) {
                translations.put((String) key, (String) props.get(key));
            }
        }
    }

    /**
     * @param key The key to translate.
     * @param arguments Array of arguments to format into the translated text. May be empty.
     * @return The formatted translated string.
     */
    public String getTranslated(String key, Object...arguments) {
        String translation = translations.get(key);
        if (translation != null) {
            if (arguments != null) {
                translation = MessageFormat.format(translation, arguments);
            }
        } else {
            translation = "!! " + key;
            if (!knownMissing.contains(key)) {
                warn("Could not find any translation text for " + key, null);
                knownMissing.add(key);
            }
        }
        return translation;
    }

    private void warn(String string, Throwable cause) {
        Status status;
        if (cause == null) {
            status = new Status(
                    IStatus.ERROR, 
                    MiddlewareActivator.PLUGIN_ID, 
                    string);
        } else {
            status = new Status(
                IStatus.ERROR, 
                MiddlewareActivator.PLUGIN_ID, 
                string,
                cause);
        }
        MiddlewareActivator.getDefault().getLog().log(status);

    }

    /**
     * @return The NLS instance.
     */
    public static HackedNLS getInstance() {
        return instance;
    }

    /**
     * @param key The key to translate.
     * @param arguments Array of arguments to format into the translated text. May be empty.
     * @return The formatted translated string.
     */
    public static String getText(String key, Object...arguments) {
        return getInstance().getTranslated(key, arguments);
    }
}

答案 2 :(得分:0)

将片段plugin.properties的名称更改为其他内容,例如。 fragment.properties

你的片段清单中的

改变了 Bundle-Localization:插件 至 Bundle-Localization:片段

你的插件将被激活两次,第一次使用plugin.properties,第二次使用fragment.properties。

答案 3 :(得分:0)

插件激活由OSGi运行时Equinox处理。但是,我强烈反对尝试修补那里的任何文件来创建特定的行为。 Mark的建议方式对你的问题似乎更为理智。

答案 4 :(得分:0)

一种方法是附加一个bundle监听器,并监听bundle的安装(也许还要查看已安装的bundle),并为每个bundle生成/提供 - 并安装 - 一个包含所需属性文件的片段。如果在应用程序启动之前完成此操作,则应该生效。