2009-03-23 8 views
7

Mein Projekt enthält mehrere Plugins und jedes Plugin enthält die Datei plugin.properties mit fast 20 Übersetzungen. Die Datei MANIFEST.MF definiert den Namen der Eigenschaftendateien, in denen die externen Plug-in-Strings gespeichert sind.plugin.properties Mechanismus in Eclipse RCP

Bundle-Localization: plugin 

Der Name des Plug-i wie

definieren
%plugin.name 

Eklipse die "% plugin.name" suchen in der plugin.properties Datei zur Laufzeit.

Welche Klasse liest den Eintrag MANIFEST.MF Bundle-Localization aus und an welcher Stelle wird die Zeichenkette mit dem Suffix '%' in der Datei "plugin.properties" gesucht?

Ich möchte diese Klasse auf diese Weise finden und patchen, dass ich zuerst in einigen anderen Verzeichnissen/Dateien nach dem "% plugin.name" Bezeichner suchen kann. Mit diesem neuen Mechanismus kann ich Fragmente zu meinem Produkt hinzufügen und einzelne Zeilen in einer "plugin.properties" -Datei überschreiben, ohne das ursprüngliche Plugin zu ändern. Mit diesen Mechanismen konnte ich einen Build-Prozess für mehrere Kunden erstellen, indem Sie einfach verschiedene Fragmente hinzufügen. Die Fragmente einschließlich der Kundennamen und der speziellen Zeichenfolge, die sie ändern möchten.

Ich möchte es so machen, weil der Fragmentmechanismus nur Dateien zum ursprünglichen Plugin hinzufügt. Wenn die Datei "plugin.properties" im Plugin vorhanden ist, wird das Fragment "plugin.properties" ignoriert.

UPDATE 1:

Verfahren

class ManifestLocalization{ 
... 
protected ResourceBundle getResourceBundle(String localeString) { 
} 
... 
} 

kehrt die Resource der Eigenschaften für den gegebenen locale String-Datei. Wenn jemand jetzt weiß, wie ich jetzt zuerst in das Fragment schauen kann, um den Ressourcenpfad zu bekommen, bitte posten Sie es.

UPDATE 2:

Die Methode in der Klasse ManifestLocalization

private URL findInResolved(String filePath, AbstractBundle bundleHost) { 

     URL result = findInBundle(filePath, bundleHost); 
     if (result != null) 
      return result; 
     return findInFragments(filePath, bundleHost); 
    } 

Suchen für die Eigenschaften-Datei und die Cache-es. Die Übersetzungen können dann aus der zwischengespeicherten Datei abgerufen werden. Das Problem ist, dass die komplette Datei zwischengespeichert wird und nicht einzelne Übersetzungen.

Eine Lösung wäre, zuerst die Fragmentdatei zu lesen, dann die Bundle-Datei zu lesen. Wenn beide Dateien vorhanden sind, führen Sie sie in eine Datei zusammen und schreiben Sie die neue Eigenschaftendatei auf den Datenträger. Die URL der neuen Eigenschaftendatei wird zurückgegeben, sodass die neue Property-Datei zwischengespeichert werden kann.

Antwort

3

Obwohl ich die Informationen falsch bekam ... hatte ich genau das gleiche Problem. Das Plugin wird nicht zweimal aktiviert und ich kann nicht zu den Paketschlüssel-Lokalisierungsschlüsseln gelangen.

Ich möchte alle meine Übersetzungen in die plugin.properties (ich weiß, das ist verpönt, aber es ist viel einfacher, eine einzelne Datei zu verwalten).

I (halb) lösten das Problem, indem sie

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()))); 
} 

verwenden und einfach meinen Fragment Lokalisierungsdateinamen 'fragment.properties' nennen.

Dies ist nicht besonders elegant, aber es funktioniert.

Übrigens, um Dateien aus dem Fragment zu erhalten, benötigen Sie die getResource, es scheint, dass Fragmentdateien im Klassenpfad sind oder nur bei Verwendung von getResource gesucht werden.

Wenn jemand einen besseren Ansatz hat, bitte korrigieren Sie mich.

Alles Gute,

Mark.

+0

Wo kann ich die populate Methode finden? Oder muss ich es schreiben? –

+0

Können Sie bitte mehr Informationen in Ihre Antwort einfügen. Vielen Dank! –

0

Ändern Sie den Namen Ihres Fragments plugin.properties in etwas anderes, z. Plugin zu Bundle-Lokalisierung: fragment.properties

in Ihrem Fragmente Manifest die Bundle-Lokalisierung ändern Fragment

Ihr Plugin zweimal aktiviert wird, zum ersten Mal der plugin.properties verwendet wird, unter Verwendung der zweiten die fragment.properties.

+0

Aber ich kann den gleichen Schlüssel nicht für einen anderen Wert verwenden. Nur der Plugin-Schlüssel wird gefunden und zurückgegeben. Wenn der gesuchte Schlüssel im Plugin gefunden wird, ist das fragmet niemals geöffnet –

0

Plugin-Aktivierung wird von der OSGi Runtime Equinox behandelt. Ich rate jedoch dringend davon ab, irgendwelche Dateien dort zu patchen, um ein bestimmtes Verhalten zu erzeugen. Der vorgeschlagene Weg von Mark scheint ein viel vernünftigerer Ansatz für Ihr Problem zu sein.

+0

Meinst du den vorgeschlagenen Weg von Mark Miller oder was Mark? :) – Peteter

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); 
    } 
} 
+0

GetLocalizedEntry bundle.getResource und bundle.getEntry sind erforderlich, da Dateien im Klassenpfad (die im Fragment gefunden werden) für die getResource benötigt werden, während die im plugin root (die Plugin-Lokalisierung) den Befehl getEntry benötigen. Noch einmal, wenn jemand eine bessere Antwort hat, lassen Sie es uns bitte wissen, als würde mich auch interessieren. –

+0

Ich bin unklar, wie Sie die Klasse verwenden, die Sie bereitgestellt haben. Könnte es zum Beispiel für die Übersetzung eines in einer Datei plugin.xml deklarierten Perspektivennamens verwendet werden, anders als in der Datei bundle.properties? – Peteter

0

Eine Möglichkeit ist, ein Bündel Hörer zu befestigen und für Installationen von Bündeln hören (und vielleicht auch bei bereits installierten Paketen suchen) und für jedes Bündel erzeugen/liefern - und installieren - ein Fragment mit den gewünschten Eigenschaftsdateien . Wenn dies vor dem Start der Anwendung erfolgt, sollte dies Auswirkungen haben.