Last active
August 29, 2015 13:56
-
-
Save tschulte/9003397 to your computer and use it in GitHub Desktop.
Use custom ResourceBundle.Control in Eclipse TranslationService and MessageFactoryService
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package custom.translation; | |
import java.util.Dictionary; | |
import java.util.Locale; | |
import java.util.ResourceBundle; | |
import java.util.ResourceBundle.Control; | |
import kam.text.Utf8ResourceTextControl; | |
import org.eclipse.e4.core.internal.services.ResourceBundleHelper; | |
import org.eclipse.osgi.service.localization.BundleLocalization; | |
import org.osgi.framework.Bundle; | |
import org.osgi.framework.Constants; | |
import org.osgi.framework.wiring.BundleWiring; | |
public class CustomBundleLocalization implements BundleLocalization | |
{ | |
@Override | |
public ResourceBundle getLocalization(Bundle bundle, String localeString) | |
{ | |
Dictionary<String, String> headers = bundle.getHeaders(); | |
String bundleName; | |
if (headers == null || (bundleName = headers.get(Constants.BUNDLE_LOCALIZATION)) == null) | |
{ | |
return null; | |
} | |
// TODO: Use Control that talks to the DB instead | |
Control control = new Utf8ResourceTextControl(); | |
ClassLoader classLoader = bundle.adapt(BundleWiring.class).getClassLoader(); | |
Locale locale = ResourceBundleHelper.toLocale(localeString); | |
return ResourceBundle.getBundle(bundleName, locale, classLoader, control); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package custom.translation; | |
import java.net.URI; | |
import java.net.URISyntaxException; | |
import java.util.ResourceBundle; | |
import javax.inject.Inject; | |
import org.eclipse.e4.core.internal.services.BundleTranslationProvider; | |
import org.eclipse.e4.core.internal.services.ServicesActivator; | |
import org.eclipse.osgi.service.localization.BundleLocalization; | |
import org.osgi.framework.Bundle; | |
import org.osgi.service.log.LogService; | |
import org.osgi.service.packageadmin.PackageAdmin; | |
public class CustomTranslationService extends BundleTranslationProvider | |
{ | |
/* | |
* BEGIN: copied from org.eclipse.e4.core.internal.services.BundleTranslationProvider | |
*/ | |
/** | |
* The schema identifier used for Eclipse platform references | |
*/ | |
final private static String PLATFORM_SCHEMA = "platform"; //$NON-NLS-1$ | |
final private static String PLUGIN_SEGMENT = "/plugin/"; //$NON-NLS-1$ | |
final private static String FRAGMENT_SEGMENT = "/fragment/"; //$NON-NLS-1$ | |
/* | |
* END: copied from org.eclipse.e4.core.internal.services.BundleTranslationProvider | |
*/ | |
@Inject | |
private BundleLocalization localization; | |
/* | |
* Partly copied from org.eclipse.e4.core.internal.services.BundleTranslationProvider | |
*/ | |
@Override | |
public String translate(String key, String contributorURI) | |
{ | |
Bundle bundle = getBundle(contributorURI); | |
if (bundle == null) | |
return key; | |
ResourceBundle resourceBundle = localization.getLocalization(bundle, locale); | |
if (resourceBundle == null) | |
return key; | |
return getResourceString(key, resourceBundle); | |
} | |
/* | |
* Copied from org.eclipse.e4.core.internal.services.BundleTranslationProvider | |
*/ | |
private Bundle getBundle(String contributorURI) | |
{ | |
if (contributorURI == null) | |
return null; | |
URI uri; | |
try | |
{ | |
uri = new URI(contributorURI); | |
} | |
catch (URISyntaxException e) | |
{ | |
LogService logService = ServicesActivator.getDefault().getLogService(); | |
if (logService != null) | |
logService.log(LogService.LOG_ERROR, "Invalid contributor URI: " + contributorURI); //$NON-NLS-1$ | |
return null; | |
} | |
if (!PLATFORM_SCHEMA.equals(uri.getScheme())) | |
return null; // not implemented | |
String bundleName = uri.getPath(); | |
if (bundleName.startsWith(PLUGIN_SEGMENT)) | |
bundleName = bundleName.substring(PLUGIN_SEGMENT.length()); | |
else if (bundleName.startsWith(FRAGMENT_SEGMENT)) | |
bundleName = bundleName.substring(FRAGMENT_SEGMENT.length()); | |
PackageAdmin packageAdmin = ServicesActivator.getDefault().getPackageAdmin(); | |
Bundle[] bundles = packageAdmin.getBundles(bundleName, null); | |
if (bundles == null) | |
return null; | |
// Return the first bundle that is not installed or uninstalled | |
for (int i = 0; i < bundles.length; i++) | |
{ | |
if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) | |
{ | |
return bundles[i]; | |
} | |
} | |
return null; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package custom.translation; | |
import javax.annotation.PostConstruct; | |
import org.eclipse.e4.core.contexts.ContextInjectionFactory; | |
import org.eclipse.e4.core.contexts.IEclipseContext; | |
import org.eclipse.e4.core.services.translation.TranslationService; | |
import org.eclipse.osgi.service.localization.BundleLocalization; | |
public class CustomTranslationServiceAddon | |
{ | |
@PostConstruct | |
public void init(IEclipseContext context) | |
{ | |
context.set(BundleLocalization.class, | |
ContextInjectionFactory.make(CalipseBundleLocalization.class, context)); | |
context.set(TranslationService.class, | |
ContextInjectionFactory.make(CalipseTranslationService.class, context)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package custom.translation; | |
import java.io.*; | |
import java.net.*; | |
import java.util.*; | |
import java.util.logging.Logger; | |
/** | |
* This is a special Control for the ResourceBundle, that allows UTF-8 ResourceBundle files. The Idea comes from | |
* http://stackoverflow.com/questions/4659929/how-to-use-utf-8-in-resource-properties-with-resourcebundle. This Control | |
* will have no problems with ResourceBundle-files that are ASCII. Files that where converted with the native2ascii-tool | |
* are no problem. Files in ISO-8859-1 with chars above 127 bit will be auto-detected and the default-java | |
* implementation will be used. | |
* | |
* @author Schulte | |
*/ | |
public class Utf8ResourceTextControl extends ResourceBundle.Control | |
{ | |
private static final Logger LOGGER = Logger.getLogger(Utf8ResourceTextControl.class.getName()); | |
private static final String UNACCEPTABLE_UTF8_CHAR = "\ufffd"; | |
@Override | |
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) | |
throws IllegalAccessException, InstantiationException, IOException | |
{ | |
if (format.equals("java.properties")) | |
{ | |
/* | |
* this is a copy of the base implementation just adding UTF-8 loading (and leaving out the | |
* AccessController.doPrivileged-stuff) | |
*/ | |
String bundleName = toBundleName(baseName, locale); | |
final String resourceName = toResourceName(bundleName, "properties"); | |
InputStream stream = getInputStream(loader, reload, resourceName); | |
if (stream != null) | |
{ | |
try | |
{ | |
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); | |
boolean bomConsumed = consumeBom(reader); | |
if (bomConsumed) | |
{ | |
LOGGER.warning("skipped UTF-8 BOM in " + resourceName); | |
} | |
PropertyResourceBundle bundle = new PropertyResourceBundle(reader); | |
if (!bomConsumed && containsNonUTF8Chars(bundle)) | |
{ | |
// no UTF-8 file use default implementation | |
LOGGER.warning(resourceName + " is no UTF-8 file, trying ISO-8859-1 instead"); | |
return super.newBundle(baseName, locale, format, loader, reload); | |
} | |
return bundle; | |
} | |
finally | |
{ | |
stream.close(); | |
} | |
} | |
} | |
return super.newBundle(baseName, locale, format, loader, reload); | |
} | |
private boolean containsNonUTF8Chars(ResourceBundle bundle) | |
{ | |
for (String key : bundle.keySet()) | |
{ | |
if (key.contains(UNACCEPTABLE_UTF8_CHAR) || bundle.getString(key).contains(UNACCEPTABLE_UTF8_CHAR)) | |
return true; | |
} | |
return false; | |
} | |
/** | |
* If the first char of the BufferedReader is the BOM, this char is consumed. | |
* | |
* @return true, if the bom has been consumed | |
*/ | |
private boolean consumeBom(BufferedReader reader) throws IOException | |
{ | |
char utf8bom = '\ufeff'; | |
reader.mark(1); | |
if (reader.read() == utf8bom) | |
{ | |
return true; | |
} | |
else | |
{ | |
reader.reset(); | |
return false; | |
} | |
} | |
protected InputStream getInputStream(ClassLoader loader, boolean reload, final String resourceName) | |
throws IOException | |
{ | |
if (reload) | |
{ | |
URL url = loader.getResource(resourceName); | |
if (url != null) | |
{ | |
URLConnection connection = url.openConnection(); | |
if (connection != null) | |
{ | |
// Disable caches to get fresh data for | |
// reloading. | |
connection.setUseCaches(false); | |
return connection.getInputStream(); | |
} | |
} | |
} | |
else | |
{ | |
return loader.getResourceAsStream(resourceName); | |
} | |
return null; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment