Skip to content

Commit

Permalink
Extend automatic i18n support to Tab and MenuItem
Browse files Browse the repository at this point in the history
  • Loading branch information
aalmiray committed Dec 1, 2016
1 parent 8312cb7 commit 72da1ab
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The Griffon team is happy to announce the release of Griffon 2.9.0!
The following list summarizes the changes brought by this release:

* Action properties can react to application `Locale` changes.
* `Labeled` nodes can react to application `Locale` changes.
* `Labeled`, `Tab` and `MenuItem` nodes can react to application `Locale` changes.
* `JavaFXAction` has the following updates:
** `style`: used to set style on the bound widget.
** `graphic`: used to set the graphic node on the bound widget.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Andres Almiray

=== Dependencies

No dependencies updated in this release.
The following dependencies have been upgraded

* org.jetbrains.kotlin:kotlin-stdlib:1.0.5-2

=== Runtime

Expand All @@ -24,9 +26,9 @@ Any properties configured via `messages.properties` will be refreshed when the a

==== JavaFX Support

`Labeled` nodes can react to changes made to the application's `Locale` provided you supply enough information to resolve
the target message. `JavaFXUtils` exposes 3 new properties and 1 connect method to make this feature work. You may use
these properties with FXML, for example
`Labeled`, `Tab` and `MenuItem` nodes can react to changes made to the application's `Locale` provided you supply enough
information to resolve the target message. `JavaFXUtils` exposes 3 new properties and 1 connect method to make this feature
work. You may use these properties with FXML, for example

[source, xml]
[subs="verbatim"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,88 @@ public final class JavaFXUtils {
private static final String ERROR_APPLICATION_NULL = "Argument 'application' must not be null";
private static final String ACTION_TARGET_SUFFIX = "ActionTarget";
private static final String PROPERTY_SUFFIX = "Property";
private static final String SUFFIX_KEY = "-KEY";
private static final String SUFFIX_ARGS = "-ARGS";
private static final String SUFFIX_DEFAULT_VALUE = "-DEFAULT_VALUE";

private JavaFXUtils() {

}

/**
* Finds out if an i18n {@code key} has been registered with the target {@code Node}, returning the key if found.
*
* @param node the target node on which the key may have been registered.
*
* @return the key registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nKey(@Nonnull Labeled node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_KEY);
}

/**
* Associates an i18n arrays of arguments to a {@code node}.
* These arguments will be used alongside a key to resolve a message via the application's {@code MessageSource}.
*
* @param node the target node on which the key will be registered.
* @param args the array of arguments to be registered.
*
* @since 2.9.0
*/
public static void setI18nArgs(@Nonnull Labeled node, @Nullable String args) {
requireNonNull(node, ERROR_NODE_NULL);
requireNonBlank(args, ERROR_ARGS_BLANK);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_ARGS, args);
}

/**
* Finds out if an {@code arguments array} has been registered with the target {@code Node}, returning the array if found.
*
* @param node the target node on which the arguments may have been registered.
*
* @return the arguments registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nArgs(@Nonnull Labeled node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_ARGS);
}

/**
* Associates an default value {@code node}.
* The value will be used alongside a key to resolve a message via the application's {@code MessageSource}.
*
* @param node the target node on which the key will be registered.
* @param defaultValue the value to be registered.
*
* @since 2.9.0
*/
public static void setI18nDefaultValue(@Nonnull Labeled node, @Nullable String defaultValue) {
requireNonNull(node, ERROR_NODE_NULL);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE, defaultValue);
}

/**
* Finds out if a {@code default value} has been registered with the target {@code Node}, returning the value if found.
*
* @param node the target node on which the value may have been registered.
*
* @return the value registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nDefaultValue(@Nonnull Labeled node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE);
}

/**
* Associates an i18n key to a {@code node}. The key is used to resolve a message via the application's {@code MessageSource}.
*
Expand All @@ -112,10 +189,10 @@ private JavaFXUtils() {
*
* @since 2.9.0
*/
public static void setI18nKey(@Nonnull Labeled node, @Nonnull String key) {
public static void setI18nKey(@Nonnull Tab node, @Nonnull String key) {
requireNonNull(node, ERROR_NODE_NULL);
requireNonBlank(key, ERROR_KEY_BLANK);
node.getProperties().put(MessageSource.class.getName() + "-KEY", key);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_KEY, key);
}

