[boschindego] Add localization support for textual states (#12949)

* Add support for localization of textualstate texts
* Refactor state texts to eliminate redundancy

Fixes #12941

Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
Jacob Laursen 2022-06-19 14:07:26 +02:00 committed by GitHub
parent daea9ae5b2
commit efb1bfc772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 164 additions and 93 deletions

View File

@ -18,6 +18,8 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.boschindego.internal.handler.BoschIndegoHandler; import org.openhab.binding.boschindego.internal.handler.BoschIndegoHandler;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.openhab.core.io.net.http.HttpClientFactory; import org.openhab.core.io.net.http.HttpClientFactory;
import org.openhab.core.thing.Thing; import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingTypeUID;
@ -40,12 +42,15 @@ import org.osgi.service.component.annotations.Reference;
public class BoschIndegoHandlerFactory extends BaseThingHandlerFactory { public class BoschIndegoHandlerFactory extends BaseThingHandlerFactory {
private final HttpClient httpClient; private final HttpClient httpClient;
private final BoschIndegoTranslationProvider translationProvider;
@Activate @Activate
public BoschIndegoHandlerFactory(@Reference HttpClientFactory httpClientFactory, public BoschIndegoHandlerFactory(@Reference HttpClientFactory httpClientFactory,
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider,
ComponentContext componentContext) { ComponentContext componentContext) {
super.activate(componentContext); super.activate(componentContext);
this.httpClient = httpClientFactory.getCommonHttpClient(); this.httpClient = httpClientFactory.getCommonHttpClient();
this.translationProvider = new BoschIndegoTranslationProvider(i18nProvider, localeProvider);
} }
@Override @Override
@ -58,7 +63,7 @@ public class BoschIndegoHandlerFactory extends BaseThingHandlerFactory {
ThingTypeUID thingTypeUID = thing.getThingTypeUID(); ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (THING_TYPE_INDEGO.equals(thingTypeUID)) { if (THING_TYPE_INDEGO.equals(thingTypeUID)) {
return new BoschIndegoHandler(thing, httpClient); return new BoschIndegoHandler(thing, httpClient, translationProvider);
} }
return null; return null;

View File

@ -0,0 +1,51 @@
/**
* Copyright (c) 2010-2022 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.boschindego.internal;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.i18n.LocaleProvider;
import org.openhab.core.i18n.TranslationProvider;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
/**
* {@link BoschIndegoTranslationProvider} provides i18n message lookup.
*
* @author Jacob Laursen - Initial contribution
*/
@NonNullByDefault
public class BoschIndegoTranslationProvider {
private final Bundle bundle;
private final TranslationProvider i18nProvider;
private final LocaleProvider localeProvider;
public BoschIndegoTranslationProvider(TranslationProvider i18nProvider, LocaleProvider localeProvider) {
this.bundle = FrameworkUtil.getBundle(this.getClass());
this.i18nProvider = i18nProvider;
this.localeProvider = localeProvider;
}
public @Nullable String getText(String key, @Nullable Object... arguments) {
return i18nProvider.getText(bundle, key, null, localeProvider.getLocale(), arguments);
}
public String getText(String key, String defaultText, @Nullable Object... arguments) {
String text = i18nProvider.getText(bundle, key, defaultText, localeProvider.getLocale(), arguments);
if (text == null) {
return defaultText;
}
return text;
}
}

View File

@ -29,43 +29,46 @@ import org.openhab.binding.boschindego.internal.dto.DeviceCommand;
@NonNullByDefault @NonNullByDefault
public class DeviceStatus { public class DeviceStatus {
private static final Map<Integer, DeviceStatus> STATUS_MAP = Map.ofEntries( private final static String STATE_PREFIX = "indego.state.";
entry(0, new DeviceStatus("Reading status", false, DeviceCommand.RETURN)), private final static String STATE_UNKNOWN = "unknown";
entry(257, new DeviceStatus("Charging", false, DeviceCommand.RETURN)),
entry(258, new DeviceStatus("Docked", true, DeviceCommand.RETURN)),
entry(259, new DeviceStatus("Docked - Software update", false, DeviceCommand.RETURN)),
entry(260, new DeviceStatus("Docked", true, DeviceCommand.RETURN)),
entry(261, new DeviceStatus("Docked", true, DeviceCommand.RETURN)),
entry(262, new DeviceStatus("Docked - Loading map", false, DeviceCommand.MOW)),
entry(263, new DeviceStatus("Docked - Saving map", false, DeviceCommand.RETURN)),
entry(513, new DeviceStatus("Mowing", false, DeviceCommand.MOW)),
entry(514, new DeviceStatus("Relocalising", false, DeviceCommand.MOW)),
entry(515, new DeviceStatus("Loading map", false, DeviceCommand.MOW)),
entry(516, new DeviceStatus("Learning lawn", false, DeviceCommand.MOW)),
entry(517, new DeviceStatus("Paused", true, DeviceCommand.PAUSE)),
entry(518, new DeviceStatus("Border cut", false, DeviceCommand.MOW)),
entry(519, new DeviceStatus("Idle in lawn", true, DeviceCommand.MOW)),
entry(769, new DeviceStatus("Returning to dock", false, DeviceCommand.RETURN)),
entry(770, new DeviceStatus("Returning to dock", false, DeviceCommand.RETURN)),
entry(771, new DeviceStatus("Returning to dock - Battery low", false, DeviceCommand.RETURN)),
entry(772, new DeviceStatus("Returning to dock - Calendar timeslot ended", false, DeviceCommand.RETURN)),
entry(773, new DeviceStatus("Returning to dock - Battery temp range", false, DeviceCommand.RETURN)),
entry(774, new DeviceStatus("Returning to dock", false, DeviceCommand.RETURN)),
entry(775, new DeviceStatus("Returning to dock - Lawn complete", false, DeviceCommand.RETURN)),
entry(776, new DeviceStatus("Returning to dock - Relocalising", false, DeviceCommand.RETURN)),
entry(1025, new DeviceStatus("Diagnostic mode", false, null)),
entry(1026, new DeviceStatus("End of life", false, null)),
entry(1281, new DeviceStatus("Software update", false, null)),
entry(64513, new DeviceStatus("Docked", true, DeviceCommand.RETURN)));
private String message; private static final Map<Integer, DeviceStatus> STATUS_MAP = Map.ofEntries(
entry(0, new DeviceStatus("reading-status", false, DeviceCommand.RETURN)),
entry(257, new DeviceStatus("charging", false, DeviceCommand.RETURN)),
entry(258, new DeviceStatus("docked", true, DeviceCommand.RETURN)),
entry(259, new DeviceStatus("docked-software-update", false, DeviceCommand.RETURN)),
entry(260, new DeviceStatus("docked", true, DeviceCommand.RETURN)),
entry(261, new DeviceStatus("docked", true, DeviceCommand.RETURN)),
entry(262, new DeviceStatus("docked-loading-map", false, DeviceCommand.MOW)),
entry(263, new DeviceStatus("docked-saving-map", false, DeviceCommand.RETURN)),
entry(513, new DeviceStatus("mowing", false, DeviceCommand.MOW)),
entry(514, new DeviceStatus("relocalising", false, DeviceCommand.MOW)),
entry(515, new DeviceStatus("loading-map", false, DeviceCommand.MOW)),
entry(516, new DeviceStatus("learning-lawn", false, DeviceCommand.MOW)),
entry(517, new DeviceStatus("paused", true, DeviceCommand.PAUSE)),
entry(518, new DeviceStatus("border-cut", false, DeviceCommand.MOW)),
entry(519, new DeviceStatus("idle-in-lawn", true, DeviceCommand.MOW)),
entry(769, new DeviceStatus("returning-to-dock", false, DeviceCommand.RETURN)),
entry(770, new DeviceStatus("returning-to-dock", false, DeviceCommand.RETURN)),
entry(771, new DeviceStatus("returning-to-dock-battery-low", false, DeviceCommand.RETURN)),
entry(772, new DeviceStatus("returning-to-dock-calendar-timeslot-ended", false, DeviceCommand.RETURN)),
entry(773, new DeviceStatus("returning-to-dock-battery-temp-range", false, DeviceCommand.RETURN)),
entry(774, new DeviceStatus("returning-to-dock", false, DeviceCommand.RETURN)),
entry(775, new DeviceStatus("returning-to-dock-lawn-complete", false, DeviceCommand.RETURN)),
entry(776, new DeviceStatus("returning-to-dock-relocalising", false, DeviceCommand.RETURN)),
entry(1025, new DeviceStatus("diagnostic-mode", false, null)),
entry(1026, new DeviceStatus("end-of-life", false, null)),
entry(1281, new DeviceStatus("software-update", false, null)),
entry(64513, new DeviceStatus("docked", true, DeviceCommand.RETURN)));
private String textKey;
private boolean isReadyToMow; private boolean isReadyToMow;
private @Nullable DeviceCommand associatedCommand; private @Nullable DeviceCommand associatedCommand;
private DeviceStatus(String message, boolean isReadyToMow, @Nullable DeviceCommand associatedCommand) { private DeviceStatus(String textKey, boolean isReadyToMow, @Nullable DeviceCommand associatedCommand) {
this.message = message; this.textKey = textKey;
this.isReadyToMow = isReadyToMow; this.isReadyToMow = isReadyToMow;
this.associatedCommand = associatedCommand; this.associatedCommand = associatedCommand;
} }
@ -95,11 +98,21 @@ public class DeviceStatus {
break; break;
} }
return new DeviceStatus(String.format("Unknown status code %d", code), false, command); return new DeviceStatus(String.valueOf(code), false, command);
} }
public String getMessage() { /**
return message; * Returns a localized description for this {@link DeviceStatus}.
*
* @param translationProvider
* @return localized status description
*/
public String getMessage(BoschIndegoTranslationProvider translationProvider) {
String textualState = translationProvider.getText(STATE_PREFIX + textKey);
if (textualState == null) {
textualState = String.format(translationProvider.getText(STATE_PREFIX + STATE_UNKNOWN, textKey), textKey);
}
return textualState;
} }
public boolean isReadyToMow() { public boolean isReadyToMow() {

View File

@ -20,6 +20,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.openhab.binding.boschindego.internal.BoschIndegoTranslationProvider;
import org.openhab.binding.boschindego.internal.DeviceStatus; import org.openhab.binding.boschindego.internal.DeviceStatus;
import org.openhab.binding.boschindego.internal.IndegoController; import org.openhab.binding.boschindego.internal.IndegoController;
import org.openhab.binding.boschindego.internal.config.BoschIndegoConfiguration; import org.openhab.binding.boschindego.internal.config.BoschIndegoConfiguration;
@ -53,15 +54,17 @@ public class BoschIndegoHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(BoschIndegoHandler.class); private final Logger logger = LoggerFactory.getLogger(BoschIndegoHandler.class);
private final HttpClient httpClient; private final HttpClient httpClient;
private final BoschIndegoTranslationProvider translationProvider;
private @NonNullByDefault({}) IndegoController controller; private @NonNullByDefault({}) IndegoController controller;
private @Nullable ScheduledFuture<?> pollFuture; private @Nullable ScheduledFuture<?> pollFuture;
private long refreshRate; private long refreshRate;
private boolean propertiesInitialized; private boolean propertiesInitialized;
public BoschIndegoHandler(Thing thing, HttpClient httpClient) { public BoschIndegoHandler(Thing thing, HttpClient httpClient, BoschIndegoTranslationProvider translationProvider) {
super(thing); super(thing);
this.httpClient = httpClient; this.httpClient = httpClient;
this.translationProvider = translationProvider;
} }
@Override @Override
@ -178,7 +181,7 @@ public class BoschIndegoHandler extends BaseThingHandler {
updateState(ERRORCODE, new DecimalType(error)); updateState(ERRORCODE, new DecimalType(error));
updateState(MOWED, new PercentType(mowed)); updateState(MOWED, new PercentType(mowed));
updateState(STATE, new DecimalType(status)); updateState(STATE, new DecimalType(status));
updateState(TEXTUAL_STATE, new StringType(deviceStatus.getMessage())); updateState(TEXTUAL_STATE, new StringType(deviceStatus.getMessage(translationProvider)));
} }
private boolean isReadyToMow(DeviceStatus deviceStatus, int error) { private boolean isReadyToMow(DeviceStatus deviceStatus, int error) {

View File

@ -31,34 +31,7 @@ channel-type.boschindego.state.state.option.1 = Mow
channel-type.boschindego.state.state.option.2 = Charge/Dock channel-type.boschindego.state.state.option.2 = Charge/Dock
channel-type.boschindego.state.state.option.3 = Pause channel-type.boschindego.state.state.option.3 = Pause
channel-type.boschindego.statecode.label = State Code channel-type.boschindego.statecode.label = State Code
channel-type.boschindego.statecode.description = API-code of the Indego state channel-type.boschindego.statecode.description = API code of the Indego state
channel-type.boschindego.statecode.state.option.0 = Reading status
channel-type.boschindego.statecode.state.option.257 = Charging
channel-type.boschindego.statecode.state.option.258 = Docked
channel-type.boschindego.statecode.state.option.259 = Docked - Software update
channel-type.boschindego.statecode.state.option.260 = Docked
channel-type.boschindego.statecode.state.option.261 = Docked
channel-type.boschindego.statecode.state.option.262 = Docked - Loading map
channel-type.boschindego.statecode.state.option.263 = Docked - Saving map
channel-type.boschindego.statecode.state.option.512 = Mowing
channel-type.boschindego.statecode.state.option.514 = Relocalising
channel-type.boschindego.statecode.state.option.515 = Loading map
channel-type.boschindego.statecode.state.option.516 = Learning lawn
channel-type.boschindego.statecode.state.option.517 = Paused
channel-type.boschindego.statecode.state.option.518 = Border cut
channel-type.boschindego.statecode.state.option.519 = Idle in lawn
channel-type.boschindego.statecode.state.option.769 = Returning to Dock
channel-type.boschindego.statecode.state.option.770 = Returning to Dock
channel-type.boschindego.statecode.state.option.771 = Returning to Dock - Battery low
channel-type.boschindego.statecode.state.option.772 = Returning to Dock - Calendar timeslot ended
channel-type.boschindego.statecode.state.option.773 = Returning to Dock - Battery temp range
channel-type.boschindego.statecode.state.option.774 = Returning to Dock
channel-type.boschindego.statecode.state.option.775 = Returning to Dock - Lawn complete
channel-type.boschindego.statecode.state.option.776 = Returning to Dock - Relocalising
channel-type.boschindego.statecode.state.option.1025 = Diagnostic mode
channel-type.boschindego.statecode.state.option.1026 = End of life
channel-type.boschindego.statecode.state.option.1281 = Software update
channel-type.boschindego.statecode.state.option.64513 = Docked
channel-type.boschindego.textualstate.label = Textual State channel-type.boschindego.textualstate.label = Textual State
# thing status descriptions # thing status descriptions
@ -66,3 +39,29 @@ channel-type.boschindego.textualstate.label = Textual State
offline.comm-error.authentication-failure = The login credentials are wrong or another client is connected to your Indego account offline.comm-error.authentication-failure = The login credentials are wrong or another client is connected to your Indego account
offline.conf-error.missing-password = Password missing offline.conf-error.missing-password = Password missing
offline.conf-error.missing-username = Username missing offline.conf-error.missing-username = Username missing
# indego states
indego.state.unknown = Unknown status code: %s
indego.state.reading-status = Reading status
indego.state.charging = Charging
indego.state.docked = Docked
indego.state.docked-software-update = Docked - Software update
indego.state.docked-loading-map = Docked - Loading map
indego.state.docked-saving-map = Docked - Saving map
indego.state.mowing = Mowing
indego.state.relocalising = Relocalising
indego.state.loading-map = Loading map
indego.state.learning-lawn = Learning lawn
indego.state.paused = Paused
indego.state.border-cut = Border cut
indego.state.idle-in-lawn = Idle in lawn
indego.state.returning-to-dock = Returning to Dock
indego.state.returning-to-dock-battery-low = Returning to Dock - Battery low
indego.state.returning-to-dock-calendar-timeslot-ended = Calendar timeslot ended
indego.state.returning-to-dock-battery-temp-range = Returning to Dock - Battery temp range
indego.state.returning-to-dock-lawn-complete = Returning to Dock - Lawn complete
indego.state.returning-to-dock-relocalising = Returning to Dock - Relocalising
indego.state.diagnostic-mode = Diagnostic mode
indego.state.end-of-life = End of life
indego.state.software-update = Software update

View File

@ -53,36 +53,36 @@
<channel-type id="statecode" advanced="true"> <channel-type id="statecode" advanced="true">
<item-type>Number</item-type> <item-type>Number</item-type>
<label>State Code</label> <label>State Code</label>
<description>API-code of the Indego state</description> <description>API code of the Indego state</description>
<state readOnly="true"> <state readOnly="true">
<options> <options>
<option value="0">Reading status</option> <option value="0">@text/indego.state.reading-status</option>
<option value="257">Charging</option> <option value="257">@text/indego.state.charging</option>
<option value="258">Docked</option> <option value="258">@text/indego.state.docked</option>
<option value="259">Docked - Software update</option> <option value="259">@text/indego.state.docked-software-update</option>
<option value="260">Docked</option> <option value="260">@text/indego.state.docked</option>
<option value="261">Docked</option> <option value="261">@text/indego.state.docked</option>
<option value="262">Docked - Loading map</option> <option value="262">@text/indego.state.docked-loading-map</option>
<option value="263">Docked - Saving map</option> <option value="263">@text/indego.state.docked-saving-map</option>
<option value="512">Mowing</option> <option value="512">@text/indego.state.mowing</option>
<option value="514">Relocalising</option> <option value="514">@text/indego.state.relocalising</option>
<option value="515">Loading map</option> <option value="515">@text/indego.state.loading-map</option>
<option value="516">Learning lawn</option> <option value="516">@text/indego.state.learning-lawn</option>
<option value="517">Paused</option> <option value="517">@text/indego.state.paused</option>
<option value="518">Border cut</option> <option value="518">@text/indego.state.border-cut</option>
<option value="519">Idle in lawn</option> <option value="519">@text/indego.state.idle-in-lawn</option>
<option value="769">Returning to Dock</option> <option value="769">@text/indego.state.returning-to-dock</option>
<option value="770">Returning to Dock</option> <option value="770">@text/indego.state.returning-to-dock</option>
<option value="771">Returning to Dock - Battery low</option> <option value="771">@text/indego.state.returning-to-dock-battery-low</option>
<option value="772">Returning to Dock - Calendar timeslot ended</option> <option value="772">@text/indego.state.returning-to-dock-calendar-timeslot-ended</option>
<option value="773">Returning to Dock - Battery temp range</option> <option value="773">@text/indego.state.returning-to-dock-battery-temp-range</option>
<option value="774">Returning to Dock</option> <option value="774">@text/indego.state.returning-to-dock</option>
<option value="775">Returning to Dock - Lawn complete</option> <option value="775">@text/indego.state.returning-to-dock-lawn-complete</option>
<option value="776">Returning to Dock - Relocalising</option> <option value="776">@text/indego.state.returning-to-dock-relocalising</option>
<option value="1025">Diagnostic mode</option> <option value="1025">@text/indego.state.diagnostic-mode</option>
<option value="1026">End of life</option> <option value="1026">@text/indego.state.end-of-life</option>
<option value="1281">Software update</option> <option value="1281">@text/indego.state.software-update</option>
<option value="64513">Docked</option> <option value="64513">@text/indego.state.docked</option>
</options> </options>
</state> </state>
</channel-type> </channel-type>