![](/img/trans.png)
[英]Java internationalization - Do I have to load a resource bundle for every class?
[英]In Java how do I find out what languages I have available my Resource Bundle
我有一些資源包打包在我的主 jar
widget_en.properties
widget_de.properties
我根據我的默認語言環境檢索資源包,如下所示
ResourceBundle.getBundle("widget", Locale.getDefault());
但我想向用戶提供支持的可用語言列表,以便 select 一種可能與他們的計算機默認設置不同的語言
但是我在 ResourceBundle 中找不到可以列出可用語言環境的方法,我不想對列表進行硬編碼,因為我可能會在添加另一個資源包時忘記更新它。
編輯
因為我只有不同語言的資源包(我沒有國家細化)所以我通過遍歷所有已知的語言代碼生成了一個列表並將每個語言代碼檢查為資源。
String[]langs = Locale.getISOLanguages();
for(String lang:langs)
{
URL rb = ClassLoader.getSystemResource("widget_"+lang+".properties");
if(rb!=null)
{
System.out.println("Found:"+rb.toString());
}
}
如果你真的打包JAR 里面的資源文件,然后我會做這樣的:
public static void main(String[] args) {
Set<ResourceBundle> resourceBundles = getResourceBundles(A.class.getName());
if (resourceBundles.isEmpty())
// ...
}
public static Set<ResourceBundle> getResourceBundles(String baseName) {
Set<ResourceBundle> resourceBundles = new HashSet<>();
for (Locale locale : Locale.getAvailableLocales()) {
try {
resourceBundles.add(ResourceBundle.getBundle(baseName, locale));
} catch (MissingResourceException ex) {
// ...
}
}
return Collections.unmodifiableSet(resourceBundles);
}
如果您關心JAR,那么至少會得到一個包含給定baseName
默認資源的集合。
如果您只有諸如baseName_<country>
類的資源,則此方法可以完美地工作,因為只有那些ResourceBundles
將被添加到JAR中存在的集合中。 即使您決定需要分開的baseName_en_US
和baseName_en_UK
資源,它也可以正常工作。
無恥的自我插入:我編寫了一個ResourceBundle.Control
,它以Charset
作為參數,如果要加載UTF-8編碼的資源文件,可能會對它感興趣。 它可以在GitHub上獲得。
我認為沒有API,因為可以即時創建新的有效語言環境對象:
Locale locale = new Locale("abcd");
無需在某個地方注冊。 然后,您可以不受限制地使用資源包widget_abcd.properties
:
ResourceBundle resource= ResourceBundle.getBundle("widget", new Locale("abcd"));
從java.util.Locale
API文檔中:
因為Locale對象只是區域的標識符,所以在構造Locale時不執行有效性檢查。 如果要查看特定資源是否可用於您構造的語言環境,則必須查詢這些資源。
為了解決該問題,您仍然可以遍歷資源目錄中所有名為“ widget_”的文件,並發現新添加的資源束。
請注意,由於上述原因, Locale.getAvailableLocales()
並非100%可靠 :您可能有一天會定義非標准語言環境。 但是,如果僅添加一些標准語言環境,則可以使用此靜態方法遍歷系統語言環境並獲取相應的捆綁軟件。
如果可以做出兩個基本假設:
1)您有一個默認的資源包,其中沒有語言環境,或者至少有一個您知道的語言環境。
2)您所有的資源都在相同的位置(即,單個jar文件中的相同路徑)
然后,您可以獲得單個資源的URL:
URL url = SomeClass.class.getClassLoader().getResource("widget.properties");
一旦有了它,就應該能夠解析URL。
如果使用commons-vfs,則應該能夠將URL轉換為FileObject:
FileSystemManager manager = VFS.getManager();
FileObject resource = manager.resolveFile(url.toExternalForm());
FileObject parent = resource.getParent();
FileObject children[] = parent.getChildren();
// figure out which ones are bundles, and parse the names into a list of locales.
這將節省您處理jar:樣式url之類的復雜性的麻煩,因為vfs會為您處理。
通過列出文件來解決。
public class JavaApplication1 {
public static final ArrayList<String> LOCALES = new ArrayList<>();
static {
try {
File f = new File(JavaApplication1.class.getResource("/l10n").toURI());
final String bundle = "widget_";// Bundle name prefix.
for (String s : f.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith(bundle);
}
})) {
LOCALES.add(s.substring(bundle.length(), s.indexOf('.')));
}
} catch (URISyntaxException x) {
throw new RuntimeException(x);
}
LOCALES.trimToSize();
}
...
}
這是我的解決方案,希望可以幫助人們。
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
import org.apache.commons.io.filefilter.PrefixFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang3.StringUtils;
private static Locale[] getAvailableLocales(String name) {
String path = thisClass.class.getClassLoader().getResource("").getPath();
if (path.contains("%20")) {
path = path.replaceFirst("%20", " ");
}
File file = new File(path);
Locale[] array = FileUtils.listFiles(file, new AndFileFilter(new PrefixFileFilter(name), new SuffixFileFilter(".properties")),null)
.stream()
.map(File::getName)
.map(v -> StringUtils.substringBetween(v, name + '_', ".properties"))
.map(v->v.replaceFirst("_","-"))
.map(Locale::forLanguageTag)
.toArray(Locale[]::new);
return array;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.