blob: 4bc0a2cd42075eb65aec197a5b2a2e5ac9bd03e5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2018 Obeo.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors: Obeo - initial API and implementation
*******************************************************************************/
package org.eclipse.eef.common.api.utils;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.eclipse.emf.common.EMFPlugin;
/**
* Helper class with bundle-independent code, that can be reused by other I18N classes local to each plug-in.
*
* @author pcdavid
*/
public final class I18N {
/**
* Used to mark a {@code public static String} field of a class as an externalized string, whose actual value will
* depend on the locale used at runtime. The optional value corresponds to the key in the {@code ResourceLocator};
* if absent, the name of the field itself is used as key.
*
* @author pcdavid
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface TranslatableMessage {
/**
* The (optional) value of the message key. If absent, the key is assumed to be the same as the Java field's
* name.
*
* @return the message key, if different from the field name.
*/
String[] value() default {};
}
/**
* The constructor.
*/
private I18N() {
// Prevent instantiation
}
/**
* Initializes the value of a class's {@code TranslatableMessage}s using the specified plugin as
* {@code ResourceLocator}.
*
* @param messagesClass
* the class which defines the fields to initialize.
* @param plugin
* the plugin from which to obtain the localized value of the fields.
*/
public static void initializeMessages(final Class<?> messagesClass, final EMFPlugin plugin) {
if (System.getSecurityManager() == null) {
load(plugin, messagesClass);
return;
}
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
load(plugin, messagesClass);
return null;
}
});
}
/**
* Loads the message class with the given {@link EMFPlugin}.
*
* @param plugin
* The plugin
* @param messagesClass
* The message class
*/
private static void load(EMFPlugin plugin, Class<?> messagesClass) {
for (Field field : messagesClass.getDeclaredFields()) {
if (isMessageField(field)) {
initialize(field, plugin);
}
}
}
/**
* Indicates if the given field is a message field.
*
* @param field
* The field
* @return <code>true</code> if the given field is a message field, <code>false</code> otherwise.
*/
private static boolean isMessageField(Field field) {
int mods = field.getModifiers();
boolean modsOK = Modifier.isPublic(mods) && Modifier.isStatic(mods) && !Modifier.isFinal(mods);
return modsOK && field.isAnnotationPresent(I18N.TranslatableMessage.class) && field.getType() == String.class;
}
/**
* Initializes the given field used the plugin.
*
* @param field
* The field to initialize
* @param plugin
* The plugin
*/
private static void initialize(Field field, EMFPlugin plugin) {
String key = getKey(field);
String value = plugin.getString(key);
if (!field.isAccessible()) {
field.setAccessible(true);
}
try {
field.set(null, value);
} catch (IllegalArgumentException e) {
plugin.log(e);
} catch (IllegalAccessException e) {
plugin.log(e);
}
}
/**
* Returns the key for the given field.
*
* @param field
* The field
* @return The key of the field
*/
private static String getKey(Field field) {
I18N.TranslatableMessage annot = field.getAnnotation(I18N.TranslatableMessage.class);
String[] key = annot.value();
if (key == null || key.length == 0) {
key = new String[] { field.getName() };
}
return key[0];
}
}