fix various i18n issues
This commit is contained in:
parent
a60a0af0cd
commit
f0b99146fe
15 changed files with 135 additions and 37 deletions
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
49
src/main/java/com/faendir/acra/i18n/I18nLoginForm.java
Normal file
49
src/main/java/com/faendir/acra/i18n/I18nLoginForm.java
Normal 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));
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ReportTab implements AppTab {
|
|||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "report";
|
||||
return "reports";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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,11 +72,10 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <R> Grid.Column<T, R> addColumn(@NonNull ValueProvider<T, R> valueProvider, @NonNull String captionId, Object... params) {
|
||||
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,9 +87,11 @@ class TimeChart extends Chart<Date> {
|
|||
@Override
|
||||
public void updateMessageStrings(Locale locale) {
|
||||
super.updateMessageStrings(locale);
|
||||
if(getChart() != null) {
|
||||
XYPlot plot = getChart().getXYPlot();
|
||||
plot.getDomainAxis().setLabel(getI18n().get(Messages.DATE));
|
||||
plot.getRangeAxis().setLabel(getI18n().get(Messages.REPORTS));
|
||||
markAsDirtyRecursive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -127,3 +127,4 @@ 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=
|
||||
login=Login
|
|
@ -127,3 +127,4 @@ 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=
|
||||
login=Login
|
Loading…
Reference in a new issue