2009-03-23 15 views
7

Il mio progetto include più plugin e ogni plugin include il file plugin.properties con quasi 20 traduzioni. Il file MANIFEST.MF definisce il nome dei file delle proprietà in cui sono archiviate le stringhe del plugin esterno.meccanismo plugin.properties in eclipse RCP

Bundle-Localization: plugin 

Il nome del plugin definisco come

%plugin.name 

Eclipse cercherà la "% plugin.name" nel file plugin.properties in fase di esecuzione.

Quale classe legge la voce di localizzazione del pacchetto MANIFEST.MF ea quale punto viene cercata la stringa con il suffisso iniziale '%' nel file "plugin.properties"?

Voglio trovare e applicare patch a queste classi in questo modo, che posso prima cercare in qualche altro file/directory per l'identificatore "% plugin.name". Con questo nuovo meccanismo posso aggiungere frammenti al mio prodotto e sovrascrivere singole righe in un file "plugin.properties" senza modificare il plug-in originale. Con questo meccanismo posso creare un processo di compilazione per più clienti semplicemente aggiungendo diversi frammenti. I frammenti includono i nomi dei clienti e la stringa speciale che vogliono cambiare.

Voglio farlo in questo modo, perché il meccanismo dei frammenti aggiunge solo i file al plug-in originale. Quando il file "plugin.properties" è presente nel plug-in, i frammenti "plugin.properties" vengono ignorati.

UPDATE 1:

Il metodo

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

restituisce il ResourceBundle delle proprietà del file per il data stringa locale. Quando qualcuno mostra come posso ora cercare prima nel frammento per ottenere il percorso della risorsa, per favore pubblicatelo.

UPDATE 2:

Il metodo nella classe ManifestLocalization

private URL findInResolved(String filePath, AbstractBundle bundleHost) { 

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

ricerche per le proprietà del file e la cache di esso. Le traduzioni possono essere ottenute dal file memorizzato nella cache. Il problema è che il file completo è memorizzato nella cache e non singole traduzioni.

Una soluzione sarebbe quella di leggere prima il file del frammento, piuttosto che leggere il file del pacchetto. Quando entrambi i file sono esistenti, unirli in un unico file e scrivere il nuovo file delle proprietà sul disco. Ritorna l'URL del nuovo file delle proprietà, in modo che il nuovo file di proprietà possa essere memorizzato nella cache.

risposta

3

Anche se ho sbagliato l'informazione ... Ho avuto esattamente lo stesso problema. Il plug-in non viene attivato due volte e non riesco ad accedere alla chiave Bundle-Localization dei frammenti.

Voglio tutte le mie traduzioni di lingua nel plugin.properties (so che questo è disapprovato ma è molto più facile gestire un singolo file).

I (metà) risolto il problema utilizzando

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

e semplicemente chiamare il mio frammento localizzazione nome del file 'fragment.properties.

Questo non è particolarmente elegante, ma funziona.

A proposito, per ottenere i file dal frammento è necessario getResource, sembra che i file di frammenti si trovino sul percorso di classe o vengano cercati solo quando si utilizza getResource.

Se qualcuno ha un approccio migliore, correggimi.

Tutto il meglio,

Marco.

+0

Dove posso trovare il metodo di popolamento? O devo scriverlo? –

+0

Puoi inserire più informazioni nella tua risposta. Grazie! –

0

Modificare il nome del frammento plugin.properties in qualcos'altro, ad es. fragment.properties

nel frammento manifestare cambiare il Bundle-localizzazione: plug per Bundle-localizzazione: frammento

il plugin sarà attivato due volte, la prima volta con i plugin.properties, il secondo utilizzando il framment.properties.

+0

Ma non posso usare la stessa chiave per un valore diverso. Solo la chiave del plugin viene trovata e restituita. Quando la chiave ricercata viene trovata nel plug-in, il fragmet non è mai aperto. –

0

L'attivazione del plug-in viene gestita da Equinox runtime OSGi. Tuttavia, sconsiglio vivamente di provare a correggere qualsiasi file lì per creare un comportamento specifico. Il modo suggerito da Mark sembra un approccio molto più sano al tuo problema.

+0

Intendi la via suggerita da Mark Miller o da cosa 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

I file getLocalizedEntry bundle.getResource e bundle.getEntry sono richiesti come file sul classpath (quelli trovati nel frammento) necessari per getResource mentre quelli nella radice del plugin (la localizzazione del plugin) richiedono getEntry. Ancora una volta, se qualcuno ha una risposta migliore, fatecelo sapere come sarei interessato. –

+0

Non sono chiaro come utilizzare la classe che hai fornito. Potrebbe essere utilizzato per tradurre ad esempio un nome prospettiva dichiarato in un file plugin.xml, in un modo diverso rispetto a quello nel file bundle.properties? – Peteter

0

Un modo è quello di collegare un ascoltatore fascio, e ascoltare per le installazioni di pacchetti (e forse anche guardare fasci già installate) e per ogni fascio generare/fornire - ed installare - un frammento con i file di proprietà desiderati . Se questo viene fatto prima dell'avvio dell'applicazione, questo dovrebbe avere effetto.