| /******************************************************************************* |
| * Copyright (c) 2005, 2011 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.equinox.metatype.impl; |
| |
| import java.io.IOException; |
| import java.net.URL; |
| import java.util.*; |
| import org.osgi.framework.Bundle; |
| |
| public abstract class LocalizationElement { |
| public static final char KEY_SIGN = '%'; |
| public static final char LOCALE_SEP = '_'; |
| |
| /* |
| * Internal Method - to get resource bundle. |
| */ |
| private static ResourceBundle getResourceBundle(String resourceBase, String locale, Bundle bundle) { |
| |
| // There are seven searching candidates possible: |
| // baseName + |
| // "_" + language1 + "_" + country1 + "_" + variation1 + ".properties" |
| // or "_" + language1 + "_" + country1 + ".properties" |
| // or "_" + language1 + ".properties" |
| // or "_" + language2 + "_" + country2 + "_" + variation2 + ".properties" |
| // or "_" + language2 + "_" + country2 + ".properties" |
| // or "_" + language2 + ".properties" |
| // or "" + ".properties" |
| // |
| // Where language1[_country1[_variation1]] is the requested locale, |
| // and language2[_country2[_variation2]] is the default locale. |
| |
| String[] searchCandidates = new String[7]; |
| |
| // Candidates from passed locale: |
| if (locale != null && locale.length() > 0) { |
| int idx1_first = locale.indexOf(LOCALE_SEP); |
| if (idx1_first == -1) { |
| // locale has only language. |
| searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale; |
| } else { |
| // locale has at least language and country. |
| searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_first); |
| int idx1_second = locale.indexOf(LOCALE_SEP, idx1_first + 1); |
| if (idx1_second == -1) { |
| // locale just has both language and country. |
| searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale; |
| } else { |
| // locale has language, country, and variation all. |
| searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_second); |
| searchCandidates[0] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale; |
| } |
| } |
| } |
| |
| // Candidates from Locale.getDefault(): |
| String defaultLocale = Locale.getDefault().toString(); |
| int idx2_first = defaultLocale.indexOf(LOCALE_SEP); |
| int idx2_second = defaultLocale.indexOf(LOCALE_SEP, idx2_first + 1); |
| if (idx2_second != -1) { |
| // default-locale is format of [language]_[country]_variation. |
| searchCandidates[3] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale; |
| if (searchCandidates[3].equalsIgnoreCase(searchCandidates[0])) { |
| searchCandidates[3] = null; |
| } |
| } |
| if ((idx2_first != -1) && (idx2_second != idx2_first + 1)) { |
| // default-locale is format of [language]_country[_variation]. |
| searchCandidates[4] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + ((idx2_second == -1) ? defaultLocale : defaultLocale.substring(0, idx2_second)); |
| if (searchCandidates[4].equalsIgnoreCase(searchCandidates[1])) { |
| searchCandidates[4] = null; |
| } |
| } |
| if ((idx2_first == -1) && (defaultLocale.length() > 0)) { |
| // default-locale has only language. |
| searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale; |
| } else if (idx2_first > 0) { |
| // default-locale is format of language_[...]. |
| searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale.substring(0, idx2_first); |
| } |
| if (searchCandidates[5] != null && searchCandidates[5].equalsIgnoreCase(searchCandidates[2])) { |
| searchCandidates[5] = null; |
| } |
| |
| // The final candidate. |
| searchCandidates[6] = ""; //$NON-NLS-1$ |
| |
| URL resourceUrl = null; |
| URL[] urls = null; |
| |
| for (int idx = 0; (idx < searchCandidates.length) && (resourceUrl == null); idx++) { |
| urls = (searchCandidates[idx] == null ? null : FragmentUtils.findEntries(bundle, resourceBase + searchCandidates[idx] + MetaTypeProviderImpl.RESOURCE_FILE_EXT)); |
| if (urls != null && urls.length > 0) |
| resourceUrl = urls[0]; |
| } |
| |
| if (resourceUrl != null) { |
| try { |
| return new PropertyResourceBundle(resourceUrl.openStream()); |
| } catch (IOException ioe) { |
| // Exception when creating PropertyResourceBundle object. |
| } |
| } |
| return null; |
| } |
| |
| private final String localization; |
| |
| // @GuardedBy("this") |
| private Bundle bundle; |
| // @GuardedBy("this") |
| private String locale; |
| // @GuardedBy("this") |
| private Map<String, ResourceBundle> resourceBundleCache; |
| |
| public LocalizationElement(String localization) { |
| this.localization = localization; |
| } |
| |
| String getLocalization() { |
| return localization; |
| } |
| |
| /** |
| * Method to get the localized text of inputed String. |
| */ |
| protected String getLocalized(String key) { |
| if (key == null) { |
| return null; |
| } |
| if ((key.length() > 1) && (key.charAt(0) == KEY_SIGN)) { |
| ResourceBundle rb = getResourceBundle(); |
| if (rb != null) { |
| try { |
| String transfered = rb.getString(key.substring(1)); |
| if (transfered != null) { |
| return transfered; |
| } |
| } catch (MissingResourceException mre) { |
| // Nothing found for this key. |
| } |
| } |
| // If no localization file available or no localized value found |
| // for the key, then return the raw data without the key-sign. |
| return key.substring(1); |
| } |
| return key; |
| } |
| |
| /* |
| * This method must be (and currently is) called after setLocaleAndBundle(String, Bundle). |
| * If the bundle is not set, an NPE will be generated by getResourceBundle(String, String, Bundle). |
| */ |
| protected synchronized ResourceBundle getResourceBundle() { |
| // Determine the base name of the bundle localization property files. |
| // If the <MetaData> 'localization' attribute was not specified, |
| // use the Bundle-Localization manifest header value instead if it exists. |
| String resourceBase = localization != null ? localization : MetaTypeProviderImpl.getBundleLocalization(bundle); |
| long bundleId = bundle.getBundleId(); |
| String key = (locale != null) ? bundleId + ":" + locale + ":" + resourceBase : bundleId + ":" + resourceBase; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| ResourceBundle resourceBundle = resourceBundleCache.get(key); |
| |
| if (resourceBundle == null) { |
| resourceBundle = getResourceBundle(resourceBase, locale, bundle); |
| if (resourceBundle != null) { |
| resourceBundleCache.put(key, resourceBundle); |
| } |
| } |
| return resourceBundle; |
| } |
| |
| /* |
| * This method must be (and currently is) called before getResourceBundle(). |
| * If the bundle is not set, an NPE will be generated by getResourceBundle(String, String, Bundle). |
| */ |
| protected synchronized void setLocaleAndBundle(String locale, Bundle bundle, Map<String, ResourceBundle> resourceBundleCache) { |
| this.locale = locale; |
| this.bundle = bundle; |
| this.resourceBundleCache = resourceBundleCache; |
| } |
| } |