2009-03-23 14 views
7

Mi proyecto incluye varios complementos y cada complemento incluye el archivo plugin.properties con cerca de 20 traducciones. El archivo MANIFEST.MF define el nombre de los archivos de propiedades donde se almacenan las cadenas de complementos externos.mecanismo de plugin.properties en eclipse RCP

Bundle-Localization: plugin 

El nombre del plugin defino como

%plugin.name 

Eclipse buscará el "% plugin.name" en el archivo plugin.properties en tiempo de ejecución.

¿Qué clase leyó la entrada MANIFEST.MF Bundle-Localization y en qué punto se busca la cadena con el sufijo inicial '%' en el archivo "plugin.properties"?

Quiero encontrar y aplicar un parche a estas clases de esa manera, que primero puedo buscar en otros directorios/archivos el identificador "% plugin.name". Con este nuevo mecanismo puedo agregar fragmentos a mi producto y sobrescribir líneas individuales en un archivo "plugin.properties" sin cambiar el plugin original. Con estos mecanismos podría crear un proceso de compilación para múltiples clientes simplemente agregando diferentes fragmentos. Los fragmentos incluyen los nombres de los clientes y las cadenas especiales que desean cambiar.

Quiero hacerlo de esa manera, porque el mecanismo de fragmento solo agrega archivos al plugin original. Cuando el archivo "plugin.properties" está en el complemento, los archivos "plugin.properties" del fragmento se ignoran.

ACTUALIZACIÓN 1:

El método

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

devuelve el ResourceBundle del archivo de propiedades para la cadena de localización dada. Cuando alguien dice que ahora puedo examinar primero el fragmento para obtener la ruta del recurso, publíquelo.

ACTUALIZACIÓN 2:

El método en la clase ManifestLocalization

private URL findInResolved(String filePath, AbstractBundle bundleHost) { 

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

busque por el archivo de propiedades y la memoria caché ella. Las traducciones pueden obtenerse del archivo en caché. El problema es que el archivo completo está en caché y no solo las traducciones.

Una solución sería leer primero el archivo de fragmento, que leer el archivo de paquete. Cuando ambos archivos están existentes, combínelos en un archivo y escriba el nuevo archivo de propiedades en el disco. La URL del nuevo archivo de propiedades regresa, de modo que el nuevo archivo de propetries pueda almacenarse en caché.

Respuesta

3

Aunque obtuve la información incorrecta ... tuve exactamente el mismo problema. El complemento no se activa dos veces y no puedo acceder a la clave de Bundle-Localization de fragmentos.

Quiero todas mis traducciones de idiomas en plugin.properties (sé que esto está mal visto, pero es mucho más fácil administrar un solo archivo).

I (medio) resolvió el problema utilizando

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

y simplemente llamar a mi fragmento de localización de nombre de archivo '' fragment.properties.

Esto no es particularmente elegante, pero funciona.

Por cierto, para obtener archivos del fragmento necesita el getResource, parece que los archivos de fragmentos están en el classpath, o solo se buscan cuando se usa getResource.

Si alguien tiene un mejor enfoque, por favor corríjanme.

Todo lo mejor,

Marcos.

+0

¿Dónde puedo encontrar el método populate? ¿O tengo que escribirlo? –

+0

¿Puede poner más información en su respuesta? ¡Gracias! –

0

Cambie el nombre de su fragmento plugin.properties a otra cosa, p. Ej. fragment.properties

en su fragmento de manifestar cambiar el Bundle-Localización: Plugin a Bundle-Localización: fragmento

Tu lector se activa dos veces, la primera vez que utiliza los plugin.properties, utilizando el segundo el fragmento.propiedades.

+0

Pero no puedo usar la misma clave para un valor diferente. Solo la clave del complemento es encontrada y devuelta. Cuando la clave buscada es encontrar en el complemento, el fragmento nunca está abierto –

0

La activación del complemento se maneja mediante el tiempo de ejecución OSGi Equinox. Sin embargo, desaconsejaría encarecidamente intentar parchar cualquier archivo allí para crear un comportamiento específico. La forma sugerida por Mark parece ser un enfoque mucho más sensato para su problema.

+0

¿Te refieres a la forma sugerida por Mark Miller o por qué 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

El getLocalizedEntry bundle.getResource y bundle.getEntry son necesarios ya que los archivos en el classpath (los que se encuentran en el fragmento) necesitan el getResource mientras que los que están en el plugin root (la localización del plugin) requieren getEntry. Una vez más, si alguien tiene una respuesta mejor por favor háganoslo saber, ya que también estaría interesado. –

+0

No tengo claro cómo usar la clase que proporcionó. ¿Podría usarse para traducir, por ejemplo, un nombre de perspectiva declarado en un archivo plugin.xml, de una manera diferente a buscar en el archivo bundle.properties? – Peteter

0

Una forma es adjuntar un oyente paquete, y escuchar para instalaciones de paquetes (y quizás también mirar a los paquetes ya instalados) y para cada haz de generar/proporcionar - e instalar - un fragmento con los archivos de propiedades deseadas . Si esto se hace antes de que la aplicación se inicie, esto debería tener efecto.

Cuestiones relacionadas