/** * Copyright (c) 2014-2017 by the respective copyright holders. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.core.thing.i18n; import java.util.Arrays; import java.util.Locale; import org.eclipse.smarthome.core.i18n.I18nProvider; import org.eclipse.smarthome.core.i18n.I18nUtil; import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingStatusInfo; import org.eclipse.smarthome.core.thing.binding.ThingHandler; import org.osgi.framework.Bundle; import org.osgi.framework.FrameworkUtil; /** * The {@link ThingStatusInfoI18nLocalizationService} can be used to localize the {@link ThingStatusInfo} of a thing * using the I18N mechanism of the Eclipse SmartHome framework. Currently the description of the {@link ThingStatusInfo} * is the single attribute which can be localized. * </p> * In order to provide a localized description the corresponding {@link ThingHandler} of the thing does not provide a * localized string in the <i>ThingStatus.description</i> attribute, but instead provides the reference of the * localization string, e.g @text/rate_limit. The handler is able to provide placeholder values as a JSON-serialized * array of strings: * * <pre> * @text/rate_limit ["60", "10", "@text/hour"] * </pre> * * <pre> * rate_limit=Device is blocked by remote service for {0} minutes. Maximum limit of {1} configuration * changes per {2} has been exceeded. For further info please refer to device vendor. * </pre> * * @author Thomas Höfer - Initial contribution */ public final class ThingStatusInfoI18nLocalizationService { private I18nProvider i18nProvider; /** * Localizes the {@link ThingStatusInfo} for the given thing. * * @param thing the thing whose thing status info is to be localized (must not be null) * @param locale the locale to be used (can be null) * @return the localized thing status or the original thing status if * <ul> * <li>there is nothing to be localized</li> * <li>the thing does not have a handler</li> * </ul> * * @throws IllegalArgumentException if given thing is null */ public ThingStatusInfo getLocalizedThingStatusInfo(Thing thing, Locale locale) { if (thing == null) { throw new IllegalArgumentException("Thing must not be null."); } ThingHandler thingHandler = thing.getHandler(); if (thingHandler == null) { return thing.getStatusInfo(); } String description = thing.getStatusInfo().getDescription(); if (!I18nUtil.isConstant(description)) { return thing.getStatusInfo(); } Bundle bundle = FrameworkUtil.getBundle(thingHandler.getClass()); Description desc = new Description(bundle, locale, description, i18nProvider); String translatedDescription = i18nProvider.getText(bundle, desc.key, description, locale, desc.args); return new ThingStatusInfo(thing.getStatus(), thing.getStatusInfo().getStatusDetail(), translatedDescription); } protected void setI18nProvider(I18nProvider i18nProvider) { this.i18nProvider = i18nProvider; } protected void unsetI18nProvider(I18nProvider i18nProvider) { i18nProvider = null; } /** * Utility class to parse the thing status description into the text reference and optional arguments. */ private final class Description { private static final int LIMIT = 2; private final String key; private final Object[] args; private Description(final Bundle bundle, final Locale locale, String description, final I18nProvider theI18nProvider) { String[] parts = description.split("\\s+", LIMIT); this.key = I18nUtil.stripConstant(parts[0]); if (parts.length == 1) { this.args = null; } else { this.args = Arrays.stream(parts[1].replaceAll("\\[|\\]|\"", "").split(",")).filter(s -> { if (s == null) { return false; } return !s.trim().isEmpty(); }).map(s -> { String input = s.trim(); return I18nUtil.isConstant(input) ? theI18nProvider.getText(bundle, I18nUtil.stripConstant(input), input, locale) : input; }).toArray(size -> new String[size]); } } } }