Pergunta

Meu projeto inclui vários plugins e cada plugin inclui o arquivo plugin.properties com perto de 20 traduções. O arquivo MANIFEST.MF define o nome dos arquivos de propriedades onde as cordas de plugins externos são armazenados.

Bundle-Localization: plugin

O nome do plugin i definir como

%plugin.name

Eclipse irá procurar o "% plugin.name" no arquivo plugin.properties em tempo de execução.

Qual classe ler a entrada MANIFEST.MF Bundle-Localization e em que ponto é a string com a iniciar '%' sufixo é pesquisado no arquivo "plugin.properties"?

Eu quero encontrar e corrigir estes classe dessa forma, que eu possa primeiro olhar para alguns outros diretórios / arquivos para o identificador "% plugin.name". Com estes novo mecanismo posso adicionar fragmentos para meu produto e linhas simples sobrescrever em um arquivo "plugin.properties" sem alterar o plugin originais. Com estes mecanismo i poderia criar um processo de compilação de vários clientes apenas adicionando diferentes fragmentos. Os fragmentos incluindo os nomes de clientes e corda especial que deseja alterar.

Eu quero fazê-lo dessa maneira, porque o mecanismo fragmento só adicionar arquivos para o plugin originais. Quando o "plugin.properties" arquivo é existente no plugin, os "plugin.properties" fragmentos de arquivos são ignorados.

UPDATE 1:

O método

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

retorna o ResourceBundle do arquivo de propriedades para a string dada localidade. Quando agoras alguém como eu pode agora olhar primeiro para o fragmento para obter o caminho de recursos por favor poste.

UPDATE 2:

O método em ManifestLocalization classe

    private URL findInResolved(String filePath, AbstractBundle bundleHost) {

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

Pesquisas para o arquivo de propriedades e cache-lo. As traduções podem que começa a partir do arquivo em cache. O problema é que o arquivo completo é armazenado em cache e não traduções individuais.

Uma solução seria a primeira ler o arquivo de fragmento, de ler o arquivo de pacote. Quando ambos os arquivos são existente fundi-los em um arquivo e gravar o arquivo novas propriedades para o disco. O URL dos novos retornos propriedades do arquivo, para que o novo arquivo propetries pode cache.

Foi útil?

Solução

Embora eu tenho o errado informações ... Eu tinha exatamente o mesmo problema. O plug-in não é ativado duas vezes e eu não posso chegar aos fragmentos chave Bundle-Localization.

Eu quero que todos os meus traduções de idiomas nos plugin.properties (eu sei que isso é desaprovado, mas é muito mais fácil gerenciar um único arquivo).

I (meia) resolveu o problema usando

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 simplesmente chamar meus fragmento de nome de arquivo de localização 'fragment.properties'.

Isto não é particularmente elegante, mas funciona.

A propósito, para obter arquivos do fragmento é necessário o getResource, parece que os arquivos de fragmento estão no classpath, ou só são procurados quando usando getResource.

Se alguém tem uma abordagem melhor, por favor me corrijam.

Todo o melhor,

Mark.

Outras dicas

/**
 * 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);
    }
}

Alterar o nome de seus plugin.properties fragmento para outra coisa, por exemplo. fragment.properties

no seu fragmento de manifestar a mudança do Bundle-Localization: plugin de para Bundle-Localization: fragmento

Seu plugin será ativado duas vezes, a primeira vez usando os plugin.properties, o segundo usando os fragment.properties.

activação

Plugin é tratado pelo runtime OSGi Equinox. No entanto gostaria fortemente desencorajar a tentar corrigir quaisquer arquivos de lá para criar um comportamento específico. A forma sugerida de Mark parece ser uma abordagem muito mais sensato para o seu problema.

É uma maneira de anexar um ouvinte pacote, e ouvir para instalações de pacotes (e talvez também olhar para pacotes já instalados) e para cada pacote gerar / fornecer - e instalar - um fragmento com os arquivos de propriedade queria. Se isso for feito antes do aplicativo é iniciado, isso deve ter efeito.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top