Skip to content

Commit

Permalink
fix: Update current UI instance upon locale change (#11725) (#11785)
Browse files Browse the repository at this point in the history
Fixes #11599

Co-authored-by: Mikhail Shabarov <[email protected]>
  • Loading branch information
vaadin-bot and mshabarov authored Sep 7, 2021
1 parent 1ca9747 commit a500d47
Show file tree
Hide file tree
Showing 4 changed files with 203 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,15 @@ public void setLocale(Locale locale) {
checkHasLock();
this.locale = locale;

getUIs().forEach(ui -> ui.setLocale(locale));
getUIs().forEach(ui -> {
Map<Class<?>, CurrentInstance> oldInstances = CurrentInstance
.setCurrent(ui);
try {
ui.setLocale(locale);
} finally {
CurrentInstance.restoreInstances(oldInstances);
}
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
import com.vaadin.flow.router.internal.AfterNavigationHandler;
import com.vaadin.flow.router.internal.BeforeEnterHandler;
import com.vaadin.flow.router.internal.BeforeLeaveHandler;
import com.vaadin.flow.server.BootstrapHandler;
import com.vaadin.flow.server.BootstrapHandlerTest;
import com.vaadin.flow.server.InvalidRouteConfigurationException;
import com.vaadin.flow.server.MockVaadinServletService;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright 2000-2021 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.uitest.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.HtmlComponent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.NativeButton;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.i18n.LocaleChangeEvent;
import com.vaadin.flow.i18n.LocaleChangeObserver;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.VaadinSession;

@Route("com.vaadin.flow.uitest.ui.LocaleChangeView")
public class LocaleChangeView extends Div {

public static final String SAME_UI_RESULT_ID = "same-ui-result-id";
public static final String CHANGE_LOCALE_BUTTON_ID = "change-locale-button-id";
public static final String SHOW_RESULTS_BUTTON_ID = "show-results-button-id";

public LocaleChangeView() {
Locale defaultLocale = UI.getCurrent().getLocale();
NativeButton changeLocaleButton = new NativeButton("Change Locale",
click -> {
if (defaultLocale.equals(Locale.ENGLISH)) {
changeSessionLocale(Locale.FRANCE);
} else {
changeSessionLocale(Locale.ENGLISH);
}
});
changeLocaleButton.setId(CHANGE_LOCALE_BUTTON_ID);

LocaleObserverComponent localeObserverComponent = new LocaleObserverComponent(
defaultLocale);

NativeButton showLocaleUpdates = new NativeButton("Show locale updates",
click -> localeObserverComponent.showLocaleUpdates());
showLocaleUpdates.setId(SHOW_RESULTS_BUTTON_ID);

add(changeLocaleButton, showLocaleUpdates, new HtmlComponent(Tag.BR),
localeObserverComponent);
}

private void changeSessionLocale(Locale locale) {
UI.getCurrent().getSession().setLocale(locale);
}

@Tag("Div")
private static class LocaleObserverComponent extends Component
implements HasComponents, LocaleChangeObserver {

private final Locale defaultLocale;

public LocaleObserverComponent(Locale defaultLocale) {
this.defaultLocale = defaultLocale;
}

@Override
public void localeChange(LocaleChangeEvent event) {
if (event.getLocale().equals(defaultLocale)) {
return;
}
final boolean sameUI = getUI().isPresent()
&& getUI().get() == UI.getCurrent();

registerLocaleUpdate(sameUI);
}

public void showLocaleUpdates() {
LocaleUpdates localeUpdates = getLocaleUpdates();
renderResults(localeUpdates);
}

private void renderResults(LocaleUpdates localeUpdates) {
for (int i = 0; i < localeUpdates.getUiCheckResults().size(); i++) {
Boolean checkResult = localeUpdates.getUiCheckResults().get(i);
Span sameUIResult = new Span();
sameUIResult
.setId(String.format("%s-%d", SAME_UI_RESULT_ID, i));
sameUIResult.setText(Boolean.toString(checkResult));
Span caption = new Span(String
.format("Component %d uses current UI instance = ", i));
add(caption, sameUIResult, new HtmlComponent(Tag.BR));
}
}

private void registerLocaleUpdate(boolean sameUIcheckUp) {
VaadinSession session = VaadinSession.getCurrent();
// no lock needed, since flow listeners are called under lock
// already
LocaleUpdates localeUpdates = session
.getAttribute(LocaleUpdates.class);
if (localeUpdates == null) {
localeUpdates = new LocaleUpdates();
}
localeUpdates.addUICheckResult(sameUIcheckUp);
session.setAttribute(LocaleUpdates.class, localeUpdates);
}

private LocaleUpdates getLocaleUpdates() {
VaadinSession session = VaadinSession.getCurrent();
// no lock needed, since flow listeners are called under lock
// already
return session.getAttribute(LocaleUpdates.class);
}
}

static class LocaleUpdates {
private final List<Boolean> uiCheckResults = new ArrayList<>(3);

public void addUICheckResult(boolean uiCheckResult) {
uiCheckResults.add(uiCheckResult);
}

public List<Boolean> getUiCheckResults() {
return uiCheckResults;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2000-2021 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.flow.uitest.ui;

import java.util.stream.IntStream;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import com.vaadin.flow.testutil.ChromeBrowserTest;

import static com.vaadin.flow.uitest.ui.LocaleChangeView.CHANGE_LOCALE_BUTTON_ID;
import static com.vaadin.flow.uitest.ui.LocaleChangeView.SAME_UI_RESULT_ID;
import static com.vaadin.flow.uitest.ui.LocaleChangeView.SHOW_RESULTS_BUTTON_ID;

public class LocaleChangeIT extends ChromeBrowserTest {

@Test
public void setSessionLocale_currentUIInstanceUpdatedUponEachLocaleUpdate() {
final int openedUI = 3;

IntStream.range(0, openedUI).forEach(i -> open());

waitForElementPresent(By.id(CHANGE_LOCALE_BUTTON_ID));
findElement(By.id(CHANGE_LOCALE_BUTTON_ID)).click();

waitForElementPresent(By.id(SHOW_RESULTS_BUTTON_ID));
findElement(By.id(SHOW_RESULTS_BUTTON_ID)).click();

IntStream.range(0, openedUI).forEach(i -> {
String id = String.format("%s-%d", SAME_UI_RESULT_ID, i);
waitForElementPresent(By.id(id));
WebElement result = findElement(By.id(id));
Assert.assertTrue(
"Component's UI and current UI instances are different",
Boolean.parseBoolean(result.getText()));
});
}
}

0 comments on commit a500d47

Please sign in to comment.