The simplest way is to provide the operator overloads yourself.
I am thinking of creating a macro to expand the basic overloads per type.
#include <type_traits>
enum class SBJFrameDrag
{
None = 0x00,
Top = 0x01,
Left = 0x02,
Bottom = 0x04,
Right = 0x08,
};
inline SBJFrameDrag operator | (SBJFrameDrag lhs, SBJFrameDrag rhs)
{
using T = std::underlying_type_t <SBJFrameDrag>;
return static_cast<SBJFrameDrag>(static_cast<T>(lhs) | static_cast<T>(rhs));
}
inline SBJFrameDrag& operator |= (SBJFrameDrag& lhs, SBJFrameDrag rhs)
{
lhs = lhs | rhs;
return lhs;
}
(Note that type_traits is a C++11 header and std::underlying_type_t is a C++14 feature.)
I would approach this problem as I would approach any localization issue: ResourceBundle. I use a class called I18n
that has a static method called getMessage
that takes a key and optionally a list of arguments. The key gets looked up in a ResourceBundle
configured to use the default Locale
or whatever you prefer (specifics here aren't important, so long as the caller to I18n
doesn't have to know about what the Locale
is).
The I18n
class is as follows:
public final class I18n {
private I18n() {
}
private static ResourceBundle bundle;
public static String getMessage(String key) {
if(bundle == null) {
bundle = ResourceBundle.getBundle("path.to.i18n.messages");
}
return bundle.getString(key);
}
public static String getMessage(String key, Object ... arguments) {
return MessageFormat.format(getMessage(key), arguments);
}
}
In your project, you would have in package path.to.i18n, files containing messages.properties (default), messages_en.properties (Locale en), messages_it.properties (Locale it), etc.
When you need to translate an enum value, you shouldn't have to treat it any differently than any other key, except the key is the enum term.
In other words, you have:
public enum AccountStatusEnum {
Active,
Inactive,
Pending
}
When you call I18n.getMessage
, you pass with AccountStatusEnum.Active.toString()
and the translation will be found in a property file with key "Active". If you're like me, and you prefer to use lower-case keys, then you should perform toLowerCase()
on the string. Better still, you create a new I18n.getMessage
that takes an Enum rather than a key, and that method calls the String version of I18n.getMessage
with the enum value converted to string and in lowercase.
So you'd then add this to the I18n
class:
public static String getMessage(Enum<?> enumVal) {
return getMessage(enumVal.toString().toLowerCase());
}
I prefer to use this method because it incorporates the same translation logic in the same part of the program without impacting your design. You may even want to differentiate enum keys from your other keys, in which case you can begin each enum key with "enum.", so you would prepend "enum." when calling getMessage
. Just remember to name your keys in your properties files accordingly.
I hope that helps!
Best Answer
Enum would be wrong way for this in JDK API which is supposed to serve wide variety of applications.
It would be also wrong in application development, unless the application is purposedly designed to serve a fixed, limited subset of languages - subset that is known at compile time - which, in turn, would hardly qualify as related to BCP-47.
This is because substantial attribute of BCP-47 is addressing an open-ended set of values:
Above, in turn, makes it wrong fit for enum, which is intended to serve fixed, limited sets of values: