Eclipse RCP の plugin.properties メカニズム
質問
私のプロジェクトには複数のプラグインが含まれており、各プラグインには 20 近くの翻訳を含む plugin.properties ファイルが含まれています。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);
}
プロパティ ファイルを検索してキャッシュします。翻訳はキャッシュされたファイルから取得できます。問題は、単一の翻訳ではなくファイル全体がキャッシュされることです。
解決策は、バンドル ファイルを読み取るのではなく、最初にフラグメント ファイルを読み取ることです。両方のファイルが存在する場合は、それらを 1 つのファイルにマージし、新しいプロパティ ファイルをディスクに書き込みます。新しいプロパティ ファイルの URL が返されるので、新しいプロパティ ファイルをキャッシュできます。
解決
情報を間違えてしまいましたが…私もまったく同じ問題を抱えていました。プラグインが 2 回アクティブ化されておらず、フラグメントの 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を使用した場合にのみ検索されるようです。
誰かがより良いアプローチを持っている場合は、修正してください。
ではごきげんよう、
マーク。
他のヒント
/**
* 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);
}
}
フラグメントの plugin.properties の名前を別の名前に変更します。フラグメントのプロパティ
あなたのフラグメントでマニフェストはバンドルローカリゼーションを変更します:バンドルローカリゼーションへのプラグイン:断片
プラグインは 2 回アクティブ化されます。1 回目は plugin.properties を使用し、2 回目は Fragment.properties を使用します。
プラグインのアクティブ化は、OSGi ランタイム Equinox によって処理されます。ただし、特定の動作を作成するためにそこにあるファイルにパッチを適用することは強くお勧めしません。マークから提案された方法は、問題に対するはるかに賢明なアプローチのように思えます。
1 つの方法は、バンドル リスナーをアタッチし、バンドルのインストールをリッスンし (おそらく、すでにインストールされているバンドルも確認し)、バンドルごとに、必要なプロパティ ファイルを含むフラグメントを生成/提供し、インストールします。アプリケーションが起動する前にこれを実行すると、効果があるはずです。