Механизм плагина.properties в eclipse RCP
Вопрос
Мой проект включает в себя несколько плагинов, и каждый плагин включает файл плагина.properties, содержащий около 20 переводов.Файл MANIFEST.MF определяет имена файлов свойств, в которых хранятся строки внешнего плагина.
Bundle-Localization: plugin
Имя плагина я определяю как
%plugin.name
Eclipse будет искать «%plugin.name» в файле плагина.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-адрес нового файла свойств, чтобы новый файл свойств можно было кэшировать.
Решение
Хотя я неправильно понял информацию...У меня была точно такая же проблема.Плагин дважды не активируется и я не могу добраться до фрагментов Bundle-Key Localization.
Я хочу, чтобы все мои языковые переводы были в плагине.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.
Если у кого-то есть лучший подход, пожалуйста, поправьте меня.
Всего наилучшего,
Отметка.
Другие советы
/**
* 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);
}
}
Измените имя вашего фрагмента плагин.свойства на что-нибудь другое, например.фрагмент.свойства
В вашем фрагменте Manifest Измените локализацию пакета:плагин на пакет-локализацию:фрагмент
Ваш плагин будет активирован дважды: первый раз с помощью плагина.properties, второй с помощью фрагмента.свойств.
Активация плагина осуществляется средой выполнения OSGi Equinox.Однако я бы настоятельно не рекомендовал исправлять какие-либо файлы для создания определенного поведения.Предложенный способ Марка кажется гораздо более разумным подходом к вашей проблеме.
Один из способов — подключить прослушиватель пакетов и прослушивать установки пакетов (и, возможно, также просматривать уже установленные пакеты), а также для каждого пакета генерировать/предоставлять — и устанавливать — фрагмент с нужными файлами свойств.Если это сделать до запуска приложения, это должно иметь эффект.