механизм plugin.properties в RCP затмения - PullRequest
7 голосов
/ 23 марта 2009

Мой проект включает в себя несколько плагинов, и каждый плагин содержит файл plugin.properties с почти 20 переводами. Файл MANIFEST.MF определяет имя файлов свойств, в которых хранятся строки внешних плагинов.

Bundle-Localization: plugin

Название плагина, который я определяю как

%plugin.name

Eclipse будет искать «% plugin.name» в файле plugin.properties во время выполнения.

Какой класс считывает запись 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);
    }

Поиск файла свойств и его кеширование. Переводы можно потом получить из кэшированного файла. Проблема в том, что весь файл кэшируется, а не отдельные переводы.

Решение состоит в том, чтобы сначала прочитать файл фрагмента, а не прочитать файл комплекта. Когда оба файла существуют, объедините их в один файл и запишите новый файл свойств на диск. Возвращается URL-адрес нового файла свойств, поэтому новый файл свойств можно кэшировать.

Ответы [ 5 ]

3 голосов
/ 06 апреля 2009

Хотя я неправильно понял информацию ... У меня была точно такая же проблема. Плагин не активируется дважды, и я не могу добраться до фрагментов Bundle-Localization key.

Я хочу, чтобы все мои языковые переводы были в 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())));
}

и просто назовите мое имя файла локализации фрагмента «фрагмент.свойства».

Это не особенно элегантно, но работает.

Кстати, чтобы получить файлы из фрагмента, вам нужен getResource, кажется, что файлы фрагментов находятся в пути к классам или ищутся только при использовании getResource.

Если у кого-то есть лучший подход, поправьте меня.

Всего наилучшего,

Mark.

1 голос
/ 29 апреля 2009
/**
 * 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);
    }
}
0 голосов
/ 16 августа 2010

Один из способов - подключить прослушиватель пакета и прослушивать установки пакетов (и, возможно, также посмотреть на уже установленные пакеты) и для каждого пакета генерировать / предоставлять - и устанавливать - фрагмент с требуемыми файлами свойств. Если это делается до запуска приложения, это должно иметь эффект.

0 голосов
/ 04 апреля 2009

Активация плагина обрабатывается операционной системой OSGi Equinox. Тем не менее, я бы настоятельно не рекомендовал пытаться исправить какие-либо файлы там, чтобы создать определенное поведение. Предложенный путь от Марка кажется гораздо более разумным подходом к вашей проблеме.

0 голосов
/ 03 апреля 2009

Измените имя вашего фрагмента plugin.properties на другое, например. фрагмент.свойства

в вашем фрагменте манифеста измените Bundle-Localization: плагин в Bundle-Localization: фрагмент

Ваш плагин будет активирован дважды, первый раз с использованием plugin.properties, второй с использованием фрагмента .properties.

...