7

私のプロジェクトには複数のプラグインが含まれており、すべてのプラグインには20近くの翻訳を含むplugin.propertiesファイルが含まれています。MANIFEST.MFファイルは、外部プラグイン文字列が保存されているプロパティファイルの名前を定義します。

Bundle-Localization: plugin

私が定義するプラグインの名前

%plugin.name

Eclipseは、実行時にplugin.propertiesファイルの「%plugin.name」を検索します。

どのクラスがMANIFEST.MFBundle-Localizationエントリを読み取り、どの時点で「plugin.properties」ファイルで「%」という接尾辞が付いた文字列が検索されますか?

この方法でこれらのクラスを見つけてパッチを適用したいので、最初に他のディレクトリ/ファイルで「%plugin.name」識別子を調べます。これらの新しいメカニズムを使用すると、元のプラグインを変更せずに、製品にフラグメントを追加し、「plugin.properties」ファイルの1行を上書きできます。これらのメカニズムを使用すると、さまざまなフラグメントを追加するだけで、複数の顧客向けのビルドプロセスを作成できます。顧客名と変更したい特別な文字列を含むフラグメント。

フラグメントメカニズムは元のプラグインにファイルを追加するだけなので、そのようにしたいです。「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が返されるため、新しいプロパティファイルをキャッシュできます。

4

5 に答える 5

3

情報は間違っていましたが…まったく同じ問題がありました。プラグインが 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 を使用した場合にのみ検索されるようです。

誰かがより良いアプローチをしている場合は、私を修正してください。

ではごきげんよう、

マーク。

于 2009-04-06T09:06:35.587 に答える
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);
    }
}
于 2009-04-29T08:12:53.533 に答える
0

プラグインのアクティブ化は、OSGiランタイムEquinoxによって処理されます。ただし、特定の動作を作成するために、そこにあるファイルにパッチを適用することは強くお勧めしません。マークから提案された方法は、あなたの問題に対してはるかに正しいアプローチのようです。

于 2009-04-03T22:08:58.993 に答える
0

フラグメント plugin.properties の名前を別の名前に変更します。フラグメントのプロパティ

フラグメント マニフェストで、Bundle-Localization: プラグインを Bundle-Localization: fragment に変更します。

プラグインは 2 回アクティブ化されます。1 回目は plugin.properties を使用し、2 回目は fragment.properties を使用します。

于 2009-04-03T09:48:06.807 に答える
0

1 つの方法は、バンドル リスナーをアタッチし、バンドルのインストールをリッスンし (おそらく、既にインストールされているバンドルも確認します)、各バンドルに対して、必要なプロパティ ファイルを含むフラグメントを生成/提供し、インストールします。アプリケーションが起動する前にこれを行うと、効果があるはずです。

于 2010-08-16T15:08:13.717 に答える