2009-03-23 7 views
7

내 프로젝트에 여러 개의 플러그인이 포함되어 있으며 모든 플러그인에는 20 개에 가까운 번역이 포함 된 plugin.properties 파일이 포함되어 있습니다. MANIFEST.MF 파일은 외부 플러그인 문자열이 저장된 특성 파일의 이름을 정의합니다.Eclipse의 plugin.properties 메커니즘 RCP

Bundle-Localization: plugin 

내가 이클립스 런타임시 plugin.properties 파일에 "%의 plugin.name"를 검색합니다

%plugin.name 

같이 정의 플러그인의 이름입니다.

"plugin.properties"파일에서 MANIFEST.MF Bundle-Localization 항목을 읽고 클래스의 시작 부분에 '%'접미사가있는 문자열을 검색하는 클래스는 무엇입니까?

"% plugin.name"식별자에 대해 다른 디렉토리/파일을 먼저 조사 할 수 있도록이 클래스를 찾아서 패치하고 싶습니다. 이러한 새로운 메커니즘을 사용하면 제품에 단편을 추가하고 원래 플러그인을 변경하지 않고 "plugin.properties"파일에서 한 줄을 덮어 쓸 수 있습니다. 이러한 메커니즘을 사용하면 여러 조각을 추가하여 여러 고객을위한 빌드 프로세스를 만들 수 있습니다. 변경하려는 고객 이름 및 특수 문자열을 포함한 조각입니다.

조각 메커니즘은 원래 플러그인에 파일을 추가하기 때문에 그렇게하고 싶습니다. "plugin.properties"파일이 플러그인에 있으면 "plugin.properties"단편은 무시됩니다.

UPDATE 1 :

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

반환 속성의 ResourceBundle의 지정된 로케일에 문자열을 파일

방법. 누가 리소스 경로를 가져 오기 위해 먼저 조각을 조사 할 수 있는지 알려주세요.

업데이트 2 : 클래스의 속성에 대한

private URL findInResolved(String filePath, AbstractBundle bundleHost) { 

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

검색 수는 파일 ManifestLocalization로 캐쉬에

방법. 번역은 캐시 된 파일에서 가져올 수 있습니다. 문제는 전체 파일이 캐시되고 단일 변환이 아니라는 것입니다.

해결책은 번들 파일을 읽는 것보다 먼저 조각 파일을 읽는 것입니다. 두 파일이 모두 존재할 때 파일을 하나의 파일로 병합하고 새 특성 파일을 디스크에 작성하십시오. 새 특성 파일의 URL이 리턴되어 새 특성 파일이 캐시 될 수 있습니다.

답변

3

비록 정보가 잘못되었지만 ... 똑같은 문제가있었습니다. 플러그인이 두 번 활성화되지 않아 조각 번들 현지화 키를 가져올 수 없습니다.

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를 사용할 때만 검색되는 것 같습니다.

누군가가 더 나은 접근법을 가지고 있다면, 나를 교정하십시오.

모두 최고,

마크. 설치 - - 조각을 원하는 속성 파일

+0

어디 populate 메서드를 찾을 수 있습니까? 또는 그것을 작성해야합니까? –

+0

답변에 더 많은 정보를 입력 할 수 있습니까? 고맙습니다! –

0

조각 plugin.properties의 이름을 다른 것으로 변경하십시오. 당신의 조각에 fragment.properties

는 번들 - 현지화를 변경 매니페스트 : 플러그인 을 번들 - 현지화에 : 조각

귀하의 플러그인이 plugin.properties를 사용하여, 두 번 처음으로 활성화됩니다, 두 번째를 사용하여 fragments.properties.

+0

하지만 다른 값으로 동일한 키를 사용할 수 없습니다. 플러그인 키만 찾아서 반환합니다. 검색된 키가 플러그인에서 발견되면 fragmet은 결코 열리지 않습니다 –

0

플러그인 활성화는 OSGi 런타임 퀴녹스에 의해 처리됩니다. 그러나 특정 동작을 만들기 위해 파일을 패치하려고하지 않는 것이 좋습니다. 마크의 제안 된 방법은 문제에 훨씬 더 정숙한 접근 방법입니다.

+0

마크 밀러 (Mark Miller) 또는 마크 (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 및 bundle.getEntry는 클래스 경로의 파일 (조각에있는 파일)에 getResource가 필요한 반면, 플러그인 루트 (플러그인 로컬 리 제이션)에는 getEntry가 필요하므로 필요합니다. 또 다른 사람이 더 좋은 답변을 가지고 있다면 알려 주시기 바랍니다. –

+0

제공하신 수업을 어떻게 사용하는지 잘 모르겠습니다. 예를 들어 bundle.properties 파일을 보는 것과는 다른 방식으로 plugin.xml 파일에 선언 된 퍼스펙티브 이름을 번역하는 데 사용할 수 있습니까? – Peteter

0

한 가지 방법은 번들 리스너를 첨부하고 번들 설치를 수신 (아마도 이미 설치 번들보고) 각 번들 생성/제공하는 것입니다 . 응용 프로그램이 시작되기 전에이 작업이 완료되면이 작업이 수행되어야합니다.