When adding a DatePicker to my app I get the following:
I assume this is because I use Hebrew on my computer. How can I change the language of the DatePicker to be English?
When adding a DatePicker to my app I get the following:
I assume this is because I use Hebrew on my computer. How can I change the language of the DatePicker to be English?
You can define the default locale for your instance of the Java Virtual Machine calling:
Locale.setDefault(Locale.ENGLISH);
Or if you can't find the locale, you need, in the pre made constants, you can look up the country code in the list of officially supported locales and create your "custom" locale like this:
Locale.setDefault(Locale("cs")) //locale for Czech language
on the start
method. If you also want to implement a custom formatter for the text editor, you should add locale to the formatter too.
This is just an example:
private final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("EEEE, d.MM.uuuu", Locale.ENGLISH);
@Override
public void start(Stage primaryStage) {
Locale.setDefault(Locale.ENGLISH);
DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setConverter(new StringConverter<LocalDate>() {
@Override
public String toString(LocalDate object) {
return object.format(formatter);
}
@Override
public LocalDate fromString(String string) {
return LocalDate.parse(string, formatter);
}
});
StackPane root = new StackPane(datePicker);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
EDIT
By design, DatePicker
uses Locale.getDefault()
in all the formats applied to the controls displayed on the popup. This can be checked in com.sun.javafx.scene.control.skin.DatePickerContent
class.
Unless you provide a custom skin for the control changing these formatters, in order to change the DatePicker
content to English, avoiding further changes in other localized controls, a workaround could be this:
private final Locale myLocale = Locale.getDefault(Locale.Category.FORMAT);
@Override
public void start(Stage primaryStage) {
DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setOnShowing(e-> Locale.setDefault(Locale.Category.FORMAT,Locale.ENGLISH));
datePicker.setOnShown(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
...
}
EDIT 2
Returning to the original locale on setOnShown
is too soon, since if the user changes the month, the original locale is used and it will not be shown properly. To work it should be turned off both on setOnHiding
and on setOnAction
.
private final Locale myLocale = Locale.getDefault(Locale.Category.FORMAT);
@Override
public void start(Stage primaryStage) {
DatePicker datePicker=new DatePicker();
datePicker.setValue(LocalDate.now());
datePicker.setOnShowing(e-> Locale.setDefault(Locale.Category.FORMAT,Locale.ENGLISH));
datePicker.setOnHiding(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
datePicker.setOnAction(e-> Locale.setDefault(Locale.Category.FORMAT,myLocale));
...
}
Starting with fx9, the skins are moved out into public api - so you might consider creating a custom skin that allows to configure the Locale per-picker. Unfortunately, the class that does the internal formatting is still hidden in internals, so tweaking requires to go dirty.
If you are daring/allowed to access internals, one way to go is
getLocale()
to first check whether the picker's properties contain a custom locale - if so return that, otherwise delegate to superSample code:
public class DatePickerLocale extends Application {
/**
* Custom DatePickerContent that uses a per-picker Locale if
* available.
*/
public static class XDatePickerContent extends DatePickerContent {
public XDatePickerContent(DatePicker datePicker) {
super(datePicker);
}
@Override
protected Locale getLocale() {
if (datePicker != null) {
Object locale = datePicker.getProperties().get("CONTROL_LOCALE");
if (locale instanceof Locale) {
return (Locale) locale;
}
}
return super.getLocale();
}
}
/**
* Custom DatePickerSkin that injects a custom content.
*/
public static class XDatePickerSkin extends DatePickerSkin {
public XDatePickerSkin(DatePicker control) {
super(control);
}
@Override
public Node getPopupContent() {
DatePickerContent content = (XDatePickerContent) getDatePickerContent();
if (!(content instanceof XDatePickerContent)) {
content = new XDatePickerContent((DatePicker) getSkinnable());
replaceDatePickerContent(content);
}
return content;
}
//------------- going dirty: reflective access to super
protected DatePickerContent getDatePickerContent() {
return (DatePickerContent) FXUtils.invokeGetFieldValue(DatePickerSkin.class, this, "datePickerContent");
}
protected void replaceDatePickerContent(DatePickerContent content) {
FXUtils.invokeSetFieldValue(DatePickerSkin.class, this, "datePickerContent", content);
}
}
private Parent createContent() {
LocalDate now = LocalDate.now();
DatePicker picker = new DatePicker(now) {
@Override
protected Skin<?> createDefaultSkin() {
return new XDatePickerSkin(this);
}
};
Locale customLocale = Locale.CHINA;
// config locale for content
picker.getProperties().put("CONTROL_LOCALE", customLocale);
// config locale for chronology/converter
picker.setChronology(Chronology.ofLocale(customLocale));
picker.setConverter(new LocalDateStringConverter(FormatStyle.SHORT,
customLocale, picker.getChronology()));
// just to see some formats with default locale
List<String> patterns = List.of("e", "ee", "eee", "eeee", "eeeee");
HBox box = new HBox(10);
patterns.forEach(p -> {
DateTimeFormatter ccc = DateTimeFormatter.ofPattern(p);
String name = ccc.withLocale(Locale.getDefault(Locale.Category.FORMAT)).format(now);
box.getChildren().add(new Label(name));
});
BorderPane content = new BorderPane(picker);
content.setBottom(box);
return content;
}
@Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent(), 400, 200));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
@SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(DatePickerLocale.class.getName());
}