/**
Expand All @@ -128,9 +205,9 @@ public static void setI18nKey(@Nonnull Labeled node, @Nonnull String key) {
* @since 2.9.0
*/
@Nullable
public static String getI18nKey(@Nonnull Labeled node) {
public static String getI18nKey(@Nonnull Tab node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + "-KEY");
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_KEY);
}

/**
Expand All @@ -142,10 +219,10 @@ public static String getI18nKey(@Nonnull Labeled node) {
*
* @since 2.9.0
*/
public static void setI18nArgs(@Nonnull Labeled node, @Nullable String args) {
public static void setI18nArgs(@Nonnull Tab node, @Nullable String args) {
requireNonNull(node, ERROR_NODE_NULL);
requireNonBlank(args, ERROR_ARGS_BLANK);
node.getProperties().put(MessageSource.class.getName() + "-ARGS", args);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_ARGS, args);
}

/**
Expand All @@ -158,9 +235,9 @@ public static void setI18nArgs(@Nonnull Labeled node, @Nullable String args) {
* @since 2.9.0
*/
@Nullable
public static String getI18nArgs(@Nonnull Labeled node) {
public static String getI18nArgs(@Nonnull Tab node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + "-ARGS");
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_ARGS);
}

/**
Expand All @@ -172,9 +249,9 @@ public static String getI18nArgs(@Nonnull Labeled node) {
*
* @since 2.9.0
*/
public static void setI18nDefaultValue(@Nonnull Labeled node, @Nullable String defaultValue) {
public static void setI18nDefaultValue(@Nonnull Tab node, @Nullable String defaultValue) {
requireNonNull(node, ERROR_NODE_NULL);
node.getProperties().put(MessageSource.class.getName() + "-DEFAULT_VALUE", defaultValue);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE, defaultValue);
}

/**
Expand All @@ -187,36 +264,179 @@ public static void setI18nDefaultValue(@Nonnull Labeled node, @Nullable String d
* @since 2.9.0
*/
@Nullable
public static String getI18nDefaultValue(@Nonnull Labeled node) {
public static String getI18nDefaultValue(@Nonnull Tab node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE);
}

/**
* Associates an i18n key to a {@code node}. The key is used to resolve a message via the application's {@code MessageSource}.
*
* @param node the target node on which the key will be registered.
* @param key the message key to be registered.
*
* @since 2.9.0
*/
public static void setI18nKey(@Nonnull MenuItem node, @Nonnull String key) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + "-DEFAULT_VALUE");
requireNonBlank(key, ERROR_KEY_BLANK);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_KEY, key);
}

/**
* Finds out if an i18n {@code key} has been registered with the target {@code Node}, returning the key if found.
*
* @param node the target node on which the key may have been registered.
*
* @return the key registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nKey(@Nonnull MenuItem node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_KEY);
}

/**
* Associates an i18n arrays of arguments to a {@code node}.
* These arguments will be used alongside a key to resolve a message via the application's {@code MessageSource}.
*
* @param node the target node on which the key will be registered.
* @param args the array of arguments to be registered.
*
* @since 2.9.0
*/
public static void setI18nArgs(@Nonnull MenuItem node, @Nullable String args) {
requireNonNull(node, ERROR_NODE_NULL);
requireNonBlank(args, ERROR_ARGS_BLANK);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_ARGS, args);
}

/**
* Finds out if an {@code arguments array} has been registered with the target {@code Node}, returning the array if found.
*
* @param node the target node on which the arguments may have been registered.
*
* @return the arguments registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nArgs(@Nonnull MenuItem node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_ARGS);
}

/**
* Associates an default value {@code node}.
* The value will be used alongside a key to resolve a message via the application's {@code MessageSource}.
*
* @param node the target node on which the key will be registered.
* @param defaultValue the value to be registered.
*
* @since 2.9.0
*/
public static void setI18nDefaultValue(@Nonnull MenuItem node, @Nullable String defaultValue) {
requireNonNull(node, ERROR_NODE_NULL);
node.getProperties().put(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE, defaultValue);
}

/**
* Finds out if a {@code default value} has been registered with the target {@code Node}, returning the value if found.
*
* @param node the target node on which the value may have been registered.
*
* @return the value registered with the target {@code Node} or {@code null} if not found.
*
* @since 2.9.0
*/
@Nullable
public static String getI18nDefaultValue(@Nonnull MenuItem node) {
requireNonNull(node, ERROR_NODE_NULL);
return (String) node.getProperties().get(MessageSource.class.getName() + SUFFIX_DEFAULT_VALUE);
}


public static void connectMessageSource(@Nonnull Object node, @Nonnull GriffonApplication application) {
requireNonNull(node, ERROR_NODE_NULL);
requireNonNull(application, ERROR_APPLICATION_NULL);

findElements(node, arg -> arg instanceof Labeled && !isBlank(getI18nKey((Labeled) arg)))
.forEach(element -> doConnectMessageSource((Labeled) element, application));
findElements(node, arg -> (arg instanceof Labeled && !isBlank(getI18nKey((Labeled) arg))) ||
(arg instanceof Tab && !isBlank(getI18nKey((Tab) arg))) ||
(arg instanceof MenuItem && !isBlank(getI18nKey((MenuItem) arg))))
.forEach(element -> {
if (element instanceof Labeled) {
doConnectMessageSource((Labeled) element, application);
} else if (element instanceof Tab) {
doConnectMessageSource((Tab) element, application);
} else if (element instanceof MenuItem) {
doConnectMessageSource((MenuItem) element, application);
}
});
}

private static void doConnectMessageSource(final @Nonnull Labeled labeled, final @Nonnull GriffonApplication application) {
application.addPropertyChangeListener(PROPERTY_LOCALE, evt -> updateLabeled(labeled, application));
updateLabeled(labeled, application);
private static void doConnectMessageSource(final @Nonnull Labeled node, final @Nonnull GriffonApplication application) {
application.addPropertyChangeListener(PROPERTY_LOCALE, evt -> updateLabeled(node, application));
updateLabeled(node, application);
}

private static void updateLabeled(@Nonnull Labeled labeled, @Nonnull GriffonApplication application) {
String key = getI18nKey(labeled);
String args = getI18nArgs(labeled);
String defaultValue = getI18nDefaultValue(labeled);
private static void doConnectMessageSource(final @Nonnull Tab node, final @Nonnull GriffonApplication application) {
application.addPropertyChangeListener(PROPERTY_LOCALE, evt -> updateLabeled(node, application));
updateLabeled(node, application);
}

Object[] argArray = isBlank(args) ? EMPTY_OBJECT_ARRAY : args.split(",");
private static void doConnectMessageSource(final @Nonnull MenuItem node, final @Nonnull GriffonApplication application) {
application.addPropertyChangeListener(PROPERTY_LOCALE, evt -> updateLabeled(node, application));
updateLabeled(node, application);
}

if (isBlank(defaultValue)) {
labeled.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale()));
} else {
labeled.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale(), defaultValue));
}
private static void updateLabeled(final @Nonnull Labeled node, final @Nonnull GriffonApplication application) {
runInsideUIThread(() -> {
String key = getI18nKey(node);
String args = getI18nArgs(node);
String defaultValue = getI18nDefaultValue(node);

Object[] argArray = isBlank(args) ? EMPTY_OBJECT_ARRAY : args.split(",");

if (isBlank(defaultValue)) {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale()));
} else {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale(), defaultValue));
}
});
}

private static void updateLabeled(final @Nonnull Tab node, final @Nonnull GriffonApplication application) {
runInsideUIThread(() -> {
String key = getI18nKey(node);
String args = getI18nArgs(node);
String defaultValue = getI18nDefaultValue(node);

Object[] argArray = isBlank(args) ? EMPTY_OBJECT_ARRAY : args.split(",");

if (isBlank(defaultValue)) {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale()));
} else {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale(), defaultValue));
}
});
}

private static void updateLabeled(final @Nonnull MenuItem node, final @Nonnull GriffonApplication application) {
runInsideUIThread(() -> {
String key = getI18nKey(node);
String args = getI18nArgs(node);
String defaultValue = getI18nDefaultValue(node);

Object[] argArray = isBlank(args) ? EMPTY_OBJECT_ARRAY : args.split(",");

if (isBlank(defaultValue)) {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale()));
} else {
node.setText(application.getMessageSource().getMessage(key, argArray, application.getLocale(), defaultValue));
}
});
}

/**
Expand Down

0 comments on commit 72da1ab

Please sign in to comment.