fix various i18n issues

This commit is contained in:
f43nd1r 2018-08-17 01:42:06 +02:00
parent a60a0af0cd
commit f0b99146fe
15 changed files with 135 additions and 37 deletions

View file

@ -33,19 +33,19 @@ public class I18nLabel extends Label implements Translatable {
private final Object[] params;
public I18nLabel(ContentMode contentMode, I18N i18n, String captionId, Object... params) {
this(i18n, captionId, params);
setContentMode(contentMode);
}
public I18nLabel(I18N i18n, String captionId, Object... params) {
this.i18n = i18n;
this.captionId = captionId;
this.params = params;
setContentMode(contentMode);
updateMessageStrings(i18n.getLocale());
}
public I18nLabel(I18N i18n, String captionId, Object... params) {
this(ContentMode.TEXT, i18n, captionId, params);
}
@Override
public void updateMessageStrings(Locale locale) {
setCaption(i18n.get(captionId, locale, params));
setValue(i18n.get(captionId, locale, params));
}
}

View file

@ -0,0 +1,49 @@
/*
* (C) Copyright 2018 Lukas Morawietz (https://github.com/F43nd1r)
*
* 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.faendir.acra.i18n;
import com.vaadin.ui.LoginForm;
import org.vaadin.spring.i18n.I18N;
import org.vaadin.spring.i18n.support.Translatable;
import java.util.Locale;
/**
* @author lukas
* @since 16.08.18
*/
public class I18nLoginForm extends LoginForm implements Translatable {
private final I18N i18n;
private final String usernameId;
private final String passwordId;
private final String loginId;
public I18nLoginForm(I18N i18n, String usernameId, String passwordId, String loginId) {
this.i18n = i18n;
this.usernameId = usernameId;
this.passwordId = passwordId;
this.loginId = loginId;
updateMessageStrings(i18n.getLocale());
}
@Override
public void updateMessageStrings(Locale locale) {
setUsernameCaption(i18n.get(usernameId));
setPasswordCaption(i18n.get(passwordId));
setLoginButtonCaption(i18n.get(loginId));
}
}

View file

@ -61,14 +61,16 @@ public class I18nMenuBar extends MenuBar implements Translatable {
public I18nMenuItem addItem(Command command, String captionId, Object... params) {
I18nMenuItem item = new I18nMenuItem(null, command, i18n, captionId, params);
getItems().add(item);
getChildren().add(item);
return item;
}
@Override
public void updateMessageStrings(Locale locale) {
setText(i18n.get(captionId, params));
getItems().stream().filter(Translatable.class::isInstance).map(Translatable.class::cast).forEach(translatable -> translatable.updateMessageStrings(locale));
if(getChildren() != null) {
getChildren().stream().filter(Translatable.class::isInstance).map(Translatable.class::cast).forEach(translatable -> translatable.updateMessageStrings(locale));
}
}
}
}

View file

@ -16,6 +16,7 @@
package com.faendir.acra.ui;
import com.faendir.acra.i18n.I18nLabel;
import com.faendir.acra.i18n.I18nLoginForm;
import com.faendir.acra.i18n.I18nMenuBar;
import com.faendir.acra.i18n.Messages;
import com.faendir.acra.model.User;
@ -96,6 +97,7 @@ public class BackendUI extends TranslatableUI {
} else {
showLogin();
}
setLocale(request.getLocale());
}
private void login(@NonNull String username, @NonNull String password) {
@ -121,7 +123,7 @@ public class BackendUI extends TranslatableUI {
}
private void showLogin() {
LoginForm loginForm = new LoginForm();
LoginForm loginForm = new I18nLoginForm(i18n, Messages.USERNAME, Messages.PASSWORD, Messages.LOGIN);
loginForm.addLoginListener(event -> login(event.getLoginParameter("username"), event.getLoginParameter("password")));
VerticalLayout layout = new VerticalLayout(loginForm);
layout.setSizeFull();

View file

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.faendir.acra.ui.navigation;
import com.faendir.acra.model.App;
@ -21,6 +20,9 @@ import com.faendir.acra.security.SecurityUtils;
import com.faendir.acra.ui.annotation.RequiresAppPermission;
import com.faendir.acra.ui.view.base.navigation.ParametrizedBaseView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Lukas
* @since 24.03.2018
@ -45,9 +47,11 @@ public abstract class SingleParametrizedViewProvider<T, V extends ParametrizedBa
V view = super.getView(viewName);
if (view != null) {
view.setParameterParser(e -> {
String parameters = getParameters(e.getViewName().substring(e.getViewName().indexOf(getId())) + (e.getParameters().isEmpty() ?
"" :
MyNavigator.SEPARATOR_CHAR + e.getParameters()));
String parameters = null;
Matcher matcher = Pattern.compile("(^|/)(" + getId() + ")($|/)").matcher(e.getViewName());
if (matcher.find()) {
parameters = getParameters(e.getViewName().substring(matcher.start(2)) + (e.getParameters().isEmpty() ? "" : MyNavigator.SEPARATOR_CHAR + e.getParameters()));
}
return parameters != null ? parseParameterInternal(parameters) : null;
});
}

View file

@ -76,7 +76,7 @@ public class BugTab implements AppTab {
@Override
public String getId() {
return "bug";
return "bugs";
}
@Override
@ -88,7 +88,7 @@ public class BugTab implements AppTab {
layout.addComponent(header);
layout.setComponentAlignment(header, Alignment.MIDDLE_LEFT);
CheckBox hideSolved = new I18nCheckBox(true, i18n, Messages.HIDE_SOLVED);
MyGrid<VBug> bugs = new MyGrid<>(dataService.getBugProvider(app, hideSolved::getValue));
MyGrid<VBug> bugs = new MyGrid<>(dataService.getBugProvider(app, hideSolved::getValue), i18n);
bugs.setSelectionMode(Grid.SelectionMode.MULTI);
hideSolved.addValueChangeListener(e -> layout.getUI().access(() -> {
bugs.deselectAll();

View file

@ -61,7 +61,7 @@ public class ReportTab implements AppTab {
@Override
public String getId() {
return "report";
return "reports";
}
@Override

View file

@ -63,7 +63,7 @@ public class ProguardPanel implements AdminPanel{
@Override
public Component createContent(@NonNull App app, @NonNull NavigationManager navigationManager) {
VerticalLayout layout = new VerticalLayout();
MyGrid<ProguardMapping> grid = new MyGrid<>(dataService.getMappingProvider(app));
MyGrid<ProguardMapping> grid = new MyGrid<>(dataService.getMappingProvider(app), i18n);
grid.setSizeToRows();
grid.sort(grid.addColumn(ProguardMapping::getVersionCode, QProguardMapping.proguardMapping.versionCode, Messages.VERSION), SortDirection.ASCENDING);
if (SecurityUtils.hasPermission(app, Permission.Level.EDIT)) {

View file

@ -17,6 +17,8 @@ package com.faendir.acra.ui.view.base.layout;
import com.faendir.acra.client.mygrid.GridMiddleClickExtensionConnector;
import com.faendir.acra.dataprovider.QueryDslDataProvider;
import com.faendir.acra.i18n.HasI18n;
import com.faendir.acra.i18n.Messages;
import com.faendir.acra.ui.navigation.NavigationManager;
import com.faendir.acra.ui.view.base.navigation.BaseView;
import com.querydsl.core.types.Expression;
@ -34,9 +36,11 @@ import org.springframework.lang.NonNull;
import org.vaadin.spring.i18n.I18N;
import org.vaadin.spring.i18n.support.Translatable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EventObject;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@ -46,16 +50,17 @@ import java.util.function.Function;
* @author Lukas
* @since 14.05.2017
*/
public class MyGrid<T> extends Composite implements Translatable {
public class MyGrid<T> extends Composite implements Translatable, HasI18n {
private final I18N i18n;
private final String captionId;
private final Object[] params;
private final Map<Grid.Column<T, ?>, Pair<String, Object[]>> columnCaptions;
private final List<Translatable> translatables;
private final ExposingGrid<T> grid;
private final QueryDslDataProvider<T> dataProvider;
public MyGrid(QueryDslDataProvider<T> dataProvider) {
this(dataProvider, null, null);
public MyGrid(QueryDslDataProvider<T> dataProvider, I18N i18n) {
this(dataProvider, i18n, Messages.BLANK);
}
public MyGrid(QueryDslDataProvider<T> dataProvider, I18N i18n, String captionId, Object... params) {
@ -67,10 +72,9 @@ public class MyGrid<T> extends Composite implements Translatable {
this.i18n = i18n;
this.captionId = captionId;
columnCaptions = new HashMap<>();
translatables = new ArrayList<>();
this.params = params;
if (i18n != null) {
updateMessageStrings(i18n.getLocale());
}
updateMessageStrings(i18n.getLocale());
}
@NonNull
@ -81,27 +85,33 @@ public class MyGrid<T> extends Composite implements Translatable {
}
@NonNull
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull AbstractRenderer<? super T, ? super R> renderer, @NonNull String captionId, Object... params) {
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull AbstractRenderer<? super T, ? super R> renderer, @NonNull String captionId,
Object... params) {
Grid.Column<T, R> column = addColumn(valueProvider, renderer).setCaption(i18n.get(captionId, params));
columnCaptions.put(column, Pair.of(captionId, params));
return column;
}
@NonNull
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull Expression<? extends Comparable> sort, @NonNull String captionId, Object... params) {
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull Expression<? extends Comparable> sort, @NonNull String captionId,
Object... params) {
return addColumn(valueProvider, new TextRenderer(), sort, captionId, params);
}
@NonNull
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull AbstractRenderer<? super T, ? super R> renderer,
@NonNull Expression<? extends Comparable> sort, @NonNull String captionId, Object... params) {
Grid.Column<T, R> column = grid.addColumn(valueProvider, renderer).setId(dataProvider.addSortable(sort)).setCaption(i18n.get(captionId, params));
Grid.Column<T, R> column = addColumn(valueProvider, renderer).setId(dataProvider.addSortable(sort)).setCaption(i18n.get(captionId, params)).setSortable(true);
columnCaptions.put(column, Pair.of(captionId, params));
return column;
}
@NonNull
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull AbstractRenderer<? super T, ? super R> renderer) {
if(renderer instanceof Translatable) {
((Translatable) renderer).updateMessageStrings(i18n.getLocale());
translatables.add((Translatable) renderer);
}
return grid.addColumn(valueProvider, renderer).setSortable(false);
}
@ -157,6 +167,12 @@ public class MyGrid<T> extends Composite implements Translatable {
public void updateMessageStrings(Locale locale) {
setCaption(i18n.get(captionId, locale, params));
columnCaptions.forEach((column, caption) -> column.setCaption(i18n.get(caption.getFirst(), locale, caption.getSecond())));
translatables.forEach(translatable -> translatable.updateMessageStrings(locale));
}
@Override
public I18N getI18n() {
return i18n;
}
public static class MiddleClickExtension<T> extends Grid.AbstractGridExtension<T> {

View file

@ -98,6 +98,11 @@ public class MyTabSheet<T> extends TabSheet {
public String getCaption() {
return tab.getCaption();
}
@Override
public String getId() {
return tab.getId();
}
}
public static class MiddleClickExtension extends AbstractExtension {

View file

@ -22,6 +22,7 @@ import com.vaadin.ui.UI;
import com.vaadin.ui.themes.AcraTheme;
import org.jfree.chart.JFreeChart;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.vaadin.addon.JFreeChartWrapper;
import org.vaadin.spring.i18n.I18N;
import org.vaadin.spring.i18n.support.Translatable;
@ -70,7 +71,8 @@ abstract class Chart<T> extends Composite implements Translatable, HasI18n {
protected abstract JFreeChart createChart(@NonNull Map<T, Long> map);
protected JFreeChart getChart() {
@Nullable
JFreeChart getChart() {
return chart;
}

View file

@ -87,9 +87,11 @@ class TimeChart extends Chart<Date> {
@Override
public void updateMessageStrings(Locale locale) {
super.updateMessageStrings(locale);
XYPlot plot = getChart().getXYPlot();
plot.getDomainAxis().setLabel(getI18n().get(Messages.DATE));
plot.getRangeAxis().setLabel(getI18n().get(Messages.REPORTS));
markAsDirtyRecursive();
if(getChart() != null) {
XYPlot plot = getChart().getXYPlot();
plot.getDomainAxis().setLabel(getI18n().get(Messages.DATE));
plot.getRangeAxis().setLabel(getI18n().get(Messages.REPORTS));
markAsDirtyRecursive();
}
}
}

View file

@ -16,10 +16,12 @@
package com.faendir.acra.util;
import com.vaadin.ui.UI;
import com.vaadin.ui.renderers.TextRenderer;
import elemental.json.Json;
import elemental.json.JsonValue;
import org.springframework.lang.Nullable;
import org.vaadin.spring.i18n.support.Translatable;
import org.xbib.time.pretty.PrettyTime;
import java.time.ZonedDateTime;
@ -29,12 +31,24 @@ import java.util.Locale;
* @author Lukas
* @since 26.05.2017
*/
public class TimeSpanRenderer extends TextRenderer {
public class TimeSpanRenderer extends TextRenderer implements Translatable {
private Locale locale;
public TimeSpanRenderer() {
locale = UI.getCurrent().getLocale();
}
@Override
public JsonValue encode(@Nullable Object value) {
if (value instanceof ZonedDateTime) {
return Json.create(new PrettyTime(Locale.US).formatUnrounded(((ZonedDateTime) value).toLocalDateTime()));
return Json.create(new PrettyTime(locale).formatUnrounded(((ZonedDateTime) value).toLocalDateTime()));
}
return super.encode(value);
}
@Override
public void updateMessageStrings(Locale locale) {
this.locale = locale;
markAsDirty();
}
}

View file

@ -17,7 +17,7 @@
newApp=Neue App
apps=Apps
name=Name
bugs=
bugs=Bugs
reports=Berichte
importAcralyzer=Von Acralyzer importieren
host=Host
@ -115,7 +115,7 @@ changePassword=Passwort ändern
success=Erfolgreich!
users=Nutzer
username=Nutzername
accessPermission=Zugriffsbeschränkung für {0}
accessPermission=Zugriffsrechte für {0}
newUser=Neuer Benutzer
password=Passwort
usernameEmpty=Nutzername darf nicht leer sein
@ -126,4 +126,5 @@ missingRole=Fehlende benötigte Rolle
darkTheme=Dunkles Thema
logout=Logout
footer=Acrarium wird entwickelt von <a href=https://github.com/F43nd1r>F43nd1r</a>. Der <a href=https://github.com/F43nd1r/acra-backend>Code</a> ist lizensiert unter <a href=https://github.com/F43nd1r/acra-backend/blob/master/LICENSE>Apache License v2</a>.
blank=
blank=
login=Login

View file

@ -126,4 +126,5 @@ missingRole=Missing required role
darkTheme=Dark Theme
logout=Logout
footer=Acrarium is developed by <a href=https://github.com/F43nd1r>F43nd1r</a>. <a href=https://github.com/F43nd1r/acra-backend>Code</a> is licensed under <a href=https://github.com/F43nd1r/acra-backend/blob/master/LICENSE>Apache License v2</a>.
blank=
blank=
login=Login