Eclipse RCP의 Plugin.properties 메커니즘
문제
내 프로젝트에는 여러 플러그인이 포함되어 있으며 모든 플러그인에는 플러그인이 포함되어 있습니다. manifest.mf 파일 외부 플러그인 문자열이 저장된 속성 파일의 이름을 정의합니다.
Bundle-Localization: plugin
내가 정의하는 플러그인의 이름
%plugin.name
Eclipse는 런타임에 Plugin.Properties 파일에서 "%plugin.name"을 검색합니다.
어떤 클래스가 매니페스트를 읽었는지 MF 번들 로컬 화 항목을 읽고 시작 '%'접미사가 "플러그인 .properties"파일에서 검색되는 문자열은 어느 시점입니까?
이 클래스를 찾아 패치하고 싶습니다. 먼저 "%plugin.name"식별자에 대한 다른 디렉토리/파일을 살펴볼 수 있습니다. 이 새로운 메커니즘을 사용하면 제품에 조각을 추가하고 원래 플러그인을 변경하지 않고 "플러그인 .properties"파일로 단일 라인을 덮어 쓸 수 있습니다. 이러한 메커니즘을 사용하여 다른 조각을 추가하여 여러 고객을위한 빌드 프로세스를 만들 수 있습니다. 고객 이름과 변경하려는 특수 문자열을 포함한 조각.
조각 메커니즘은 원래 플러그인에 파일 만 추가하기 때문에 그렇게하고 싶습니다. 플러그인에 "plugin.properties"파일이 존재하는 경우 조각 "플러그인 .properties"파일이 무시됩니다.
UPDATE 1:
방법
class ManifestLocalization{
...
protected ResourceBundle getResourceBundle(String localeString) {
}
...
}
주어진 로케일 문자열에 대한 속성 파일의 ResourceBundle을 반환합니다. 누군가가 이제 내가 어떻게 먼저 조각을 조사하여 자원 경로를 얻을 수있는 방법을 게시 할 수있는 방법을 게시하십시오.
UPDATE 2:
클래스 증상의 방법
private URL findInResolved(String filePath, AbstractBundle bundleHost) {
URL result = findInBundle(filePath, bundleHost);
if (result != null)
return result;
return findInFragments(filePath, bundleHost);
}
속성 파일을 검색하고 캐시합니다. 번역은 캐시 된 파일에서 얻을 수 있습니다. 문제는 전체 파일이 캐시되고 단일 번역이 아니라는 것입니다.
솔루션은 먼저 번들 파일을 읽는 것보다 Fragment 파일을 읽는 것입니다. 두 파일이 모두 존재하면 하나의 파일로 병합되어 새 속성 파일을 디스크에 씁니다. 새 속성 파일의 URL이 반환되므로 새 Proptries 파일이 캐시 될 수 있습니다.
해결책
정보가 잘못되었지만 ... 정확히 같은 문제가있었습니다. 플러그인은 두 번 활성화되지 않았으며 Fragments 번들 로컬 화 키에 도달 할 수 없습니다.
플러그인의 모든 언어 번역을 원합니다.
나는 (절반)을 사용하여 문제를 해결했습니다
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);
}
}
조각 플러그인의 이름을 다른 것으로 변경하십시오. Fragment.properties
파편 매니페스트에서 번들로 국소화 : 플러그인으로 플러그인을 번들로 국소화 : 파편
플러그인 .properties를 사용하여 처음으로 플러그인이 두 번 활성화되고 두 번째는 Fragment.Properties를 사용합니다.
플러그인 활성화는 OSGI 런타임 Equinox에 의해 처리됩니다. 그러나 특정 동작을 만들기 위해 파일을 패치하려고 시도하지 않을 것입니다. Mark의 제안 된 방법은 문제에 대한 훨씬 더 세심한 접근 방식으로 보입니다.
한 가지 방법은 번들 리스너를 부착하고 번들 설치 (그리고 이미 설치된 번들을 살펴 보는 것)와 각 번들에 대해 원하는 속성 파일이있는 조각을 생성하고 설치하는 것입니다. 응용 프로그램이 시작되기 전에이 작업이 완료되면 효과가 있어야합니다.