feat(i18n): ajout de l'internationalisation sur l'application graphique

This commit is contained in:
Emi Boucly 2025-01-29 22:32:13 +01:00
parent 6daa8c2fad
commit 1ee6ceb15c
8 changed files with 118 additions and 40 deletions

View file

@ -8,7 +8,9 @@ import javafx.stage.Stage;
import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.Objects;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
@ -28,7 +30,9 @@ public class ChatApplication extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ChatApplication.class.getResource("chat-view.fxml"));
ResourceBundle i18nBundle = ResourceBundle.getBundle("rtgre.chat.i18nBundle",
Locale.getDefault());
FXMLLoader fxmlLoader = new FXMLLoader(ChatApplication.class.getResource("chat-view.fxml"), i18nBundle);
Scene scene = new Scene(fxmlLoader.load(), 600, 400);
stage.setTitle("Chat @BOUCLY_Emi (B2GA)");

View file

@ -77,6 +77,7 @@ public class ChatController implements Initializable {
private PostVector postVector;
private RoomMap roomMap = new RoomMap();
private ObservableList<Room> roomObservableList = FXCollections.observableArrayList();
private ResourceBundle i18nBundle;
@Override
@ -84,6 +85,8 @@ public class ChatController implements Initializable {
LOGGER.info("Initialisation de l'interface graphique");
Image image = new Image(Objects.requireNonNull(ChatController.class.getResourceAsStream("anonymous.png")));
this.avatarImageView.setImage(image);
this.i18nBundle = resourceBundle;
Thread dateTimeLoop = new Thread(this::dateTimeLoop);
dateTimeLoop.setDaemon(true);
@ -94,7 +97,7 @@ public class ChatController implements Initializable {
hostComboBox.setValue("localhost:2024");
hostComboBox.setOnAction(this::statusNameUpdate);
statusLabel.setText("Disconnected");
statusLabel.setText(i18nBundle.getString("disconnected"));
connectionButton.disableProperty().bind(validatorLogin.containsErrorsProperty());
connectionButton.selectedProperty().addListener(this::handleConnection);
@ -134,7 +137,7 @@ public class ChatController implements Initializable {
private void handleHostAdd(ActionEvent actionEvent) {
try {
ChatHostAddController controller = showNewStage("Add host", "chathostadd-view.fxml");
ChatHostAddController controller = showNewStage(i18nBundle.getString("addHost"), "chathostadd-view.fxml");
if (controller.isOk()) {
hostComboBox.getItems().add(controller.hostTextField.getText());
hostComboBox.setValue(controller.hostTextField.getText());
@ -154,7 +157,7 @@ public class ChatController implements Initializable {
* @throws IOException si le fichier FXML n'est pas trouvé dans les ressources
*/
public <T> T showNewStage(String title, String fxmlFileName) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ChatApplication.class.getResource(fxmlFileName));
FXMLLoader fxmlLoader = new FXMLLoader(ChatApplication.class.getResource(fxmlFileName), i18nBundle);
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
@ -196,7 +199,7 @@ public class ChatController implements Initializable {
try {
FileChooser fileChooser = new FileChooser();
Stage stage = (Stage) avatarImageView.getScene().getWindow();
fileChooser.setTitle("Select Avatar");
fileChooser.setTitle(i18nBundle.getString("changeAvatar"));
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("Image Files", "*.png", "*.jpg")
);
@ -230,17 +233,18 @@ public class ChatController implements Initializable {
initPostListView();
clearLists();
contactMap.add(this.contact);
this.contact.setConnected(true);
client.sendAuthEvent(contact);
this.contact.setConnected(true);
client.sendListRoomEvent();
client.sendEvent(new rtgre.modeles.Event(rtgre.modeles.Event.LIST_CONTACTS, new JSONObject()));
client.sendEvent(new rtgre.modeles.Event(rtgre.modeles.Event.CONT, contact.toJsonObject()));
initContactListView();
initPostListView();
this.statusLabel.setText("Connected to %s@%s:%s".formatted(this.contact.getLogin(), host, port));
} catch (IOException e) {
new Alert(Alert.AlertType.ERROR, "Erreur de connexion").showAndWait();
this.statusLabel.setText("%s%s@%s:%s".formatted(i18nBundle.getString("connected"), this.contact.getLogin(), host, port));
this.connectionButton.setText(i18nBundle.getString("disconnect"));
} catch (Exception e) {
new Alert(Alert.AlertType.ERROR, i18nBundle.getString("connectionError")).showAndWait();
connectionButton.setSelected(false);
}
} else if (!connectionButton.isSelected()) {
@ -249,7 +253,8 @@ public class ChatController implements Initializable {
if (this.client.isConnected()) {
this.contact.setConnected(false);
}
statusLabel.setText("Disconnected");
statusLabel.setText(i18nBundle.getString("disconnected"));
this.connectionButton.setText(i18nBundle.getString("connect"));
}
}
@ -265,10 +270,10 @@ public class ChatController implements Initializable {
private void checkLogin(Check.Context context) {
String login = context.get("login");
if (!LOGIN_PATTERN.matcher(login).matches()) {
context.error("Format de login non respecté");
context.error(i18nBundle.getString("loginError"));
}
if (login.equals("system")) {
context.error("Le login ne peut pas être system");
context.error(i18nBundle.getString("systemError"));
}
@ -296,7 +301,7 @@ public class ChatController implements Initializable {
try {
contactsListView.setCellFactory(contactListView -> new ContactListViewCell());
contactsListView.setItems(contactObservableList);
File avatars = new File(getClass().getResource("avatars.png").toURI());
//File avatars = new File(getClass().getResource("avatars.png").toURI());
//Contact fifi = new Contact("fifi", true, avatars);
//contactObservableList.add(fifi);
//contactMap.add(fifi);
@ -362,7 +367,7 @@ public class ChatController implements Initializable {
roomSelected.getUnreadCount().setUnreadCount(0);
roomsListView.refresh();
Post postSys = new Post("system", loginTextField.getText(), "Bienvenue dans le salon " + roomSelected);
Post postSys = new Post("system", loginTextField.getText(), i18nBundle.getString("systemHelloRoom") + roomSelected);
postsObservableList.clear();
postsObservableList.add(postSys);
client.sendEvent(new rtgre.modeles.Event("JOIN", new JSONObject().put("room", roomSelected.getRoomName())));
@ -381,7 +386,7 @@ public class ChatController implements Initializable {
contactSelected.getUnreadCount().setUnreadCount(0);
Post postSys = new Post("system", loginTextField.getText(), "Bienvenue dans la discussion avec " + contactSelected.getLogin());
Post postSys = new Post("system", loginTextField.getText(), i18nBundle.getString("systemHelloContact") + contactSelected.getLogin());
postsObservableList.clear();
postsObservableList.add(postSys);
client.sendListPostEvent(0, contactSelected.getLogin());
@ -498,4 +503,7 @@ public class ChatController implements Initializable {
}
}
public void errorAlert() {
new Alert(Alert.AlertType.ERROR, i18nBundle.getString("connectionError")).showAndWait();
}
}

View file

@ -26,17 +26,19 @@ public class ChatHostAddController implements Initializable {
private boolean ok = false;
public static final Pattern HOST_PORT_REGEX = Pattern.compile("^([-.a-zA-Z0-9]+)(?::([0-9]{1,5}))?$");
private Validator validatorHost = new Validator();
private ResourceBundle i18nBundle;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
submitButton.setOnAction(this::onActionSubmit);
resetButton.setOnAction(this::onActionReset);
this.i18nBundle = resourceBundle;
submitButton.disableProperty().bind(validatorHost.containsErrorsProperty());
TooltipWrapper<Button> submitWrapper = new TooltipWrapper<>(
submitButton,
validatorHost.containsErrorsProperty(),
Bindings.concat("Cannot submit:\n", validatorHost.createStringBinding())
Bindings.concat(i18nBundle.getString("cannotSubmit"), validatorHost.createStringBinding())
);
this.submitWrapper.getChildren().add(submitWrapper);
@ -45,13 +47,12 @@ public class ChatHostAddController implements Initializable {
.withMethod(this::checkHost)
.decorates(hostTextField)
.immediate();
}
private void checkHost(Check.Context context) {
String host = context.get("host");
if (!HOST_PORT_REGEX.matcher(host).matches()) {
context.error("Host should be a valid IP address or name with potentially port number");
context.error(i18nBundle.getString("hostError"));
}
}

View file

@ -95,6 +95,7 @@ public class ChatClient extends ClientTCP {
} catch (IOException e) {
LOGGER.severe("[%s] %s".formatted(ipPort, e));
connected = false;
Platform.runLater(() -> listener.connectionButton.setSelected(false));
} finally {
close();
}