diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 7eb91847cf..acf1a3161c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -69,6 +69,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponse; import org.thingsboard.server.service.rpc.ToDeviceRpcRequestActorMsg; import org.thingsboard.server.service.rpc.ToServerRpcResponseActorMsg; import org.thingsboard.server.service.transport.msg.TransportToDeviceActorMsgWrapper; +import org.thingsboard.server.utils.JsonUtils; import javax.annotation.Nullable; import java.util.ArrayList; @@ -102,7 +103,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { private final Map toServerRpcPendingMap; private final Gson gson = new Gson(); - private final JsonParser jsonParser = new JsonParser(); private int rpcSeq = 0; private String deviceName; @@ -327,7 +327,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { } private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { - JsonObject json = getJsonObject(postAttributes.getKvList()); + JsonObject json = JsonUtils.getJsonObject(postAttributes.getKvList()); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); pushToRuleEngine(context, tbMsg); @@ -335,7 +335,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { private void handlePostTelemetryRequest(ActorContext context, SessionInfoProto sessionInfo, PostTelemetryMsg postTelemetry) { for (TsKvListProto tsKv : postTelemetry.getTsKvListList()) { - JsonObject json = getJsonObject(tsKv.getKvList()); + JsonObject json = JsonUtils.getJsonObject(tsKv.getKvList()); TbMsgMetaData metaData = defaultMetaData.copy(); metaData.putValue("ts", tsKv.getTs() + ""); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_TELEMETRY_REQUEST.name(), deviceId, metaData, TbMsgDataType.JSON, gson.toJson(json), null, null, 0L); @@ -347,7 +347,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { UUID sessionId = getSessionId(sessionInfo); JsonObject json = new JsonObject(); json.addProperty("method", request.getMethodName()); - json.add("params", jsonParser.parse(request.getParams())); + json.add("params", JsonUtils.parse(request.getParams())); TbMsgMetaData requestMetaData = defaultMetaData.copy(); requestMetaData.putValue("requestId", Integer.toString(request.getRequestId())); @@ -551,27 +551,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { this.defaultMetaData.putValue("deviceType", deviceType); } - private JsonObject getJsonObject(List tsKv) { - JsonObject json = new JsonObject(); - for (KeyValueProto kv : tsKv) { - switch (kv.getType()) { - case BOOLEAN_V: - json.addProperty(kv.getKey(), kv.getBoolV()); - break; - case LONG_V: - json.addProperty(kv.getKey(), kv.getLongV()); - break; - case DOUBLE_V: - json.addProperty(kv.getKey(), kv.getDoubleV()); - break; - case STRING_V: - json.addProperty(kv.getKey(), kv.getStringV()); - break; - } - } - return json; - } - private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() .setSessionIdMSB(sessionInfo.getSessionIdMSB()) @@ -643,6 +622,10 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { builder.setType(KeyValueType.STRING_V); builder.setStringV(kvEntry.getStrValue().get()); break; + case JSON: + builder.setType(KeyValueType.JSON_V); + builder.setJsonV(kvEntry.getJsonValue().get()); + break; } return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 124a6e7ba1..634a78de27 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -642,6 +642,8 @@ public abstract class BaseController { entityNode.put(attr.getKey(), attr.getDoubleValue().get()); } else if (attr.getDataType() == DataType.LONG) { entityNode.put(attr.getKey(), attr.getLongValue().get()); + } else if (attr.getDataType() == DataType.JSON) { + entityNode.set(attr.getKey(), json.readTree(attr.getJsonValue().get())); } else { entityNode.put(attr.getKey(), attr.getValueAsString()); } diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index 43b525021e..86a2457e99 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -15,12 +15,15 @@ */ package org.thingsboard.server.controller; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Function; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -56,8 +59,10 @@ import org.thingsboard.server.common.data.kv.BaseDeleteTsKvQuery; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; +import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -77,6 +82,7 @@ import org.thingsboard.server.service.telemetry.exception.UncheckedApiException; import javax.annotation.Nullable; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -107,6 +113,8 @@ public class TelemetryController extends BaseController { private ExecutorService executor; + private static final ObjectMapper mapper = new ObjectMapper(); + @PostConstruct public void initExecutor() { executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("telemetry-controller")); @@ -284,8 +292,7 @@ public class TelemetryController extends BaseController { if (startTs == null || endTs == null) { deleteToTs = endTs; return getImmediateDeferredResult("When deleteAllDataForKeys is false, start and end timestamp values shouldn't be empty", HttpStatus.BAD_REQUEST); - } - else{ + } else { deleteFromTs = startTs; deleteToTs = endTs; } @@ -536,8 +543,9 @@ public class TelemetryController extends BaseController { return new FutureCallback>() { @Override public void onSuccess(List attributes) { - List values = attributes.stream().map(attribute -> new AttributeData(attribute.getLastUpdateTs(), - attribute.getKey(), attribute.getValue())).collect(Collectors.toList()); + List values = attributes.stream().map(attribute -> + new AttributeData(attribute.getLastUpdateTs(), attribute.getKey(), getKvValue(attribute)) + ).collect(Collectors.toList()); logAttributesRead(user, entityId, scope, keyList, null); response.setResult(new ResponseEntity<>(values, HttpStatus.OK)); } @@ -639,7 +647,9 @@ public class TelemetryController extends BaseController { jsonNode.fields().forEachRemaining(entry -> { String key = entry.getKey(); JsonNode value = entry.getValue(); - if (entry.getValue().isTextual()) { + if (entry.getValue().isObject() || entry.getValue().isArray()) { + attributes.add(new BaseAttributeKvEntry(new JsonDataEntry(key, toJsonStr(value)), ts)); + } else if (entry.getValue().isTextual()) { if (maxStringValueLength > 0 && entry.getValue().textValue().length() > maxStringValueLength) { String message = String.format("String value length [%d] for key [%s] is greater than maximum allowed [%d]", entry.getValue().textValue().length(), key, maxStringValueLength); throw new UncheckedApiException(new InvalidParametersException(message)); @@ -659,4 +669,27 @@ public class TelemetryController extends BaseController { }); return attributes; } + + private String toJsonStr(JsonNode value) { + try { + return mapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + throw new JsonParseException("Can't parse jsonValue: " + value, e); + } + } + + private JsonNode toJsonNode(String value) { + try { + return mapper.readTree(value); + } catch (IOException e) { + throw new JsonParseException("Can't parse jsonValue: " + value, e); + } + } + + private Object getKvValue(KvEntry entry) { + if (entry.getDataType() == DataType.JSON) { + return toJsonNode(entry.getJsonValue().get()); + } + return entry.getValue(); + } } diff --git a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java index 14d9ff821f..7ef4363e77 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -136,6 +136,7 @@ public class ThingsboardInstallService { log.info("Upgrading ThingsBoard from version 2.4.3 to 2.5 ..."); databaseTsUpgradeService.upgradeDatabase("2.4.3"); + databaseEntitiesUpgradeService.upgradeDatabase("2.4.3"); log.info("Updating system data..."); diff --git a/application/src/main/java/org/thingsboard/server/service/install/AbstractCassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/AbstractCassandraDatabaseUpgradeService.java new file mode 100644 index 0000000000..603158314a --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/AbstractCassandraDatabaseUpgradeService.java @@ -0,0 +1,48 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * 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 org.thingsboard.server.service.install; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.thingsboard.server.dao.cassandra.CassandraCluster; +import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; +import org.thingsboard.server.service.install.cql.CQLStatementsParser; + +import java.nio.file.Path; +import java.util.List; + +@Slf4j +public abstract class AbstractCassandraDatabaseUpgradeService { + @Autowired + protected CassandraCluster cluster; + + @Autowired + @Qualifier("CassandraInstallCluster") + private CassandraInstallCluster installCluster; + + protected void loadCql(Path cql) throws Exception { + List statements = new CQLStatementsParser(cql).getStatements(); + statements.forEach(statement -> { + installCluster.getSession().execute(statement); + try { + Thread.sleep(2500); + } catch (InterruptedException e) { + } + }); + Thread.sleep(5000); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java index 7e05179be0..721d43bf9f 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraDatabaseUpgradeService.java @@ -19,20 +19,15 @@ import com.datastax.driver.core.KeyspaceMetadata; import com.datastax.driver.core.exceptions.InvalidQueryException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.cassandra.CassandraCluster; -import org.thingsboard.server.dao.cassandra.CassandraInstallCluster; import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.util.NoSqlDao; -import org.thingsboard.server.service.install.cql.CQLStatementsParser; import org.thingsboard.server.service.install.cql.CassandraDbHelper; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; import static org.thingsboard.server.service.install.DatabaseHelper.ADDITIONAL_INFO; import static org.thingsboard.server.service.install.DatabaseHelper.ASSET; @@ -59,17 +54,10 @@ import static org.thingsboard.server.service.install.DatabaseHelper.TYPE; @NoSqlDao @Profile("install") @Slf4j -public class CassandraDatabaseUpgradeService implements DatabaseEntitiesUpgradeService { +public class CassandraDatabaseUpgradeService extends AbstractCassandraDatabaseUpgradeService implements DatabaseEntitiesUpgradeService { private static final String SCHEMA_UPDATE_CQL = "schema_update.cql"; - @Autowired - private CassandraCluster cluster; - - @Autowired - @Qualifier("CassandraInstallCluster") - private CassandraInstallCluster installCluster; - @Autowired private DashboardService dashboardService; @@ -264,7 +252,8 @@ public class CassandraDatabaseUpgradeService implements DatabaseEntitiesUpgradeS try { cluster.getSession().execute(updateDeviceTableStmt); Thread.sleep(2500); - } catch (InvalidQueryException e) {} + } catch (InvalidQueryException e) { + } log.info("Schema updated."); break; case "2.4.1": @@ -275,7 +264,8 @@ public class CassandraDatabaseUpgradeService implements DatabaseEntitiesUpgradeS cluster.getSession().execute(updateAssetTableStmt); Thread.sleep(2500); log.info("Assets updated."); - } catch (InvalidQueryException e) {} + } catch (InvalidQueryException e) { + } log.info("Schema updated."); break; case "2.4.2": @@ -286,24 +276,25 @@ public class CassandraDatabaseUpgradeService implements DatabaseEntitiesUpgradeS cluster.getSession().execute(updateAlarmTableStmt); Thread.sleep(2500); log.info("Alarms updated."); - } catch (InvalidQueryException e) {} + } catch (InvalidQueryException e) { + } + log.info("Schema updated."); + break; + case "2.4.3": + log.info("Updating schema ..."); + String updateAttributeKvTableStmt = "alter table attributes_kv_cf add json_v text"; + try { + log.info("Updating attributes ..."); + cluster.getSession().execute(updateAttributeKvTableStmt); + Thread.sleep(2500); + log.info("Attributes updated."); + } catch (InvalidQueryException e) { + } log.info("Schema updated."); break; default: throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); } - - } - - private void loadCql(Path cql) throws Exception { - List statements = new CQLStatementsParser(cql).getStatements(); - statements.forEach(statement -> { - installCluster.getSession().execute(statement); - try { - Thread.sleep(2500); - } catch (InterruptedException e) {} - }); - Thread.sleep(5000); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java new file mode 100644 index 0000000000..4bc68e92bc --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/install/CassandraTsDatabaseUpgradeService.java @@ -0,0 +1,56 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * 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 org.thingsboard.server.service.install; + +import com.datastax.driver.core.exceptions.InvalidQueryException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Service; +import org.thingsboard.server.dao.util.NoSqlTsDao; + +@Service +@NoSqlTsDao +@Profile("install") +@Slf4j +public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabaseUpgradeService implements DatabaseTsUpgradeService { + + @Override + public void upgradeDatabase(String fromVersion) throws Exception { + switch (fromVersion) { + case "2.4.3": + log.info("Updating schema ..."); + String updateTsKvTableStmt = "alter table ts_kv_cf add json_v text"; + String updateTsKvLatestTableStmt = "alter table ts_kv_latest_cf add json_v text"; + + try { + log.info("Updating ts ..."); + cluster.getSession().execute(updateTsKvTableStmt); + Thread.sleep(2500); + log.info("Ts updated."); + log.info("Updating ts latest ..."); + cluster.getSession().execute(updateTsKvLatestTableStmt); + Thread.sleep(2500); + log.info("Ts latest updated."); + } catch (InvalidQueryException e) { + } + log.info("Schema updated."); + break; + default: + throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); + } + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index beba984077..fd907714fa 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -106,9 +106,10 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { node.put("smtpHost", "localhost"); node.put("smtpPort", "25"); node.put("timeout", "10000"); - node.put("enableTls", "false"); + node.put("enableTls", false); node.put("username", ""); - node.put("password", ""); //NOSONAR, key used to identify password field (not password value itself) + node.put("password", ""); + node.put("tlsVersion", "TLSv1.2");//NOSONAR, key used to identify password field (not password value itself) mailSettings.setJsonValue(node); adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, mailSettings); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java index 2b1cbd053d..eb951ed9ae 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/PsqlTsDatabaseUpgradeService.java @@ -101,6 +101,9 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe executeDropStatement(conn, DROP_FUNCTION_CREATE_NEW_TS_KV_LATEST_TABLE); executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST); + executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN json_v json;"); + executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN json_v json;"); + log.info("schema timeseries updated!"); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index d018c7fcef..aa5d3e3d95 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -207,6 +207,16 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.info("Schema updated."); } break; + case "2.4.3": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + try { + conn.createStatement().execute("ALTER TABLE attribute_kv ADD COLUMN json_v json;"); + } catch (Exception e) { + } + log.info("Schema updated."); + } + break; default: throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); } diff --git a/application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java index 84adbbc140..0c57e2e9bd 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/TimescaleTsDatabaseUpgradeService.java @@ -104,6 +104,9 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TENANT_TS_KV); executeDropStatement(conn, DROP_FUNCTION_INSERT_INTO_TS_KV_LATEST); + executeQuery(conn, "ALTER TABLE ts_kv ADD COLUMN json_v json;"); + executeQuery(conn, "ALTER TABLE ts_kv_latest ADD COLUMN json_v json;"); + log.info("schema timeseries updated!"); } } diff --git a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index 9916c0203a..baa0d417a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java +++ b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java @@ -103,7 +103,18 @@ public class DefaultMailService implements MailService { javaMailProperties.put(MAIL_PROP + protocol + ".port", jsonConfig.get("smtpPort").asText()); javaMailProperties.put(MAIL_PROP + protocol + ".timeout", jsonConfig.get("timeout").asText()); javaMailProperties.put(MAIL_PROP + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(jsonConfig.get("username").asText()))); - javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", jsonConfig.has("enableTls") ? jsonConfig.get("enableTls").asText() : "false"); + boolean enableTls = false; + if (jsonConfig.has("enableTls")) { + if (jsonConfig.get("enableTls").isBoolean() && jsonConfig.get("enableTls").booleanValue()) { + enableTls = true; + } else if (jsonConfig.get("enableTls").isTextual()) { + enableTls = "true".equalsIgnoreCase(jsonConfig.get("enableTls").asText()); + } + } + javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", enableTls); + if (enableTls && jsonConfig.has("tlsVersion") && StringUtils.isNoneEmpty(jsonConfig.get("tlsVersion").asText())) { + javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", jsonConfig.get("tlsVersion").asText()); + } return javaMailProperties; } @@ -213,7 +224,7 @@ public class DefaultMailService implements MailService { } @Override - public void sendAccountLockoutEmail( String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException { + public void sendAccountLockoutEmail(String lockoutEmail, String email, Integer maxFailedLoginAttempts) throws ThingsboardException { String subject = messages.getMessage("account.lockout.subject", null, Locale.US); Map model = new HashMap(); @@ -244,7 +255,7 @@ public class DefaultMailService implements MailService { } private static String mergeTemplateIntoString(VelocityEngine velocityEngine, String templateLocation, - String encoding, Map model) throws VelocityException { + String encoding, Map model) throws VelocityException { StringWriter result = new StringWriter(); mergeTemplate(velocityEngine, templateLocation, encoding, model, result); diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 45134a6bdd..d29e5de5b7 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -24,9 +24,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; +import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; -import org.thingsboard.common.util.DonAsynchron; import org.thingsboard.server.actors.service.ActorService; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; @@ -36,7 +36,20 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.kv.*; +import org.thingsboard.server.common.data.kv.Aggregation; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.BooleanDataEntry; +import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; +import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.kv.ReadTsKvQuery; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.cluster.SendToClusterMsg; import org.thingsboard.server.common.msg.cluster.ServerAddress; import org.thingsboard.server.dao.attributes.AttributesService; @@ -105,7 +118,7 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio @Autowired @Lazy private ActorService actorService; - + private ExecutorService tsCallBackExecutor; private ExecutorService wsCallBackExecutor; @@ -692,6 +705,10 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio Optional doubleValue = attr.getDoubleValue(); doubleValue.ifPresent(dataBuilder::setDoubleValue); break; + case JSON: + Optional jsonValue = attr.getJsonValue(); + jsonValue.ifPresent(dataBuilder::setJsonValue); + break; case STRING: Optional stringValue = attr.getStrValue(); stringValue.ifPresent(dataBuilder::setStrValue); @@ -724,6 +741,9 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio case STRING: entry = new StringDataEntry(proto.getKey(), proto.getStrValue()); break; + case JSON: + entry = new JsonDataEntry(proto.getKey(), proto.getJsonValue()); + break; } return entry; } diff --git a/application/src/main/java/org/thingsboard/server/utils/JsonUtils.java b/application/src/main/java/org/thingsboard/server/utils/JsonUtils.java new file mode 100644 index 0000000000..5621362c09 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/utils/JsonUtils.java @@ -0,0 +1,55 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * 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 org.thingsboard.server.utils; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; +import java.util.List; + +public class JsonUtils { + + private static final JsonParser jsonParser = new JsonParser(); + + public static JsonObject getJsonObject(List tsKv) { + JsonObject json = new JsonObject(); + for (KeyValueProto kv : tsKv) { + switch (kv.getType()) { + case BOOLEAN_V: + json.addProperty(kv.getKey(), kv.getBoolV()); + break; + case LONG_V: + json.addProperty(kv.getKey(), kv.getLongV()); + break; + case DOUBLE_V: + json.addProperty(kv.getKey(), kv.getDoubleV()); + break; + case STRING_V: + json.addProperty(kv.getKey(), kv.getStringV()); + break; + case JSON_V: + json.add(kv.getKey(), jsonParser.parse(kv.getJsonV())); + break; + } + } + return json; + } + + public static JsonElement parse(String params) { + return jsonParser.parse(params); + } +} diff --git a/application/src/main/proto/cluster.proto b/application/src/main/proto/cluster.proto index b4ebc52f5e..cfacc66121 100644 --- a/application/src/main/proto/cluster.proto +++ b/application/src/main/proto/cluster.proto @@ -125,6 +125,7 @@ message KeyValueProto { int64 longValue = 5; double doubleValue = 6; bool boolValue = 7; + string jsonValue = 8; } message FromDeviceRPCResponseProto { diff --git a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java index 4fe33e4716..8dc0acff57 100644 --- a/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/controller/ControllerSqlTestSuite.java @@ -30,7 +30,7 @@ public class ControllerSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java index 5fb8c4d0c7..2863589ba1 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/MqttSqlTestSuite.java @@ -29,7 +29,7 @@ public class MqttSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java index ce2c6852be..5f930821f7 100644 --- a/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/rules/RuleEngineSqlTestSuite.java @@ -30,7 +30,7 @@ public class RuleEngineSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); } diff --git a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java index 3cbb7d9773..b12d513ce0 100644 --- a/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java +++ b/application/src/test/java/org/thingsboard/server/system/SystemSqlTestSuite.java @@ -31,7 +31,7 @@ public class SystemSqlTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java index ecbd2c73f5..8dc9bf6abc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/SearchTextBasedWithAdditionalInfo.java @@ -35,6 +35,7 @@ import java.util.function.Consumer; @Slf4j public abstract class SearchTextBasedWithAdditionalInfo extends SearchTextBased implements HasAdditionalInfo { + private static final ObjectMapper mapper = new ObjectMapper(); private transient JsonNode additionalInfo; @JsonIgnore private byte[] additionalInfoBytes; @@ -97,7 +98,7 @@ public abstract class SearchTextBasedWithAdditionalInfo ext public static void setJson(JsonNode json, Consumer jsonConsumer, Consumer bytesConsumer) { jsonConsumer.accept(json); try { - bytesConsumer.accept(new ObjectMapper().writeValueAsBytes(json)); + bytesConsumer.accept(mapper.writeValueAsBytes(json)); } catch (JsonProcessingException e) { log.warn("Can't serialize json data: ", e); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java index ac8a5c2f78..5639f98d01 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BaseAttributeKvEntry.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.common.data.kv; +import com.fasterxml.jackson.databind.JsonNode; + import java.util.Optional; /** @@ -65,6 +67,11 @@ public class BaseAttributeKvEntry implements AttributeKvEntry { return kv.getDoubleValue(); } + @Override + public Optional getJsonValue() { + return kv.getJsonValue(); + } + @Override public String getValueAsString() { return kv.getValueAsString(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java index a41bf6b232..7bc92ff74c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicKvEntry.java @@ -51,6 +51,11 @@ public abstract class BasicKvEntry implements KvEntry { return Optional.ofNullable(null); } + @Override + public Optional getJsonValue() { + return Optional.ofNullable(null); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicTsKvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicTsKvEntry.java index f7628da74c..c2d6688004 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicTsKvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/BasicTsKvEntry.java @@ -58,6 +58,11 @@ public class BasicTsKvEntry implements TsKvEntry { return kv.getDoubleValue(); } + @Override + public Optional getJsonValue() { + return kv.getJsonValue(); + } + @Override public Object getValue() { return kv.getValue(); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/DataType.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/DataType.java index 84f918ede3..3571b0c882 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/DataType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/DataType.java @@ -17,6 +17,6 @@ package org.thingsboard.server.common.data.kv; public enum DataType { - STRING, LONG, BOOLEAN, DOUBLE; + STRING, LONG, BOOLEAN, DOUBLE, JSON; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/JsonDataEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/JsonDataEntry.java new file mode 100644 index 0000000000..0510f311d5 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/JsonDataEntry.java @@ -0,0 +1,69 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * 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 org.thingsboard.server.common.data.kv; + +import java.util.Objects; +import java.util.Optional; + +public class JsonDataEntry extends BasicKvEntry { + private final String value; + + public JsonDataEntry(String key, String value) { + super(key); + this.value = value; + } + + @Override + public DataType getDataType() { + return DataType.JSON; + } + + @Override + public Optional getJsonValue() { + return Optional.ofNullable(value); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof JsonDataEntry)) return false; + if (!super.equals(o)) return false; + JsonDataEntry that = (JsonDataEntry) o; + return Objects.equals(value, that.value); + } + + @Override + public Object getValue() { + return value; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), value); + } + + @Override + public String toString() { + return "JsonDataEntry{" + + "value=" + value + + "} " + super.toString(); + } + + @Override + public String getValueAsString() { + return value; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/kv/KvEntry.java b/common/data/src/main/java/org/thingsboard/server/common/data/kv/KvEntry.java index c8753fda8b..296ddd37aa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/kv/KvEntry.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/kv/KvEntry.java @@ -37,6 +37,8 @@ public interface KvEntry extends Serializable { Optional getDoubleValue(); + Optional getJsonValue(); + String getValueAsString(); Object getValue(); diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java index 03f840a17e..56e2c87d6e 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; @@ -59,6 +60,7 @@ import java.util.stream.Collectors; public class JsonConverter { private static final Gson GSON = new Gson(); + private static final JsonParser JSON_PARSER = new JsonParser(); private static final String CAN_T_PARSE_VALUE = "Can't parse value: "; private static final String DEVICE_PROPERTY = "device"; @@ -204,6 +206,14 @@ public class JsonConverter { } else if (!value.isJsonNull()) { throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value); } + } else if (element.isJsonObject() || element.isJsonArray()) { + result.add(KeyValueProto + .newBuilder() + .setKey(valueEntry + .getKey()) + .setType(KeyValueType.JSON_V) + .setJsonV(element.toString()) + .build()); } else if (!element.isJsonNull()) { throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element); } @@ -354,6 +364,9 @@ public class JsonConverter { case LONG_V: json.addProperty(name, entry.getLongV()); break; + case JSON_V: + json.add(name, JSON_PARSER.parse(entry.getJsonV())); + break; } } @@ -363,47 +376,48 @@ public class JsonConverter { private static Consumer addToObjectFromProto(JsonObject result) { return de -> { - JsonPrimitive value; switch (de.getKv().getType()) { case BOOLEAN_V: - value = new JsonPrimitive(de.getKv().getBoolV()); + result.add(de.getKv().getKey(), new JsonPrimitive(de.getKv().getBoolV())); break; case DOUBLE_V: - value = new JsonPrimitive(de.getKv().getDoubleV()); + result.add(de.getKv().getKey(), new JsonPrimitive(de.getKv().getDoubleV())); break; case LONG_V: - value = new JsonPrimitive(de.getKv().getLongV()); + result.add(de.getKv().getKey(), new JsonPrimitive(de.getKv().getLongV())); break; case STRING_V: - value = new JsonPrimitive(de.getKv().getStringV()); + result.add(de.getKv().getKey(), new JsonPrimitive(de.getKv().getStringV())); break; + case JSON_V: + result.add(de.getKv().getKey(), JSON_PARSER.parse(de.getKv().getJsonV())); default: throw new IllegalArgumentException("Unsupported data type: " + de.getKv().getType()); } - result.add(de.getKv().getKey(), value); }; } private static Consumer addToObject(JsonObject result) { return de -> { - JsonPrimitive value; switch (de.getDataType()) { case BOOLEAN: - value = new JsonPrimitive(de.getBooleanValue().get()); + result.add(de.getKey(), new JsonPrimitive(de.getBooleanValue().get())); break; case DOUBLE: - value = new JsonPrimitive(de.getDoubleValue().get()); + result.add(de.getKey(), new JsonPrimitive(de.getDoubleValue().get())); break; case LONG: - value = new JsonPrimitive(de.getLongValue().get()); + result.add(de.getKey(), new JsonPrimitive(de.getLongValue().get())); break; case STRING: - value = new JsonPrimitive(de.getStrValue().get()); + result.add(de.getKey(), new JsonPrimitive(de.getStrValue().get())); + break; + case JSON: + result.add(de.getKey(), JSON_PARSER.parse(de.getJsonValue().get())); break; default: throw new IllegalArgumentException("Unsupported data type: " + de.getDataType()); } - result.add(de.getKey(), value); }; } @@ -464,6 +478,8 @@ public class JsonConverter { } else { throw new JsonSyntaxException(CAN_T_PARSE_VALUE + value); } + } else if (element.isJsonObject() || element.isJsonArray()) { + result.add(new JsonDataEntry(valueEntry.getKey(), element.toString())); } else { throw new JsonSyntaxException(CAN_T_PARSE_VALUE + element); } diff --git a/common/transport/transport-api/src/main/proto/transport.proto b/common/transport/transport-api/src/main/proto/transport.proto index 2d536b1769..e8b513574a 100644 --- a/common/transport/transport-api/src/main/proto/transport.proto +++ b/common/transport/transport-api/src/main/proto/transport.proto @@ -47,6 +47,7 @@ enum KeyValueType { LONG_V = 1; DOUBLE_V = 2; STRING_V = 3; + JSON_V = 4; } message KeyValueProto { @@ -56,6 +57,7 @@ message KeyValueProto { int64 long_v = 4; double double_v = 5; string string_v = 6; + string json_v = 7; } message TsKvProto { diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java index 93a39f8ef4..481f2ac085 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CassandraBaseAttributesDao.java @@ -112,31 +112,18 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem @Override public ListenableFuture save(TenantId tenantId, EntityId entityId, String attributeType, AttributeKvEntry attribute) { - BoundStatement stmt = getSaveStmt().bind(); - stmt.setString(0, entityId.getEntityType().name()); - stmt.setUUID(1, entityId.getId()); - stmt.setString(2, attributeType); - stmt.setString(3, attribute.getKey()); - stmt.setLong(4, attribute.getLastUpdateTs()); - stmt.setString(5, attribute.getStrValue().orElse(null)); - Optional booleanValue = attribute.getBooleanValue(); - if (booleanValue.isPresent()) { - stmt.setBool(6, booleanValue.get()); - } else { - stmt.setToNull(6); - } - Optional longValue = attribute.getLongValue(); - if (longValue.isPresent()) { - stmt.setLong(7, longValue.get()); - } else { - stmt.setToNull(7); - } - Optional doubleValue = attribute.getDoubleValue(); - if (doubleValue.isPresent()) { - stmt.setDouble(8, doubleValue.get()); - } else { - stmt.setToNull(8); - } + BoundStatement stmt = getSaveStmt().bind() + .setString(0, entityId.getEntityType().name()) + .setUUID(1, entityId.getId()) + .setString(2, attributeType) + .setString(3, attribute.getKey()) + .setLong(4, attribute.getLastUpdateTs()) + .set(5, attribute.getStrValue().orElse(null), String.class) + .set(6, attribute.getBooleanValue().orElse(null), Boolean.class) + .set(7, attribute.getLongValue().orElse(null), Long.class) + .set(8, attribute.getDoubleValue().orElse(null), Double.class) + .set(9, attribute.getJsonValue().orElse(null), String.class); + log.trace("Generated save stmt [{}] for entityId {} and attributeType {} and attribute", stmt, entityId, attributeType, attribute); return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null); } @@ -172,8 +159,9 @@ public class CassandraBaseAttributesDao extends CassandraAbstractAsyncDao implem "," + ModelConstants.BOOLEAN_VALUE_COLUMN + "," + ModelConstants.LONG_VALUE_COLUMN + "," + ModelConstants.DOUBLE_VALUE_COLUMN + + "," + ModelConstants.JSON_VALUE_COLUMN + ")" + - " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); } return saveStmt; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java index a07c4868e6..96ce14c459 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/ModelConstants.java @@ -369,17 +369,18 @@ public class ModelConstants { public static final String STRING_VALUE_COLUMN = "str_v"; public static final String LONG_VALUE_COLUMN = "long_v"; public static final String DOUBLE_VALUE_COLUMN = "dbl_v"; + public static final String JSON_VALUE_COLUMN = "json_v"; - protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; + protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; - protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN)}; + protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN), count(JSON_VALUE_COLUMN)}; - protected static final String[] MIN_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, - new String[]{min(LONG_VALUE_COLUMN), min(DOUBLE_VALUE_COLUMN), min(BOOLEAN_VALUE_COLUMN), min(STRING_VALUE_COLUMN)}); - protected static final String[] MAX_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, - new String[]{max(LONG_VALUE_COLUMN), max(DOUBLE_VALUE_COLUMN), max(BOOLEAN_VALUE_COLUMN), max(STRING_VALUE_COLUMN)}); - protected static final String[] SUM_AGGREGATION_COLUMNS = ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, - new String[]{sum(LONG_VALUE_COLUMN), sum(DOUBLE_VALUE_COLUMN)}); + protected static final String[] MIN_AGGREGATION_COLUMNS = + ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, new String[]{min(LONG_VALUE_COLUMN), min(DOUBLE_VALUE_COLUMN), min(BOOLEAN_VALUE_COLUMN), min(STRING_VALUE_COLUMN), min(JSON_VALUE_COLUMN)}); + protected static final String[] MAX_AGGREGATION_COLUMNS = + ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, new String[]{max(LONG_VALUE_COLUMN), max(DOUBLE_VALUE_COLUMN), max(BOOLEAN_VALUE_COLUMN), max(STRING_VALUE_COLUMN), max(JSON_VALUE_COLUMN)}); + protected static final String[] SUM_AGGREGATION_COLUMNS = + ArrayUtils.addAll(COUNT_AGGREGATION_COLUMNS, new String[]{sum(LONG_VALUE_COLUMN), sum(DOUBLE_VALUE_COLUMN)}); protected static final String[] AVG_AGGREGATION_COLUMNS = SUM_AGGREGATION_COLUMNS; public static String min(String s) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTsKvEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTsKvEntity.java index d7ffc72a34..f0dd03b5ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTsKvEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractTsKvEntity.java @@ -19,6 +19,7 @@ import lombok.Data; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; @@ -29,12 +30,12 @@ import javax.persistence.Column; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import javax.persistence.Transient; - import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.BOOLEAN_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.DOUBLE_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.JSON_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.LONG_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.STRING_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.TS_COLUMN; @@ -68,6 +69,9 @@ public abstract class AbstractTsKvEntity implements ToData { @Column(name = DOUBLE_VALUE_COLUMN) protected Double doubleValue; + @Column(name = JSON_VALUE_COLUMN) + protected String jsonValue; + @Transient protected String strKey; @@ -93,6 +97,8 @@ public abstract class AbstractTsKvEntity implements ToData { kvEntry = new DoubleDataEntry(strKey, doubleValue); } else if (booleanValue != null) { kvEntry = new BooleanDataEntry(strKey, booleanValue); + } else if (jsonValue != null) { + kvEntry = new JsonDataEntry(strKey, jsonValue); } return new BasicTsKvEntry(ts, kvEntry); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AttributeKvEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AttributeKvEntity.java index 250d4325e5..f0de269cea 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AttributeKvEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AttributeKvEntity.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; @@ -33,6 +34,7 @@ import java.io.Serializable; import static org.thingsboard.server.dao.model.ModelConstants.BOOLEAN_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.DOUBLE_VALUE_COLUMN; +import static org.thingsboard.server.dao.model.ModelConstants.JSON_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.LAST_UPDATE_TS_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.LONG_VALUE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.STRING_VALUE_COLUMN; @@ -57,6 +59,9 @@ public class AttributeKvEntity implements ToData, Serializable @Column(name = DOUBLE_VALUE_COLUMN) private Double doubleValue; + @Column(name = JSON_VALUE_COLUMN) + private String jsonValue; + @Column(name = LAST_UPDATE_TS_COLUMN) private Long lastUpdateTs; @@ -71,7 +76,10 @@ public class AttributeKvEntity implements ToData, Serializable kvEntry = new DoubleDataEntry(id.getAttributeKey(), doubleValue); } else if (longValue != null) { kvEntry = new LongDataEntry(id.getAttributeKey(), longValue); + } else if (jsonValue != null) { + kvEntry = new JsonDataEntry(id.getAttributeKey(), jsonValue); } + return new BaseAttributeKvEntry(kvEntry, lastUpdateTs); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/hsql/TsKvEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/hsql/TsKvEntity.java index ba24543090..a38dc185a8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/hsql/TsKvEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sqlts/hsql/TsKvEntity.java @@ -16,30 +16,16 @@ package org.thingsboard.server.dao.model.sqlts.hsql; import lombok.Data; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.kv.BasicTsKvEntry; -import org.thingsboard.server.common.data.kv.BooleanDataEntry; -import org.thingsboard.server.common.data.kv.DoubleDataEntry; -import org.thingsboard.server.common.data.kv.KvEntry; -import org.thingsboard.server.common.data.kv.LongDataEntry; -import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.dao.model.ToData; import org.thingsboard.server.dao.model.sql.AbstractTsKvEntity; import javax.persistence.Column; import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.IdClass; import javax.persistence.Table; -import javax.persistence.Transient; -import java.util.UUID; - -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN; -import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_COLUMN; import static org.thingsboard.server.dao.model.ModelConstants.KEY_COLUMN; @Data @@ -98,12 +84,14 @@ public final class TsKvEntity extends AbstractTsKvEntity implements ToData PATTERN_THREAD_LOCAL = ThreadLocal.withInitial(() -> Pattern.compile(String.valueOf(Character.MIN_VALUE))); private static final String EMPTY_STR = ""; - private static final String BATCH_UPDATE = "UPDATE attribute_kv SET str_v = ?, long_v = ?, dbl_v = ?, bool_v = ?, last_update_ts = ? " + + private static final String BATCH_UPDATE = "UPDATE attribute_kv SET str_v = ?, long_v = ?, dbl_v = ?, bool_v = ?, json_v = cast(? AS json), last_update_ts = ? " + "WHERE entity_type = ? and entity_id = ? and attribute_type =? and attribute_key = ?;"; private static final String INSERT_OR_UPDATE = - "INSERT INTO attribute_kv (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, last_update_ts) " + - "VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?) " + + "INSERT INTO attribute_kv (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, json_v, last_update_ts) " + + "VALUES(?, ?, ?, ?, ?, ?, ?, ?, cast(? AS json), ?) " + "ON CONFLICT (entity_type, entity_id, attribute_type, attribute_key) " + - "DO UPDATE SET str_v = ?, long_v = ?, dbl_v = ?, bool_v = ?, last_update_ts = ?;"; - - protected static final String BOOL_V = "bool_v"; - protected static final String STR_V = "str_v"; - protected static final String LONG_V = "long_v"; - protected static final String DBL_V = "dbl_v"; + "DO UPDATE SET str_v = ?, long_v = ?, dbl_v = ?, bool_v = ?, json_v = cast(? AS json), last_update_ts = ?;"; @Autowired protected JdbcTemplate jdbcTemplate; @@ -68,74 +60,6 @@ public abstract class AttributeKvInsertRepository { @Value("${sql.remove_null_chars}") private boolean removeNullChars; - @PersistenceContext - protected EntityManager entityManager; - - public abstract void saveOrUpdate(AttributeKvEntity entity); - - protected void processSaveOrUpdate(AttributeKvEntity entity, String requestBoolValue, String requestStrValue, String requestLongValue, String requestDblValue) { - if (entity.getBooleanValue() != null) { - saveOrUpdateBoolean(entity, requestBoolValue); - } - if (entity.getStrValue() != null) { - saveOrUpdateString(entity, requestStrValue); - } - if (entity.getLongValue() != null) { - saveOrUpdateLong(entity, requestLongValue); - } - if (entity.getDoubleValue() != null) { - saveOrUpdateDouble(entity, requestDblValue); - } - } - - @Modifying - private void saveOrUpdateBoolean(AttributeKvEntity entity, String query) { - entityManager.createNativeQuery(query) - .setParameter("entity_type", entity.getId().getEntityType().name()) - .setParameter("entity_id", entity.getId().getEntityId()) - .setParameter("attribute_type", entity.getId().getAttributeType()) - .setParameter("attribute_key", entity.getId().getAttributeKey()) - .setParameter("bool_v", entity.getBooleanValue()) - .setParameter("last_update_ts", entity.getLastUpdateTs()) - .executeUpdate(); - } - - @Modifying - private void saveOrUpdateString(AttributeKvEntity entity, String query) { - entityManager.createNativeQuery(query) - .setParameter("entity_type", entity.getId().getEntityType().name()) - .setParameter("entity_id", entity.getId().getEntityId()) - .setParameter("attribute_type", entity.getId().getAttributeType()) - .setParameter("attribute_key", entity.getId().getAttributeKey()) - .setParameter("str_v", replaceNullChars(entity.getStrValue())) - .setParameter("last_update_ts", entity.getLastUpdateTs()) - .executeUpdate(); - } - - @Modifying - private void saveOrUpdateLong(AttributeKvEntity entity, String query) { - entityManager.createNativeQuery(query) - .setParameter("entity_type", entity.getId().getEntityType().name()) - .setParameter("entity_id", entity.getId().getEntityId()) - .setParameter("attribute_type", entity.getId().getAttributeType()) - .setParameter("attribute_key", entity.getId().getAttributeKey()) - .setParameter("long_v", entity.getLongValue()) - .setParameter("last_update_ts", entity.getLastUpdateTs()) - .executeUpdate(); - } - - @Modifying - private void saveOrUpdateDouble(AttributeKvEntity entity, String query) { - entityManager.createNativeQuery(query) - .setParameter("entity_type", entity.getId().getEntityType().name()) - .setParameter("entity_id", entity.getId().getEntityId()) - .setParameter("attribute_type", entity.getId().getAttributeType()) - .setParameter("attribute_key", entity.getId().getAttributeKey()) - .setParameter("dbl_v", entity.getDoubleValue()) - .setParameter("last_update_ts", entity.getLastUpdateTs()) - .executeUpdate(); - } - protected void saveOrUpdate(List entities) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override @@ -164,11 +88,13 @@ public abstract class AttributeKvInsertRepository { ps.setNull(4, Types.BOOLEAN); } - ps.setLong(5, kvEntity.getLastUpdateTs()); - ps.setString(6, kvEntity.getId().getEntityType().name()); - ps.setString(7, kvEntity.getId().getEntityId()); - ps.setString(8, kvEntity.getId().getAttributeType()); - ps.setString(9, kvEntity.getId().getAttributeKey()); + ps.setString(5, replaceNullChars(kvEntity.getJsonValue())); + + ps.setLong(6, kvEntity.getLastUpdateTs()); + ps.setString(7, kvEntity.getId().getEntityType().name()); + ps.setString(8, kvEntity.getId().getEntityId()); + ps.setString(9, kvEntity.getId().getAttributeType()); + ps.setString(10, kvEntity.getId().getAttributeKey()); } @Override @@ -199,35 +125,39 @@ public abstract class AttributeKvInsertRepository { ps.setString(2, kvEntity.getId().getEntityId()); ps.setString(3, kvEntity.getId().getAttributeType()); ps.setString(4, kvEntity.getId().getAttributeKey()); + ps.setString(5, replaceNullChars(kvEntity.getStrValue())); - ps.setString(10, replaceNullChars(kvEntity.getStrValue())); + ps.setString(11, replaceNullChars(kvEntity.getStrValue())); if (kvEntity.getLongValue() != null) { ps.setLong(6, kvEntity.getLongValue()); - ps.setLong(11, kvEntity.getLongValue()); + ps.setLong(12, kvEntity.getLongValue()); } else { ps.setNull(6, Types.BIGINT); - ps.setNull(11, Types.BIGINT); + ps.setNull(12, Types.BIGINT); } if (kvEntity.getDoubleValue() != null) { ps.setDouble(7, kvEntity.getDoubleValue()); - ps.setDouble(12, kvEntity.getDoubleValue()); + ps.setDouble(13, kvEntity.getDoubleValue()); } else { ps.setNull(7, Types.DOUBLE); - ps.setNull(12, Types.DOUBLE); + ps.setNull(13, Types.DOUBLE); } if (kvEntity.getBooleanValue() != null) { ps.setBoolean(8, kvEntity.getBooleanValue()); - ps.setBoolean(13, kvEntity.getBooleanValue()); + ps.setBoolean(14, kvEntity.getBooleanValue()); } else { ps.setNull(8, Types.BOOLEAN); - ps.setNull(13, Types.BOOLEAN); + ps.setNull(14, Types.BOOLEAN); } - ps.setLong(9, kvEntity.getLastUpdateTs()); - ps.setLong(14, kvEntity.getLastUpdateTs()); + ps.setString(9, replaceNullChars(kvEntity.getJsonValue())); + ps.setString(15, replaceNullChars(kvEntity.getJsonValue())); + + ps.setLong(10, kvEntity.getLastUpdateTs()); + ps.setLong(16, kvEntity.getLastUpdateTs()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/HsqlAttributesInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/HsqlAttributesInsertRepository.java index 8378a4488b..1d7aad384a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/HsqlAttributesInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/HsqlAttributesInsertRepository.java @@ -30,36 +30,16 @@ import java.util.List; @Transactional public class HsqlAttributesInsertRepository extends AttributeKvInsertRepository { - private static final String ON_BOOL_VALUE_UPDATE_SET_NULLS = " attribute_kv.str_v = null, attribute_kv.long_v = null, attribute_kv.dbl_v = null "; - private static final String ON_STR_VALUE_UPDATE_SET_NULLS = " attribute_kv.bool_v = null, attribute_kv.long_v = null, attribute_kv.dbl_v = null "; - private static final String ON_LONG_VALUE_UPDATE_SET_NULLS = " attribute_kv.str_v = null, attribute_kv.bool_v = null, attribute_kv.dbl_v = null "; - private static final String ON_DBL_VALUE_UPDATE_SET_NULLS = " attribute_kv.str_v = null, attribute_kv.long_v = null, attribute_kv.bool_v = null "; - - private static final String INSERT_BOOL_STATEMENT = getInsertOrUpdateString(BOOL_V, ON_BOOL_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_STR_STATEMENT = getInsertOrUpdateString(STR_V, ON_STR_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_LONG_STATEMENT = getInsertOrUpdateString(LONG_V, ON_LONG_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_DBL_STATEMENT = getInsertOrUpdateString(DBL_V, ON_DBL_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_OR_UPDATE = - "MERGE INTO attribute_kv USING(VALUES ?, ?, ?, ?, ?, ?, ?, ?, ?) " + - "A (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, last_update_ts) " + + "MERGE INTO attribute_kv USING(VALUES ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) " + + "A (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, json_v, last_update_ts) " + "ON (attribute_kv.entity_type=A.entity_type " + "AND attribute_kv.entity_id=A.entity_id " + "AND attribute_kv.attribute_type=A.attribute_type " + "AND attribute_kv.attribute_key=A.attribute_key) " + - "WHEN MATCHED THEN UPDATE SET attribute_kv.str_v = A.str_v, attribute_kv.long_v = A.long_v, attribute_kv.dbl_v = A.dbl_v, attribute_kv.bool_v = A.bool_v, attribute_kv.last_update_ts = A.last_update_ts " + - "WHEN NOT MATCHED THEN INSERT (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, last_update_ts) " + - "VALUES (A.entity_type, A.entity_id, A.attribute_type, A.attribute_key, A.str_v, A.long_v, A.dbl_v, A.bool_v, A.last_update_ts)"; - - @Override - public void saveOrUpdate(AttributeKvEntity entity) { - processSaveOrUpdate(entity, INSERT_BOOL_STATEMENT, INSERT_STR_STATEMENT, INSERT_LONG_STATEMENT, INSERT_DBL_STATEMENT); - } - - private static String getInsertOrUpdateString(String value, String nullValues) { - return "MERGE INTO attribute_kv USING(VALUES :entity_type, :entity_id, :attribute_type, :attribute_key, :" + value + ", :last_update_ts) A (entity_type, entity_id, attribute_type, attribute_key, " + value + ", last_update_ts) ON (attribute_kv.entity_type=A.entity_type AND attribute_kv.entity_id=A.entity_id AND attribute_kv.attribute_type=A.attribute_type AND attribute_kv.attribute_key=A.attribute_key) WHEN MATCHED THEN UPDATE SET attribute_kv." + value + " = A." + value + ", attribute_kv.last_update_ts = A.last_update_ts," + nullValues + "WHEN NOT MATCHED THEN INSERT (entity_type, entity_id, attribute_type, attribute_key, " + value + ", last_update_ts) VALUES (A.entity_type, A.entity_id, A.attribute_type, A.attribute_key, A." + value + ", A.last_update_ts)"; - } - + "WHEN MATCHED THEN UPDATE SET attribute_kv.str_v = A.str_v, attribute_kv.long_v = A.long_v, attribute_kv.dbl_v = A.dbl_v, attribute_kv.bool_v = A.bool_v, attribute_kv.json_v = A.json_v, attribute_kv.last_update_ts = A.last_update_ts " + + "WHEN NOT MATCHED THEN INSERT (entity_type, entity_id, attribute_type, attribute_key, str_v, long_v, dbl_v, bool_v, json_v, last_update_ts) " + + "VALUES (A.entity_type, A.entity_id, A.attribute_type, A.attribute_key, A.str_v, A.long_v, A.dbl_v, A.bool_v, A.json_v, A.last_update_ts)"; @Override protected void saveOrUpdate(List entities) { @@ -89,7 +69,9 @@ public class HsqlAttributesInsertRepository extends AttributeKvInsertRepository ps.setNull(8, Types.BOOLEAN); } - ps.setLong(9, entity.getLastUpdateTs()); + ps.setString(9, entity.getJsonValue()); + + ps.setLong(10, entity.getLastUpdateTs()); }); }); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java index 85a4541be2..ab9964d3e3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/JpaAttributeDao.java @@ -128,6 +128,7 @@ public class JpaAttributeDao extends JpaAbstractDaoListeningExecutorService impl entity.setDoubleValue(attribute.getDoubleValue().orElse(null)); entity.setLongValue(attribute.getLongValue().orElse(null)); entity.setBooleanValue(attribute.getBooleanValue().orElse(null)); + entity.setJsonValue(attribute.getJsonValue().orElse(null)); return addToQueue(entity); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/PsqlAttributesInsertRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/PsqlAttributesInsertRepository.java index 1f553ada04..020e63cd36 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/PsqlAttributesInsertRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/attributes/PsqlAttributesInsertRepository.java @@ -17,7 +17,6 @@ package org.thingsboard.server.dao.sql.attributes; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import org.thingsboard.server.dao.model.sql.AttributeKvEntity; import org.thingsboard.server.dao.util.PsqlDao; import org.thingsboard.server.dao.util.SqlDao; @@ -27,22 +26,4 @@ import org.thingsboard.server.dao.util.SqlDao; @Transactional public class PsqlAttributesInsertRepository extends AttributeKvInsertRepository { - private static final String ON_BOOL_VALUE_UPDATE_SET_NULLS = "str_v = null, long_v = null, dbl_v = null"; - private static final String ON_STR_VALUE_UPDATE_SET_NULLS = "bool_v = null, long_v = null, dbl_v = null"; - private static final String ON_LONG_VALUE_UPDATE_SET_NULLS = "str_v = null, bool_v = null, dbl_v = null"; - private static final String ON_DBL_VALUE_UPDATE_SET_NULLS = "str_v = null, long_v = null, bool_v = null"; - - private static final String INSERT_OR_UPDATE_BOOL_STATEMENT = getInsertOrUpdateString(BOOL_V, ON_BOOL_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_OR_UPDATE_STR_STATEMENT = getInsertOrUpdateString(STR_V, ON_STR_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_OR_UPDATE_LONG_STATEMENT = getInsertOrUpdateString(LONG_V , ON_LONG_VALUE_UPDATE_SET_NULLS); - private static final String INSERT_OR_UPDATE_DBL_STATEMENT = getInsertOrUpdateString(DBL_V, ON_DBL_VALUE_UPDATE_SET_NULLS); - - @Override - public void saveOrUpdate(AttributeKvEntity entity) { - processSaveOrUpdate(entity, INSERT_OR_UPDATE_BOOL_STATEMENT, INSERT_OR_UPDATE_STR_STATEMENT, INSERT_OR_UPDATE_LONG_STATEMENT, INSERT_OR_UPDATE_DBL_STATEMENT); - } - - private static String getInsertOrUpdateString(String value, String nullValues) { - return "INSERT INTO attribute_kv (entity_type, entity_id, attribute_type, attribute_key, " + value + ", last_update_ts) VALUES (:entity_type, :entity_id, :attribute_type, :attribute_key, :" + value + ", :last_update_ts) ON CONFLICT (entity_type, entity_id, attribute_type, attribute_key) DO UPDATE SET " + value + " = :" + value + ", last_update_ts = :last_update_ts," + nullValues; - } } \ No newline at end of file diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java index 63893c3a5e..e8cbf5d73b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/AbstractSqlTimeseriesDao.java @@ -253,6 +253,8 @@ public abstract class AbstractSqlTimeseriesDao extends JpaAbstractDaoListeningEx latestEntity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null)); latestEntity.setLongValue(tsKvEntry.getLongValue().orElse(null)); latestEntity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null)); + latestEntity.setJsonValue(tsKvEntry.getJsonValue().orElse(null)); + return tsLatestQueue.add(latestEntity); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/HsqlInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/HsqlInsertTsRepository.java index 2d10f35cd9..d1e5294309 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/HsqlInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/HsqlInsertTsRepository.java @@ -37,14 +37,14 @@ import java.util.List; public class HsqlInsertTsRepository extends AbstractInsertRepository implements InsertTsRepository { private static final String INSERT_OR_UPDATE = - "MERGE INTO ts_kv USING(VALUES ?, ?, ?, ?, ?, ?, ?) " + - "T (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) " + + "MERGE INTO ts_kv USING(VALUES ?, ?, ?, ?, ?, ?, ?, ?) " + + "T (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) " + "ON (ts_kv.entity_id=T.entity_id " + "AND ts_kv.key=T.key " + "AND ts_kv.ts=T.ts) " + - "WHEN MATCHED THEN UPDATE SET ts_kv.bool_v = T.bool_v, ts_kv.str_v = T.str_v, ts_kv.long_v = T.long_v, ts_kv.dbl_v = T.dbl_v " + - "WHEN NOT MATCHED THEN INSERT (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) " + - "VALUES (T.entity_id, T.key, T.ts, T.bool_v, T.str_v, T.long_v, T.dbl_v);"; + "WHEN MATCHED THEN UPDATE SET ts_kv.bool_v = T.bool_v, ts_kv.str_v = T.str_v, ts_kv.long_v = T.long_v, ts_kv.dbl_v = T.dbl_v ,ts_kv.json_v = T.json_v " + + "WHEN NOT MATCHED THEN INSERT (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) " + + "VALUES (T.entity_id, T.key, T.ts, T.bool_v, T.str_v, T.long_v, T.dbl_v, T.json_v);"; @Override public void saveOrUpdate(List> entities) { @@ -76,6 +76,8 @@ public class HsqlInsertTsRepository extends AbstractInsertRepository implements } else { ps.setNull(7, Types.DOUBLE); } + + ps.setString(8, tsKvEntity.getJsonValue()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/TsKvHsqlRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/TsKvHsqlRepository.java index 552d515e44..a7c0effb97 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/TsKvHsqlRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/hsql/TsKvHsqlRepository.java @@ -97,7 +97,8 @@ public interface TsKvHsqlRepository extends CrudRepository :startTs AND tskv.ts <= :endTs") CompletableFuture findCount(@Param("entityId") UUID entityId, @Param("entityKey") int entityKey, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/HsqlLatestInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/HsqlLatestInsertTsRepository.java index 931eb86689..65ac6257f0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/HsqlLatestInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/HsqlLatestInsertTsRepository.java @@ -36,11 +36,11 @@ import java.util.List; public class HsqlLatestInsertTsRepository extends AbstractInsertRepository implements InsertLatestTsRepository { private static final String INSERT_OR_UPDATE = - "MERGE INTO ts_kv_latest USING(VALUES ?, ?, ?, ?, ?, ?, ?) " + - "T (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) " + + "MERGE INTO ts_kv_latest USING(VALUES ?, ?, ?, ?, ?, ?, ?, ?) " + + "T (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) " + "ON (ts_kv_latest.entity_id=T.entity_id " + "AND ts_kv_latest.key=T.key) " + - "WHEN MATCHED THEN UPDATE SET ts_kv_latest.ts = T.ts, ts_kv_latest.bool_v = T.bool_v, ts_kv_latest.str_v = T.str_v, ts_kv_latest.long_v = T.long_v, ts_kv_latest.dbl_v = T.dbl_v " + + "WHEN MATCHED THEN UPDATE SET ts_kv_latest.ts = T.ts, ts_kv_latest.bool_v = T.bool_v, ts_kv_latest.str_v = T.str_v, ts_kv_latest.long_v = T.long_v, ts_kv_latest.dbl_v = T.dbl_v, ts_kv_latest.json_v = T.json_v " + "WHEN NOT MATCHED THEN INSERT (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) " + "VALUES (T.entity_id, T.key, T.ts, T.bool_v, T.str_v, T.long_v, T.dbl_v);"; @@ -72,6 +72,8 @@ public class HsqlLatestInsertTsRepository extends AbstractInsertRepository imple } else { ps.setNull(7, Types.DOUBLE); } + + ps.setString(8, entities.get(i).getJsonValue()); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/PsqlLatestInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/PsqlLatestInsertTsRepository.java index 16a4c4ccd8..d367f44620 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/PsqlLatestInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/PsqlLatestInsertTsRepository.java @@ -38,12 +38,12 @@ import java.util.List; public class PsqlLatestInsertTsRepository extends AbstractInsertRepository implements InsertLatestTsRepository { private static final String BATCH_UPDATE = - "UPDATE ts_kv_latest SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ? WHERE entity_id = ? and key = ?"; + "UPDATE ts_kv_latest SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json) WHERE entity_id = ? and key = ?"; private static final String INSERT_OR_UPDATE = - "INSERT INTO ts_kv_latest (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES(?, ?, ?, ?, ?, ?, ?) " + - "ON CONFLICT (entity_id, key) DO UPDATE SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;"; + "INSERT INTO ts_kv_latest (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) VALUES(?, ?, ?, ?, ?, ?, ?, cast(? AS json)) " + + "ON CONFLICT (entity_id, key) DO UPDATE SET ts = ?, bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json);"; @Override public void saveOrUpdate(List entities) { @@ -76,8 +76,10 @@ public class PsqlLatestInsertTsRepository extends AbstractInsertRepository imple ps.setNull(5, Types.DOUBLE); } - ps.setObject(6, tsKvLatestEntity.getEntityId()); - ps.setInt(7, tsKvLatestEntity.getKey()); + ps.setString(6, replaceNullChars(tsKvLatestEntity.getJsonValue())); + + ps.setObject(7, tsKvLatestEntity.getEntityId()); + ps.setInt(8, tsKvLatestEntity.getKey()); } @Override @@ -106,36 +108,39 @@ public class PsqlLatestInsertTsRepository extends AbstractInsertRepository imple TsKvLatestEntity tsKvLatestEntity = insertEntities.get(i); ps.setObject(1, tsKvLatestEntity.getEntityId()); ps.setInt(2, tsKvLatestEntity.getKey()); + ps.setLong(3, tsKvLatestEntity.getTs()); - ps.setLong(8, tsKvLatestEntity.getTs()); + ps.setLong(9, tsKvLatestEntity.getTs()); if (tsKvLatestEntity.getBooleanValue() != null) { ps.setBoolean(4, tsKvLatestEntity.getBooleanValue()); - ps.setBoolean(9, tsKvLatestEntity.getBooleanValue()); + ps.setBoolean(10, tsKvLatestEntity.getBooleanValue()); } else { ps.setNull(4, Types.BOOLEAN); - ps.setNull(9, Types.BOOLEAN); + ps.setNull(10, Types.BOOLEAN); } ps.setString(5, replaceNullChars(tsKvLatestEntity.getStrValue())); - ps.setString(10, replaceNullChars(tsKvLatestEntity.getStrValue())); - + ps.setString(11, replaceNullChars(tsKvLatestEntity.getStrValue())); if (tsKvLatestEntity.getLongValue() != null) { ps.setLong(6, tsKvLatestEntity.getLongValue()); - ps.setLong(11, tsKvLatestEntity.getLongValue()); + ps.setLong(12, tsKvLatestEntity.getLongValue()); } else { ps.setNull(6, Types.BIGINT); - ps.setNull(11, Types.BIGINT); + ps.setNull(12, Types.BIGINT); } if (tsKvLatestEntity.getDoubleValue() != null) { ps.setDouble(7, tsKvLatestEntity.getDoubleValue()); - ps.setDouble(12, tsKvLatestEntity.getDoubleValue()); + ps.setDouble(13, tsKvLatestEntity.getDoubleValue()); } else { ps.setNull(7, Types.DOUBLE); - ps.setNull(12, Types.DOUBLE); + ps.setNull(13, Types.DOUBLE); } + + ps.setString(8, replaceNullChars(tsKvLatestEntity.getJsonValue())); + ps.setString(14, replaceNullChars(tsKvLatestEntity.getJsonValue())); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/SearchTsKvLatestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/SearchTsKvLatestRepository.java index 5940a33d31..b5da093b6f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/SearchTsKvLatestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/SearchTsKvLatestRepository.java @@ -29,8 +29,9 @@ import java.util.UUID; public class SearchTsKvLatestRepository { public static final String FIND_ALL_BY_ENTITY_ID = "findAllByEntityId"; + public static final String FIND_ALL_BY_ENTITY_ID_QUERY = "SELECT ts_kv_latest.entity_id AS entityId, ts_kv_latest.key AS key, ts_kv_dictionary.key AS strKey, ts_kv_latest.str_v AS strValue," + - " ts_kv_latest.bool_v AS boolValue, ts_kv_latest.long_v AS longValue, ts_kv_latest.dbl_v AS doubleValue, ts_kv_latest.ts AS ts FROM ts_kv_latest " + + " ts_kv_latest.bool_v AS boolValue, ts_kv_latest.long_v AS longValue, ts_kv_latest.dbl_v AS doubleValue, ts_kv_latest.json_v AS jsonValue, ts_kv_latest.ts AS ts FROM ts_kv_latest " + "INNER JOIN ts_kv_dictionary ON ts_kv_latest.key = ts_kv_dictionary.key_id WHERE ts_kv_latest.entity_id = cast(:id AS uuid)"; @PersistenceContext diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java index 9ba59c10ef..5232b88489 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/latest/TsKvLatestRepository.java @@ -20,11 +20,7 @@ import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestCompositeKey; import org.thingsboard.server.dao.model.sqlts.latest.TsKvLatestEntity; import org.thingsboard.server.dao.util.SqlDao; -import java.util.List; -import java.util.UUID; - @SqlDao public interface TsKvLatestRepository extends CrudRepository { - List findAllByEntityId(UUID entityId); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java index f598742713..6d60e843ec 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/JpaPsqlTimeseriesDao.java @@ -104,6 +104,7 @@ public class JpaPsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null)); entity.setLongValue(tsKvEntry.getLongValue().orElse(null)); entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null)); + entity.setJsonValue(tsKvEntry.getJsonValue().orElse(null)); PsqlPartition psqlPartition = toPartition(tsKvEntry.getTs()); log.trace("Saving entity: {}", entity); return tsQueue.add(new EntityContainer(entity, psqlPartition.getPartitionDate())); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/PsqlInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/PsqlInsertTsRepository.java index e9cf5c9b03..caf4528812 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/PsqlInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/PsqlInsertTsRepository.java @@ -41,8 +41,8 @@ public class PsqlInsertTsRepository extends AbstractInsertRepository implements private static final String INSERT_INTO_TS_KV = "INSERT INTO ts_kv_"; - private static final String VALUES_ON_CONFLICT_DO_UPDATE = " (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES (?, ?, ?, ?, ?, ?, ?) " + - "ON CONFLICT (entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;"; + private static final String VALUES_ON_CONFLICT_DO_UPDATE = " (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) VALUES (?, ?, ?, ?, ?, ?, ?, cast(? AS json)) " + + "ON CONFLICT (entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json);"; @Override public void saveOrUpdate(List> entities) { @@ -61,30 +61,33 @@ public class PsqlInsertTsRepository extends AbstractInsertRepository implements if (tsKvEntity.getBooleanValue() != null) { ps.setBoolean(4, tsKvEntity.getBooleanValue()); - ps.setBoolean(8, tsKvEntity.getBooleanValue()); + ps.setBoolean(9, tsKvEntity.getBooleanValue()); } else { ps.setNull(4, Types.BOOLEAN); - ps.setNull(8, Types.BOOLEAN); + ps.setNull(9, Types.BOOLEAN); } ps.setString(5, replaceNullChars(tsKvEntity.getStrValue())); - ps.setString(9, replaceNullChars(tsKvEntity.getStrValue())); + ps.setString(10, replaceNullChars(tsKvEntity.getStrValue())); if (tsKvEntity.getLongValue() != null) { ps.setLong(6, tsKvEntity.getLongValue()); - ps.setLong(10, tsKvEntity.getLongValue()); + ps.setLong(11, tsKvEntity.getLongValue()); } else { ps.setNull(6, Types.BIGINT); - ps.setNull(10, Types.BIGINT); + ps.setNull(11, Types.BIGINT); } if (tsKvEntity.getDoubleValue() != null) { ps.setDouble(7, tsKvEntity.getDoubleValue()); - ps.setDouble(11, tsKvEntity.getDoubleValue()); + ps.setDouble(12, tsKvEntity.getDoubleValue()); } else { ps.setNull(7, Types.DOUBLE); - ps.setNull(11, Types.DOUBLE); + ps.setNull(12, Types.DOUBLE); + + ps.setString(8, replaceNullChars(tsKvEntity.getJsonValue())); + ps.setString(13, replaceNullChars(tsKvEntity.getJsonValue())); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/TsKvPsqlRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/TsKvPsqlRepository.java index 7b3328f86b..b164046bbc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/TsKvPsqlRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/psql/TsKvPsqlRepository.java @@ -98,7 +98,8 @@ public interface TsKvPsqlRepository extends CrudRepository :startTs AND tskv.ts <= :endTs") CompletableFuture findCount(@Param("entityId") UUID entityId, @Param("entityKey") int entityKey, diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java index 15deb702a7..5a0b9c6a59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/AggregationRepository.java @@ -36,18 +36,17 @@ public class AggregationRepository { public static final String FIND_SUM = "findSum"; public static final String FIND_COUNT = "findCount"; - public static final String FROM_WHERE_CLAUSE = "FROM tenant_ts_kv tskv WHERE tskv.tenant_id = cast(:tenantId AS uuid) AND tskv.entity_id = cast(:entityId AS uuid) AND tskv.key= cast(:entityKey AS int) AND tskv.ts > :startTs AND tskv.ts <= :endTs GROUP BY tskv.tenant_id, tskv.entity_id, tskv.key, tsBucket ORDER BY tskv.tenant_id, tskv.entity_id, tskv.key, tsBucket"; public static final String FIND_AVG_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, 'AVG' AS aggType "; - public static final String FIND_MAX_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MAX(COALESCE(tskv.long_v, -9223372036854775807)) AS longValue, MAX(COALESCE(tskv.dbl_v, -1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MAX(tskv.str_v) AS strValue, 'MAX' AS aggType "; + public static final String FIND_MAX_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MAX(COALESCE(tskv.long_v, -9223372036854775807)) AS longValue, MAX(COALESCE(tskv.dbl_v, -1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MAX(tskv.str_v) AS strValue, MAX(tskv.json_v) AS jsonValue, 'MAX' AS aggType "; - public static final String FIND_MIN_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MIN(COALESCE(tskv.long_v, 9223372036854775807)) AS longValue, MIN(COALESCE(tskv.dbl_v, 1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MIN(tskv.str_v) AS strValue, 'MIN' AS aggType "; + public static final String FIND_MIN_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, MIN(COALESCE(tskv.long_v, 9223372036854775807)) AS longValue, MIN(COALESCE(tskv.dbl_v, 1.79769E+308)) as doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, MIN(tskv.str_v) AS strValue, MIN(tskv.json_v) AS jsonValue,'MIN' AS aggType "; - public static final String FIND_SUM_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, 'SUM' AS aggType "; + public static final String FIND_SUM_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(COALESCE(tskv.long_v, 0)) AS longValue, SUM(COALESCE(tskv.dbl_v, 0.0)) AS doubleValue, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longCountValue, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleCountValue, null AS strValue, null AS jsonValue, 'SUM' AS aggType "; - public static final String FIND_COUNT_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(CASE WHEN tskv.bool_v IS NULL THEN 0 ELSE 1 END) AS booleanValueCount, SUM(CASE WHEN tskv.str_v IS NULL THEN 0 ELSE 1 END) AS strValueCount, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longValueCount, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleValueCount "; + public static final String FIND_COUNT_QUERY = "SELECT time_bucket(:timeBucket, tskv.ts) AS tsBucket, :timeBucket AS interval, SUM(CASE WHEN tskv.bool_v IS NULL THEN 0 ELSE 1 END) AS booleanValueCount, SUM(CASE WHEN tskv.str_v IS NULL THEN 0 ELSE 1 END) AS strValueCount, SUM(CASE WHEN tskv.long_v IS NULL THEN 0 ELSE 1 END) AS longValueCount, SUM(CASE WHEN tskv.dbl_v IS NULL THEN 0 ELSE 1 END) AS doubleValueCount, SUM(CASE WHEN tskv.json_v IS NULL THEN 0 ELSE 1 END) AS jsonValueCount "; @PersistenceContext private EntityManager entityManager; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertTsRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertTsRepository.java index a6fad65fbf..6d863af105 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertTsRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleInsertTsRepository.java @@ -37,8 +37,8 @@ import java.util.List; public class TimescaleInsertTsRepository extends AbstractInsertRepository implements InsertTsRepository { private static final String INSERT_OR_UPDATE = - "INSERT INTO tenant_ts_kv (tenant_id, entity_id, key, ts, bool_v, str_v, long_v, dbl_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?) " + - "ON CONFLICT (tenant_id, entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?;"; + "INSERT INTO tenant_ts_kv (tenant_id, entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) VALUES(?, ?, ?, ?, ?, ?, ?, ?, cast(? AS json)) " + + "ON CONFLICT (tenant_id, entity_id, key, ts) DO UPDATE SET bool_v = ?, str_v = ?, long_v = ?, dbl_v = ?, json_v = cast(? AS json);"; @Override public void saveOrUpdate(List> entities) { @@ -56,28 +56,31 @@ public class TimescaleInsertTsRepository extends AbstractInsertRepository implem ps.setBoolean(9, tsKvEntity.getBooleanValue()); } else { ps.setNull(5, Types.BOOLEAN); - ps.setNull(9, Types.BOOLEAN); + ps.setNull(10, Types.BOOLEAN); } ps.setString(6, replaceNullChars(tsKvEntity.getStrValue())); - ps.setString(10, replaceNullChars(tsKvEntity.getStrValue())); + ps.setString(11, replaceNullChars(tsKvEntity.getStrValue())); if (tsKvEntity.getLongValue() != null) { ps.setLong(7, tsKvEntity.getLongValue()); - ps.setLong(11, tsKvEntity.getLongValue()); + ps.setLong(12, tsKvEntity.getLongValue()); } else { ps.setNull(7, Types.BIGINT); - ps.setNull(11, Types.BIGINT); + ps.setNull(12, Types.BIGINT); } if (tsKvEntity.getDoubleValue() != null) { ps.setDouble(8, tsKvEntity.getDoubleValue()); - ps.setDouble(12, tsKvEntity.getDoubleValue()); + ps.setDouble(13, tsKvEntity.getDoubleValue()); } else { ps.setNull(8, Types.DOUBLE); - ps.setNull(12, Types.DOUBLE); + ps.setNull(13, Types.DOUBLE); } + + ps.setString(9, replaceNullChars(tsKvEntity.getJsonValue())); + ps.setString(14, replaceNullChars(tsKvEntity.getJsonValue())); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java index f7e51ef18c..9f8f5c6f74 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/timescale/TimescaleTimeseriesDao.java @@ -174,6 +174,8 @@ public class TimescaleTimeseriesDao extends AbstractSqlTimeseriesDao implements entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null)); entity.setLongValue(tsKvEntry.getLongValue().orElse(null)); entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null)); + entity.setJsonValue(tsKvEntry.getJsonValue().orElse(null)); + log.trace("Saving entity to timescale db: {}", entity); return tsQueue.add(new EntityContainer(entity, null)); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java index d81ddc3801..6229f68818 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/AggregatePartitionsFunction.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -41,10 +42,12 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct private static final int DOUBLE_CNT_POS = 1; private static final int BOOL_CNT_POS = 2; private static final int STR_CNT_POS = 3; - private static final int LONG_POS = 4; - private static final int DOUBLE_POS = 5; - private static final int BOOL_POS = 6; - private static final int STR_POS = 7; + private static final int JSON_CNT_POS = 4; + private static final int LONG_POS = 5; + private static final int DOUBLE_POS = 6; + private static final int BOOL_POS = 7; + private static final int STR_POS = 8; + private static final int JSON_POS = 9; private final Aggregation aggregation; private final String key; @@ -72,7 +75,7 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct } } return processAggregationResult(aggResult); - }catch (Exception e){ + } catch (Exception e) { log.error("[{}][{}][{}] Failed to aggregate data", key, ts, aggregation, e); return Optional.empty(); } @@ -85,11 +88,13 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct Double curDValue = null; Boolean curBValue = null; String curSValue = null; + String curJValue = null; long longCount = row.getLong(LONG_CNT_POS); long doubleCount = row.getLong(DOUBLE_CNT_POS); long boolCount = row.getLong(BOOL_CNT_POS); long strCount = row.getLong(STR_CNT_POS); + long jsonCount = row.getLong(JSON_CNT_POS); if (longCount > 0 || doubleCount > 0) { if (longCount > 0) { @@ -111,6 +116,10 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct aggResult.dataType = DataType.STRING; curCount = strCount; curSValue = getStringValue(row); + } else if (jsonCount > 0) { + aggResult.dataType = DataType.JSON; + curCount = jsonCount; + curJValue = getJsonValue(row); } else { return; } @@ -120,9 +129,9 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct } else if (aggregation == Aggregation.AVG || aggregation == Aggregation.SUM) { processAvgOrSumAggregation(aggResult, curCount, curLValue, curDValue); } else if (aggregation == Aggregation.MIN) { - processMinAggregation(aggResult, curLValue, curDValue, curBValue, curSValue); + processMinAggregation(aggResult, curLValue, curDValue, curBValue, curSValue, curJValue); } else if (aggregation == Aggregation.MAX) { - processMaxAggregation(aggResult, curLValue, curDValue, curBValue, curSValue); + processMaxAggregation(aggResult, curLValue, curDValue, curBValue, curSValue, curJValue); } } @@ -136,7 +145,7 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct } } - private void processMinAggregation(AggregationResult aggResult, Long curLValue, Double curDValue, Boolean curBValue, String curSValue) { + private void processMinAggregation(AggregationResult aggResult, Long curLValue, Double curDValue, Boolean curBValue, String curSValue, String curJValue) { if (curDValue != null || curLValue != null) { if (curDValue != null) { aggResult.dValue = aggResult.dValue == null ? curDValue : Math.min(aggResult.dValue, curDValue); @@ -148,10 +157,12 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct aggResult.bValue = aggResult.bValue == null ? curBValue : aggResult.bValue && curBValue; } else if (curSValue != null && (aggResult.sValue == null || curSValue.compareTo(aggResult.sValue) < 0)) { aggResult.sValue = curSValue; + } else if (curJValue != null && (aggResult.jValue == null || curJValue.compareTo(aggResult.jValue) < 0)) { + aggResult.jValue = curJValue; } } - private void processMaxAggregation(AggregationResult aggResult, Long curLValue, Double curDValue, Boolean curBValue, String curSValue) { + private void processMaxAggregation(AggregationResult aggResult, Long curLValue, Double curDValue, Boolean curBValue, String curSValue, String curJValue) { if (curDValue != null || curLValue != null) { if (curDValue != null) { aggResult.dValue = aggResult.dValue == null ? curDValue : Math.max(aggResult.dValue, curDValue); @@ -163,6 +174,8 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct aggResult.bValue = aggResult.bValue == null ? curBValue : aggResult.bValue || curBValue; } else if (curSValue != null && (aggResult.sValue == null || curSValue.compareTo(aggResult.sValue) > 0)) { aggResult.sValue = curSValue; + } else if (curJValue != null && (aggResult.jValue == null || curJValue.compareTo(aggResult.jValue) > 0)) { + aggResult.jValue = curJValue; } } @@ -182,6 +195,14 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct } } + private String getJsonValue(Row row) { + if (aggregation == Aggregation.MIN || aggregation == Aggregation.MAX) { + return row.getString(JSON_POS); + } else { + return null; + } + } + private Long getLongValue(Row row) { if (aggregation == Aggregation.MIN || aggregation == Aggregation.MAX || aggregation == Aggregation.SUM || aggregation == Aggregation.AVG) { @@ -223,7 +244,7 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct if (aggResult.count == 0 || (aggResult.dataType == DataType.DOUBLE && aggResult.dValue == null) || (aggResult.dataType == DataType.LONG && aggResult.lValue == null)) { return Optional.empty(); } else if (aggResult.dataType == DataType.DOUBLE || aggResult.dataType == DataType.LONG) { - if(aggregation == Aggregation.AVG || aggResult.hasDouble) { + if (aggregation == Aggregation.AVG || aggResult.hasDouble) { double sum = Optional.ofNullable(aggResult.dValue).orElse(0.0d) + Optional.ofNullable(aggResult.lValue).orElse(0L); return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, aggregation == Aggregation.SUM ? sum : (sum / aggResult.count)))); } else { @@ -235,15 +256,17 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct private Optional processMinOrMaxResult(AggregationResult aggResult) { if (aggResult.dataType == DataType.DOUBLE || aggResult.dataType == DataType.LONG) { - if(aggResult.hasDouble) { + if (aggResult.hasDouble) { double currentD = aggregation == Aggregation.MIN ? Optional.ofNullable(aggResult.dValue).orElse(Double.MAX_VALUE) : Optional.ofNullable(aggResult.dValue).orElse(Double.MIN_VALUE); double currentL = aggregation == Aggregation.MIN ? Optional.ofNullable(aggResult.lValue).orElse(Long.MAX_VALUE) : Optional.ofNullable(aggResult.lValue).orElse(Long.MIN_VALUE); return Optional.of(new BasicTsKvEntry(ts, new DoubleDataEntry(key, aggregation == Aggregation.MIN ? Math.min(currentD, currentL) : Math.max(currentD, currentL)))); } else { return Optional.of(new BasicTsKvEntry(ts, new LongDataEntry(key, aggResult.lValue))); } - } else if (aggResult.dataType == DataType.STRING) { + } else if (aggResult.dataType == DataType.STRING) { return Optional.of(new BasicTsKvEntry(ts, new StringDataEntry(key, aggResult.sValue))); + } else if (aggResult.dataType == DataType.JSON) { + return Optional.of(new BasicTsKvEntry(ts, new JsonDataEntry(key, aggResult.jValue))); } else { return Optional.of(new BasicTsKvEntry(ts, new BooleanDataEntry(key, aggResult.bValue))); } @@ -253,6 +276,7 @@ public class AggregatePartitionsFunction implements com.google.common.base.Funct DataType dataType = null; Boolean bValue = null; String sValue = null; + String jValue = null; Double dValue = null; Long lValue = null; long count = 0; diff --git a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java index d0ebb49572..8fc8b4ab8a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/timeseries/CassandraBaseTimeseriesDao.java @@ -29,6 +29,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; @@ -42,6 +43,7 @@ import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.DeleteTsKvQuery; import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.JsonDataEntry; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; @@ -337,21 +339,31 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.BOOLEAN)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.DOUBLE)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.STRING)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.JSON)); break; case BOOLEAN: futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.DOUBLE)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.LONG)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.STRING)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.JSON)); break; case DOUBLE: futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.BOOLEAN)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.LONG)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.STRING)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.JSON)); break; case STRING: futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.BOOLEAN)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.DOUBLE)); futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.LONG)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.JSON)); + break; + case JSON: + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.BOOLEAN)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.DOUBLE)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.LONG)); + futures.add(saveNull(tenantId, entityId, tsKvEntry, ttl, partition, DataType.STRING)); break; } } @@ -411,6 +423,13 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem .set(5, tsKvEntry.getStrValue().orElse(null), String.class) .set(6, tsKvEntry.getLongValue().orElse(null), Long.class) .set(7, tsKvEntry.getDoubleValue().orElse(null), Double.class); + Optional jsonV = tsKvEntry.getJsonValue(); + if (jsonV.isPresent()) { + stmt.setString(8, tsKvEntry.getJsonValue().get()); + } else { + stmt.setToNull(8); + } + return getFuture(executeAsyncWrite(tenantId, stmt), rs -> null); } @@ -669,7 +688,12 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem if (boolV != null) { kvEntry = new BooleanDataEntry(key, boolV); } else { - log.warn("All values in key-value row are nullable "); + String jsonV = row.get(ModelConstants.JSON_VALUE_COLUMN, String.class); + if (StringUtils.isNoneEmpty(jsonV)) { + kvEntry = new JsonDataEntry(key, jsonV); + } else { + log.warn("All values in key-value row are nullable "); + } } } } @@ -772,8 +796,9 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem "," + ModelConstants.BOOLEAN_VALUE_COLUMN + "," + ModelConstants.STRING_VALUE_COLUMN + "," + ModelConstants.LONG_VALUE_COLUMN + - "," + ModelConstants.DOUBLE_VALUE_COLUMN + ")" + - " VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); + "," + ModelConstants.DOUBLE_VALUE_COLUMN + + "," + ModelConstants.JSON_VALUE_COLUMN + ")" + + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?)"); } return latestInsertStmt; } @@ -812,7 +837,8 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem ModelConstants.STRING_VALUE_COLUMN + "," + ModelConstants.BOOLEAN_VALUE_COLUMN + "," + ModelConstants.LONG_VALUE_COLUMN + "," + - ModelConstants.DOUBLE_VALUE_COLUMN + " " + + ModelConstants.DOUBLE_VALUE_COLUMN + "," + + ModelConstants.JSON_VALUE_COLUMN + " " + "FROM " + ModelConstants.TS_KV_LATEST_CF + " " + "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM + @@ -829,7 +855,8 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem ModelConstants.STRING_VALUE_COLUMN + "," + ModelConstants.BOOLEAN_VALUE_COLUMN + "," + ModelConstants.LONG_VALUE_COLUMN + "," + - ModelConstants.DOUBLE_VALUE_COLUMN + " " + + ModelConstants.DOUBLE_VALUE_COLUMN + "," + + ModelConstants.JSON_VALUE_COLUMN + " " + "FROM " + ModelConstants.TS_KV_LATEST_CF + " " + "WHERE " + ModelConstants.ENTITY_TYPE_COLUMN + EQUALS_PARAM + "AND " + ModelConstants.ENTITY_ID_COLUMN + EQUALS_PARAM); @@ -847,6 +874,8 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem return ModelConstants.LONG_VALUE_COLUMN; case DOUBLE: return ModelConstants.DOUBLE_VALUE_COLUMN; + case JSON: + return ModelConstants.JSON_VALUE_COLUMN; default: throw new RuntimeException("Not implemented!"); } @@ -856,27 +885,23 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem switch (kvEntry.getDataType()) { case BOOLEAN: Optional booleanValue = kvEntry.getBooleanValue(); - if (booleanValue.isPresent()) { - stmt.setBool(column, booleanValue.get().booleanValue()); - } + booleanValue.ifPresent(b -> stmt.setBool(column, b)); break; case STRING: Optional stringValue = kvEntry.getStrValue(); - if (stringValue.isPresent()) { - stmt.setString(column, stringValue.get()); - } + stringValue.ifPresent(s -> stmt.setString(column, s)); break; case LONG: Optional longValue = kvEntry.getLongValue(); - if (longValue.isPresent()) { - stmt.setLong(column, longValue.get().longValue()); - } + longValue.ifPresent(l -> stmt.setLong(column, l)); break; case DOUBLE: Optional doubleValue = kvEntry.getDoubleValue(); - if (doubleValue.isPresent()) { - stmt.setDouble(column, doubleValue.get().doubleValue()); - } + doubleValue.ifPresent(d -> stmt.setDouble(column, d)); + break; + case JSON: + Optional jsonValue = kvEntry.getJsonValue(); + jsonValue.ifPresent(jsonObject -> stmt.setString(column, jsonObject)); break; } } diff --git a/dao/src/main/resources/cassandra/schema-entities.cql b/dao/src/main/resources/cassandra/schema-entities.cql index e9844f7b1c..de2b088cef 100644 --- a/dao/src/main/resources/cassandra/schema-entities.cql +++ b/dao/src/main/resources/cassandra/schema-entities.cql @@ -410,6 +410,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.attributes_kv_cf ( str_v text, long_v bigint, dbl_v double, + json_v text, last_update_ts bigint, PRIMARY KEY ((entity_type, entity_id, attribute_type), attribute_key) ) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; diff --git a/dao/src/main/resources/cassandra/schema-ts.cql b/dao/src/main/resources/cassandra/schema-ts.cql index 338b420436..c0f4b74467 100644 --- a/dao/src/main/resources/cassandra/schema-ts.cql +++ b/dao/src/main/resources/cassandra/schema-ts.cql @@ -30,6 +30,7 @@ CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_cf ( str_v text, long_v bigint, dbl_v double, + json_v text, PRIMARY KEY (( entity_type, entity_id, key, partition ), ts) ); @@ -51,5 +52,6 @@ CREATE TABLE IF NOT EXISTS thingsboard.ts_kv_latest_cf ( str_v text, long_v bigint, dbl_v double, + json_v text, PRIMARY KEY (( entity_type, entity_id ), key) ) WITH compaction = { 'class' : 'LeveledCompactionStrategy' }; diff --git a/dao/src/main/resources/cassandra/system-data.cql b/dao/src/main/resources/cassandra/system-data.cql index 2a30dc80f7..96446449f3 100644 --- a/dao/src/main/resources/cassandra/system-data.cql +++ b/dao/src/main/resources/cassandra/system-data.cql @@ -38,7 +38,8 @@ VALUES ( now ( ), 'mail', '{ "smtpHost": "localhost", "smtpPort": "25", "timeout": "10000", - "enableTls": "false", + "enableTls": false, + "tlsVersion": "TLSv1.2", "username": "", "password": "" }' ); \ No newline at end of file diff --git a/dao/src/main/resources/sql/schema-entities-hsql.sql b/dao/src/main/resources/sql/schema-entities-hsql.sql new file mode 100644 index 0000000000..758aaafb10 --- /dev/null +++ b/dao/src/main/resources/sql/schema-entities-hsql.sql @@ -0,0 +1,251 @@ +-- +-- Copyright © 2016-2020 The Thingsboard Authors +-- +-- 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. +-- + + +CREATE TABLE IF NOT EXISTS admin_settings ( + id varchar(31) NOT NULL CONSTRAINT admin_settings_pkey PRIMARY KEY, + json_value varchar, + key varchar(255) +); + +CREATE TABLE IF NOT EXISTS alarm ( + id varchar(31) NOT NULL CONSTRAINT alarm_pkey PRIMARY KEY, + ack_ts bigint, + clear_ts bigint, + additional_info varchar, + end_ts bigint, + originator_id varchar(31), + originator_type integer, + propagate boolean, + severity varchar(255), + start_ts bigint, + status varchar(255), + tenant_id varchar(31), + propagate_relation_types varchar, + type varchar(255) +); + +CREATE TABLE IF NOT EXISTS asset ( + id varchar(31) NOT NULL CONSTRAINT asset_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + name varchar(255), + label varchar(255), + search_text varchar(255), + tenant_id varchar(31), + type varchar(255), + CONSTRAINT asset_name_unq_key UNIQUE (tenant_id, name) +); + +CREATE TABLE IF NOT EXISTS audit_log ( + id varchar(31) NOT NULL CONSTRAINT audit_log_pkey PRIMARY KEY, + tenant_id varchar(31), + customer_id varchar(31), + entity_id varchar(31), + entity_type varchar(255), + entity_name varchar(255), + user_id varchar(31), + user_name varchar(255), + action_type varchar(255), + action_data varchar(1000000), + action_status varchar(255), + action_failure_details varchar(1000000) +); + +CREATE TABLE IF NOT EXISTS attribute_kv ( + entity_type varchar(255), + entity_id varchar(31), + attribute_type varchar(255), + attribute_key varchar(255), + bool_v boolean, + str_v varchar(10000000), + long_v bigint, + dbl_v double precision, + json_v varchar(10000000), + last_update_ts bigint, + CONSTRAINT attribute_kv_pkey PRIMARY KEY (entity_type, entity_id, attribute_type, attribute_key) +); + +CREATE TABLE IF NOT EXISTS component_descriptor ( + id varchar(31) NOT NULL CONSTRAINT component_descriptor_pkey PRIMARY KEY, + actions varchar(255), + clazz varchar UNIQUE, + configuration_descriptor varchar, + name varchar(255), + scope varchar(255), + search_text varchar(255), + type varchar(255) +); + +CREATE TABLE IF NOT EXISTS customer ( + id varchar(31) NOT NULL CONSTRAINT customer_pkey PRIMARY KEY, + additional_info varchar, + address varchar, + address2 varchar, + city varchar(255), + country varchar(255), + email varchar(255), + phone varchar(255), + search_text varchar(255), + state varchar(255), + tenant_id varchar(31), + title varchar(255), + zip varchar(255) +); + +CREATE TABLE IF NOT EXISTS dashboard ( + id varchar(31) NOT NULL CONSTRAINT dashboard_pkey PRIMARY KEY, + configuration varchar(10000000), + assigned_customers varchar(1000000), + search_text varchar(255), + tenant_id varchar(31), + title varchar(255) +); + +CREATE TABLE IF NOT EXISTS device ( + id varchar(31) NOT NULL CONSTRAINT device_pkey PRIMARY KEY, + additional_info varchar, + customer_id varchar(31), + type varchar(255), + name varchar(255), + label varchar(255), + search_text varchar(255), + tenant_id varchar(31), + CONSTRAINT device_name_unq_key UNIQUE (tenant_id, name) +); + +CREATE TABLE IF NOT EXISTS device_credentials ( + id varchar(31) NOT NULL CONSTRAINT device_credentials_pkey PRIMARY KEY, + credentials_id varchar, + credentials_type varchar(255), + credentials_value varchar, + device_id varchar(31), + CONSTRAINT device_credentials_id_unq_key UNIQUE (credentials_id) +); + +CREATE TABLE IF NOT EXISTS event ( + id varchar(31) NOT NULL CONSTRAINT event_pkey PRIMARY KEY, + body varchar(10000000), + entity_id varchar(31), + entity_type varchar(255), + event_type varchar(255), + event_uid varchar(255), + tenant_id varchar(31), + CONSTRAINT event_unq_key UNIQUE (tenant_id, entity_type, entity_id, event_type, event_uid) +); + +CREATE TABLE IF NOT EXISTS relation ( + from_id varchar(31), + from_type varchar(255), + to_id varchar(31), + to_type varchar(255), + relation_type_group varchar(255), + relation_type varchar(255), + additional_info varchar, + CONSTRAINT relation_pkey PRIMARY KEY (from_id, from_type, relation_type_group, relation_type, to_id, to_type) +); + +CREATE TABLE IF NOT EXISTS tb_user ( + id varchar(31) NOT NULL CONSTRAINT tb_user_pkey PRIMARY KEY, + additional_info varchar, + authority varchar(255), + customer_id varchar(31), + email varchar(255) UNIQUE, + first_name varchar(255), + last_name varchar(255), + search_text varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS tenant ( + id varchar(31) NOT NULL CONSTRAINT tenant_pkey PRIMARY KEY, + additional_info varchar, + address varchar, + address2 varchar, + city varchar(255), + country varchar(255), + email varchar(255), + phone varchar(255), + region varchar(255), + search_text varchar(255), + state varchar(255), + title varchar(255), + zip varchar(255) +); + +CREATE TABLE IF NOT EXISTS user_credentials ( + id varchar(31) NOT NULL CONSTRAINT user_credentials_pkey PRIMARY KEY, + activate_token varchar(255) UNIQUE, + enabled boolean, + password varchar(255), + reset_token varchar(255) UNIQUE, + user_id varchar(31) UNIQUE +); + +CREATE TABLE IF NOT EXISTS widget_type ( + id varchar(31) NOT NULL CONSTRAINT widget_type_pkey PRIMARY KEY, + alias varchar(255), + bundle_alias varchar(255), + descriptor varchar(1000000), + name varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS widgets_bundle ( + id varchar(31) NOT NULL CONSTRAINT widgets_bundle_pkey PRIMARY KEY, + alias varchar(255), + search_text varchar(255), + tenant_id varchar(31), + title varchar(255) +); + +CREATE TABLE IF NOT EXISTS rule_chain ( + id varchar(31) NOT NULL CONSTRAINT rule_chain_pkey PRIMARY KEY, + additional_info varchar, + configuration varchar(10000000), + name varchar(255), + first_rule_node_id varchar(31), + root boolean, + debug_mode boolean, + search_text varchar(255), + tenant_id varchar(31) +); + +CREATE TABLE IF NOT EXISTS rule_node ( + id varchar(31) NOT NULL CONSTRAINT rule_node_pkey PRIMARY KEY, + rule_chain_id varchar(31), + additional_info varchar, + configuration varchar(10000000), + type varchar(255), + name varchar(255), + debug_mode boolean, + search_text varchar(255) +); + +CREATE TABLE IF NOT EXISTS entity_view ( + id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, + entity_id varchar(31), + entity_type varchar(255), + tenant_id varchar(31), + customer_id varchar(31), + type varchar(255), + name varchar(255), + keys varchar(10000000), + start_ts bigint, + end_ts bigint, + search_text varchar(255), + additional_info varchar +); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index f59b1045bc..55893fc124 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -74,6 +74,7 @@ CREATE TABLE IF NOT EXISTS attribute_kv ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v json, last_update_ts bigint, CONSTRAINT attribute_kv_pkey PRIMARY KEY (entity_type, entity_id, attribute_type, attribute_key) ); diff --git a/dao/src/main/resources/sql/schema-timescale.sql b/dao/src/main/resources/sql/schema-timescale.sql index e8cf0de263..7251d8be4e 100644 --- a/dao/src/main/resources/sql/schema-timescale.sql +++ b/dao/src/main/resources/sql/schema-timescale.sql @@ -25,6 +25,7 @@ CREATE TABLE IF NOT EXISTS tenant_ts_kv ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v json, CONSTRAINT tenant_ts_kv_pkey PRIMARY KEY (tenant_id, entity_id, key, ts) ); @@ -42,5 +43,6 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v json, CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) ); \ No newline at end of file diff --git a/dao/src/main/resources/sql/schema-ts-hsql.sql b/dao/src/main/resources/sql/schema-ts-hsql.sql index c29d7e2ed7..eb053a7a84 100644 --- a/dao/src/main/resources/sql/schema-ts-hsql.sql +++ b/dao/src/main/resources/sql/schema-ts-hsql.sql @@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS ts_kv ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v varchar(10000000), CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_id, key, ts) ); @@ -35,6 +36,7 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v varchar(10000000), CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) ); diff --git a/dao/src/main/resources/sql/schema-ts-psql.sql b/dao/src/main/resources/sql/schema-ts-psql.sql index 465c2d51e3..32b6762c8e 100644 --- a/dao/src/main/resources/sql/schema-ts-psql.sql +++ b/dao/src/main/resources/sql/schema-ts-psql.sql @@ -21,7 +21,8 @@ CREATE TABLE IF NOT EXISTS ts_kv ( bool_v boolean, str_v varchar(10000000), long_v bigint, - dbl_v double precision + dbl_v double precision, + json_v json ) PARTITION BY RANGE (ts); CREATE TABLE IF NOT EXISTS ts_kv_latest ( @@ -32,6 +33,7 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest ( str_v varchar(10000000), long_v bigint, dbl_v double precision, + json_v json, CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_id, key) ); diff --git a/dao/src/main/resources/sql/system-data.sql b/dao/src/main/resources/sql/system-data.sql index 6fe28be73d..f261eb2c04 100644 --- a/dao/src/main/resources/sql/system-data.sql +++ b/dao/src/main/resources/sql/system-data.sql @@ -38,7 +38,8 @@ VALUES ( '1e746126eaaefa6a91992ebcb67fe33', 'mail', '{ "smtpHost": "localhost", "smtpPort": "25", "timeout": "10000", - "enableTls": "false", + "enableTls": false, + "tlsVersion": "TLSv1.2", "username": "", "password": "" }' ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java index f4d11b328e..0af8603bf1 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/JpaDaoTestSuite.java @@ -30,7 +30,7 @@ public class JpaDaoTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/system-data.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/system-data.sql"), "sql/drop-all-tables.sql", "sql-test.properties" ); diff --git a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java index caddbabc35..7ebab237a8 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java +++ b/dao/src/test/java/org/thingsboard/server/dao/SqlDaoServiceTestSuite.java @@ -30,7 +30,7 @@ public class SqlDaoServiceTestSuite { @ClassRule public static CustomSqlUnit sqlUnit = new CustomSqlUnit( - Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), + Arrays.asList("sql/schema-ts-hsql.sql", "sql/schema-entities-hsql.sql", "sql/schema-entities-idx.sql", "sql/system-data.sql", "sql/system-test.sql"), "sql/drop-all-tables.sql", "sql-test.properties" ); diff --git a/msa/tb/docker-cassandra/Dockerfile b/msa/tb/docker-cassandra/Dockerfile index d1dfc21973..3a761398fd 100644 --- a/msa/tb/docker-cassandra/Dockerfile +++ b/msa/tb/docker-cassandra/Dockerfile @@ -19,7 +19,7 @@ FROM thingsboard/openjdk8 RUN apt-get update RUN apt-get install -y curl nmap procps RUN echo 'deb http://www.apache.org/dist/cassandra/debian 311x main' | tee --append /etc/apt/sources.list.d/cassandra.list > /dev/null -RUN curl https://www.apache.org/dist/cassandra/KEYS | apt-key add - +RUN curl -L https://www.apache.org/dist/cassandra/KEYS | apt-key add - RUN apt-get update RUN apt-get install -y cassandra cassandra-tools RUN update-rc.d cassandra disable diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java index 0b044ec37c..1c41c2a124 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNode.java @@ -20,8 +20,12 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.mail.javamail.JavaMailSenderImpl; import org.springframework.mail.javamail.MimeMessageHelper; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.TbNodeUtils; -import org.thingsboard.rule.engine.api.*; import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; @@ -137,10 +141,13 @@ public class TbSendEmailNode implements TbNode { String protocol = this.config.getSmtpProtocol(); javaMailProperties.put("mail.transport.protocol", protocol); javaMailProperties.put(MAIL_PROP + protocol + ".host", this.config.getSmtpHost()); - javaMailProperties.put(MAIL_PROP + protocol + ".port", this.config.getSmtpPort()+""); - javaMailProperties.put(MAIL_PROP + protocol + ".timeout", this.config.getTimeout()+""); + javaMailProperties.put(MAIL_PROP + protocol + ".port", this.config.getSmtpPort() + ""); + javaMailProperties.put(MAIL_PROP + protocol + ".timeout", this.config.getTimeout() + ""); javaMailProperties.put(MAIL_PROP + protocol + ".auth", String.valueOf(StringUtils.isNotEmpty(this.config.getUsername()))); javaMailProperties.put(MAIL_PROP + protocol + ".starttls.enable", Boolean.valueOf(this.config.isEnableTls()).toString()); + if (this.config.isEnableTls() && StringUtils.isNoneEmpty(this.config.getTlsVersion())) { + javaMailProperties.put(MAIL_PROP + protocol + ".ssl.protocols", this.config.getTlsVersion()); + } return javaMailProperties; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java index e7982b6590..3150b6d7f3 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mail/TbSendEmailNodeConfiguration.java @@ -29,6 +29,7 @@ public class TbSendEmailNodeConfiguration implements NodeConfiguration { private String smtpProtocol; private int timeout; private boolean enableTls; + private String tlsVersion; @Override public TbSendEmailNodeConfiguration defaultConfiguration() { @@ -39,6 +40,7 @@ public class TbSendEmailNodeConfiguration implements NodeConfiguration { configuration.setSmtpPort(25); configuration.setTimeout(10000); configuration.setEnableTls(false); + configuration.setTlsVersion("TLSv1.2"); return configuration; } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java index 4db628a7f4..be4e6b4e30 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbAbstractGetAttributesNode.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import com.google.gson.JsonParseException; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.BooleanUtils; import org.thingsboard.rule.engine.api.TbContext; @@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.msg.TbMsg; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; @@ -77,7 +79,8 @@ public abstract class TbAbstractGetAttributesNode findEntityIdAsync(TbContext ctx, TbMsg msg); @@ -168,6 +171,12 @@ public abstract class TbAbstractGetAttributesNodeadmin.timeout-invalid - {{ 'admin.enable-tls' | translate }} + + + + + {{tlsVersion}} + + + diff --git a/ui/src/app/locale/locale.constant-cs_CZ.json b/ui/src/app/locale/locale.constant-cs_CZ.json index 8e8a6b8a2f..76311883a8 100644 --- a/ui/src/app/locale/locale.constant-cs_CZ.json +++ b/ui/src/app/locale/locale.constant-cs_CZ.json @@ -83,6 +83,7 @@ "timeout-required": "Hodnota ČasovÜ limit je povinná.", "timeout-invalid": "Tohle nevypadá jako platnÜ časovÜ limit.", "enable-tls": "Povolit TLS", + "tls-version": "Verze TLS", "send-test-mail": "Odeslat testovací zprávu" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-de_DE.json b/ui/src/app/locale/locale.constant-de_DE.json index d5f43f4ef4..57d64c104e 100644 --- a/ui/src/app/locale/locale.constant-de_DE.json +++ b/ui/src/app/locale/locale.constant-de_DE.json @@ -83,6 +83,7 @@ "timeout-required": "Wartezeit ist erforderlich.", "timeout-invalid": "Das ist keine gÃŒltige Wartezeit.", "enable-tls": "TLS aktivieren", + "tls-version" : "TLS-Version", "send-test-mail": "Test E-Mail senden", "security-settings": "Sicherheitseinstellungen", "password-policy": "Kennwortrichtlinie", diff --git a/ui/src/app/locale/locale.constant-el_GR.json b/ui/src/app/locale/locale.constant-el_GR.json index 9b9783a9ad..1817c64509 100644 --- a/ui/src/app/locale/locale.constant-el_GR.json +++ b/ui/src/app/locale/locale.constant-el_GR.json @@ -88,6 +88,7 @@ "timeout-required": "Απαιτείται τιΌή Timeout.", "timeout-invalid": "Αυτή Ύε φαίΜεται Μα είΜαι Όια έγκυρη τιΌή timeout.", "enable-tls": "ΕΜεργοποίηση TLS", + "tls-version": "ΈκΎοση TLS", "send-test-mail": "Αποστολή ΎοκιΌαστικού ΌηΜύΌατος", "use-system-mail-settings": "Χρήση τωΜ ρυΞΌίσεωΜ ΎιακοΌιστή αλληλογραφίας συστήΌατος", "mail-templates": "Πρότυπα αλληλογραφίας", diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 9815b6ba81..5ed4e6bdfa 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -86,6 +86,7 @@ "timeout-required": "Timeout is required.", "timeout-invalid": "That doesn't look like a valid timeout.", "enable-tls": "Enable TLS", + "tls-version": "TLS version", "send-test-mail": "Send test mail", "security-settings": "Security settings", "password-policy": "Password policy", diff --git a/ui/src/app/locale/locale.constant-es_ES.json b/ui/src/app/locale/locale.constant-es_ES.json index 75abc889b3..0473b7df8f 100644 --- a/ui/src/app/locale/locale.constant-es_ES.json +++ b/ui/src/app/locale/locale.constant-es_ES.json @@ -85,6 +85,7 @@ "timeout-required": "Tiempo de espera es requerido.", "timeout-invalid": "Eso no parece un tiempo de espera válido.", "enable-tls": "Habilitar TLS", + "tls-version": "Versión TLS", "send-test-mail": "Enviar correo de prueba", "password-policy": "Política de contraseñas", "security-settings": "Configuraciones de seguridad", diff --git a/ui/src/app/locale/locale.constant-fa_IR.json b/ui/src/app/locale/locale.constant-fa_IR.json index 34eee792b9..4c83a7eea9 100644 --- a/ui/src/app/locale/locale.constant-fa_IR.json +++ b/ui/src/app/locale/locale.constant-fa_IR.json @@ -83,6 +83,7 @@ "timeout-required": ".مهلت مورد نياز است", "timeout-invalid": ".مهلت، ØšÙ‡ ن؞ر نمي آيد معتؚر ؚا؎د", "enable-tls": "TLS فعال سازي", + "tls-version": "نسخه TLS", "send-test-mail": "ارسال ٟيام آزماي؎ي" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-fr_FR.json b/ui/src/app/locale/locale.constant-fr_FR.json index f234afbd88..f155563742 100644 --- a/ui/src/app/locale/locale.constant-fr_FR.json +++ b/ui/src/app/locale/locale.constant-fr_FR.json @@ -1,1734 +1,1735 @@ -{ - "access": { - "access-forbidden": "AccÚs interdit", - "access-forbidden-text": "Vous n'avez pas accÚs à cet emplacement!
Essayez de vous connecter avec un autre utilisateur si vous souhaitez toujours accéder à cet emplacement.", - "refresh-token-expired": "La session a expiré", - "refresh-token-failed": "Impossible de rafraîchir la session", - "unauthorized": "non autorisé", - "unauthorized-access": "accÚs non autorisé", - "unauthorized-access-text": "Vous devez vous connecter pour avoir accÚs à cette ressource!" - }, - "action": { - "activate": "Activer", - "add": "Ajouter", - "apply": "Appliquer", - "apply-changes": "Appliquer les modifications", - "assign": "Attribuer", - "back": "retour", - "cancel": "Annuler", - "clear-search": "Effacer la recherche", - "close": "Fermer", - "continue": "Continue", - "copy": "Copier", - "copy-reference": "Copier la référence", - "create": "Créer", - "decline-changes": "Refuser les modifications", - "delete": "Supprimer", - "discard-changes": "Annuler les modifications", - "drag": "Drag", - "edit": "Modifier", - "edit-mode": "Mode édition", - "enter-edit-mode": "Entrer en mode édition", - "export": "Exporter", - "import": "Importer", - "make-private": "Rendre privé", - "no": "Non", - "ok": "OK", - "paste": "coller", - "paste-reference": "Coller référence", - "refresh": "Rafraîchir", - "remove": "Supprimer", - "run": "Exécuter", - "save": "Enregistrer", - "saveAs": "Enregistrer sous", - "search": "Rechercher", - "share": "Partager", - "share-via": "Partager via {{provider}}", - "sign-in": "Connectez-vous!", - "suspend": "Suspendre", - "unassign": "Retirer", - "undo": "Annuler", - "update": "mise à jour", - "view": "Afficher", - "yes": "Oui" - }, - "admin": { - "base-url": "URL de base", - "base-url-required": "L'URL de base est requise.", - "enable-tls": "Activer TLS", - "general": "Général", - "general-settings": "ParamÚtres généraux", - "mail-from": "Mail de", - "mail-from-required": "Mail de est requis.", - "outgoing-mail": "courrier sortant", - "outgoing-mail-settings": "ParamÚtres de courrier sortant", - "send-test-mail": "Envoyer un mail de test", - "smtp-host": "HÃŽte SMTP", - "smtp-host-required": "L'hÃŽte SMTP est requis.", - "smtp-port": "Port SMTP", - "smtp-port-invalid": "Cela ne ressemble pas à un port smtp valide.", - "smtp-port-required": "Vous devez fournir un port smtp.", - "smtp-protocol": "Protocole SMTP", - "system-settings": "ParamÚtres systÚme", - "test-mail-sent": "Le courrier de test a été envoyé avec succés!", - "timeout-invalid": "Cela ne ressemble pas à un délai d'expiration valide.", - "timeout-msec": "Délai (msec)", - "timeout-required": "Le délai est requis.", - "security-settings": "Les paramÚtres de sécurité", - "password-policy": "Politique de mot de passe", - "minimum-password-length": "Longueur minimale du mot de passe", - "minimum-password-length-required": "La longueur minimale du mot de passe est requise", - "minimum-password-length-range": "La longueur minimale du mot de passe doit être comprise entre 5 et 50.", - "minimum-uppercase-letters": "Nombre minimum de lettres majuscules", - "minimum-uppercase-letters-range": "Le nombre minimum de lettres majuscules ne peut pas être négatif", - "minimum-lowercase-letters": "Nombre minimum de lettres minuscules", - "minimum-lowercase-letters-range": "Le nombre minimum de lettres minuscules ne peut pas être négatif", - "minimum-digits": "Nombre minimum de chiffres", - "minimum-digits-range": "Le nombre minimum de chiffres ne peut pas être négatif", - "minimum-special-characters": "Nombre minimum de caractÚres spéciaux", - "minimum-special-characters-range": "Le nombre minimum de caractÚres spéciaux ne peut pas être négatif", - "password-expiration-period-days": "Délai d'expiration du mot de passe en jours", - "password-expiration-period-days-range": "La période d'expiration du mot de passe en jours ne peut pas être négative", - "password-reuse-frequency-days": "Fréquence de réutilisation du mot de passe en jours", - "password-reuse-frequency-days-range": "La fréquence de réutilisation du mot de passe en jours ne peut être négative", - "general-policy": "Politique générale", - "max-failed-login-attempts": "Nombre maximal de tentatives de connexion infructueuses avant que le compte ne soit verrouillé", - "minimum-max-failed-login-attempts-range": "Le nombre maximal de tentatives de connexion ayant échoué ne peut pas être négatif", - "user-lockout-notification-email": "En cas de verrouillage du compte d'utilisateur, envoyez une notification par courrier électronique." - }, - "aggregation": { - "aggregation": "agrégation", - "avg": "Moyenne", - "count": "Compte", - "function": "Fonction d'agrégation de données", - "group-interval": "Intervalle de regroupement", - "limit": "Valeurs maximales", - "max": "Max", - "min": "Min", - "none": "Aucune", - "sum": "Somme" - }, - "alarm": { - "ack-time": "Heure d'acquittement", - "acknowledge": "Acquitter", - "aknowledge-alarm-text": "Êtes-vous sûr de vouloir reconnaître l'alarme?", - "aknowledge-alarm-title": "Reconnaître l'alarme", - "aknowledge-alarms-text": "Êtes-vous sûr de vouloir acquitter {count, plural, 1 {1 alarme} other {# alarmes}}?", - "aknowledge-alarms-title": "Acquitter {count, plural, 1 {1 alarme} other {# alarmes}}", - "alarm": "Alarme", - "alarm-details": "Détails de l'alarme", - "alarm-required": "Une alarme est requise", - "alarm-status": "État d'alarme", - "alarm-status-filter": "Filtre d'état d'alarme", - "alarms": "Alarmes", - "clear": "Effacer", - "clear-alarm-text": "Êtes-vous sûr de vouloir effacer l'alarme?", - "clear-alarm-title": "Effacer l'alarme", - "clear-alarms-text": "Êtes-vous sûr de vouloir effacer {count, plural, 1 {1 alarme} other {# alarmes}}?", - "clear-alarms-title": "Effacer {count, plural, 1 {1 alarme} other {# alarmes}}", - "clear-time": "Heure d'éffacement", - "created-time": "Heure de création", - "details": "Détails", - "display-status": { - "ACTIVE_ACK": "Active acquittée", - "ACTIVE_UNACK": "Active non acquittée", - "CLEARED_ACK": "effacée acquittée", - "CLEARED_UNACK": "effacée non acquittée" - }, - "end-time": "Heure de fin", - "min-polling-interval-message": "Un intervalle d'interrogation d'au moins 1 seconde est autorisé.", - "no-alarms-matching": "Aucune alarme correspondant à {{entity}} n'a été trouvée. ", - "no-alarms-prompt": "Aucune alarme", - "no-data": "Aucune donnée à afficher", - "originator": "Source", - "originator-type": "Type de Source", - "polling-interval": "Intervalle d'interrogation des alarmes (sec)", - "polling-interval-required": "L'intervalle d'interrogation des alarmes est requis.", - "search": "Rechercher des alarmes", - "search-status": { - "ACK": "acquitté", - "ACTIVE": "active", - "ANY": "Toutes", - "CLEARED": "effacée", - "UNACK": "non acquittée" - }, - "select-alarm": "Sélectionnez une alarme", - "selected-alarms": "{count, plural, 1 {1 alarme} other {# alarmes}} sélectionnées", - "severity": "Gravité", - "severity-critical": "Critique", - "severity-indeterminate": "indéterminée", - "severity-major": "Majeure", - "severity-minor": "mineure", - "severity-warning": "Avertissement", - "start-time": "Heure de début", - "status": "État", - "type": "Type" - }, - "alias": { - "add": "Ajouter un alias", - "all-entities": "Toutes les entités", - "any-relation": "toutes", - "default-entity-parameter-name": "Par défaut", - "default-state-entity": "Entité d'état par défaut", - "duplicate-alias": "Un alias portant le même nom existe déjà.", - "edit": "Modifier l'alias", - "entity-filter": "Filtre d'entité", - "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.", - "filter-type": "Type de filtre", - "filter-type-asset-search-query": "requête de recherche d'actifs", - "filter-type-asset-search-query-description": "Actifs de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-asset-type": "type d'actif", - "filter-type-asset-type-and-name-description": "Actifs de type '{{assetType}}' et dont le nom commence par '{{prefix}}'", - "filter-type-asset-type-description": "Actifs de type '{{assetType}}'", - "filter-type-device-search-query": "Requête de recherche de dispositif", - "filter-type-device-search-query-description": "Dispositifs de types {{deviceTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-device-type": "Type de dispositif", - "filter-type-device-type-and-name-description": "Dispositifs de type '{{deviceType}}' et dont le nom commence par '{{prefix}}'", - "filter-type-device-type-description": "Dispositifs de type '{{deviceType}}'", - "filter-type-entity-list": "Liste d'entités", - "filter-type-entity-name": "Nom d'entité", - "filter-type-entity-view-search-query": "Requête de recherche vue d'entité", - "filter-type-entity-view-search-query-description": "Vues d'entité avec les types {{entityViewTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-entity-view-type": "Type de vue d'entité", - "filter-type-entity-view-type-and-name-description": "Vues d'entité de type '{{entityView}}' et dont le nom commence par '{{prefix}}'", - "filter-type-entity-view-type-description": "Vues d'entité de type '{{entityView}}'", - "filter-type-relations-query": "Interrogation des relations", - "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-required": "Le type de filtre est requis.", - "filter-type-single-entity": "Entité unique", - "filter-type-state-entity": "Entité de l'état du tableau de bord", - "filter-type-state-entity-description": "Entité extraite des paramétres d'état du tableau de bord", - "max-relation-level": "Niveau de relation maximum", - "name": "Nom de l'alias", - "name-required": "Le nom d'alias est requis", - "no-entity-filter-specified": "Aucun filtre d'entité spécifié", - "resolve-multiple": "Résoudre en plusieurs entités", - "root-entity": "Entité racine", - "root-state-entity": "Utiliser l'entité d'état du tableau de bord en tant que racine", - "state-entity": "Entité d'état du tableau de bord", - "state-entity-parameter-name": "Nom du paramétre d'entité d'état", - "unlimited-level": "niveau illimité" - }, - "asset": { - "add": "Ajouter un actif", - "add-asset-text": "Ajouter un nouvel actif", - "any-asset": "Tout actif", - "asset": "Actif", - "asset-details": "Détails de l'actif", - "asset-file": "Actif file", - "asset-public": "L'actif est public", - "asset-required": "Actif requis", - "asset-type": "Type d'actif", - "asset-type-list-empty": "Aucun type d'actif sélectionné.", - "asset-type-required": "Le type d'actif est requis.", - "asset-types": "Types d'actif", - "assets": "Actifs", - "assign-asset-to-customer": "Attribuer des actifs au client", - "assign-asset-to-customer-text": "Veuillez sélectionner les actifs à attribuer au client", - "assign-assets": "Attribuer des actifs", - "assign-assets-text": "Attribuer {count, plural, 1 {1 asset} other {# assets}} au client", - "assign-new-asset": "Attribuer un nouvel Asset", - "assign-to-customer": "Attribuer au client", - "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les actifs", - "assignedToCustomer": "attribué au client", - "copyId": "Copier l'Id de l'actif", - "delete": "Supprimer un actif", - "delete-asset-text": "Faites attention, aprÚs la confirmation, l'actif et toutes les données associées deviendront irrécupérables.", - "delete-asset-title": "Êtes-vous sûr de vouloir supprimer l'actif '{{assetName}}'?", - "delete-assets": "Supprimer des actifs", - "delete-assets-action-title": "Supprimer {count, plural, 1 {1 asset} other {# assets}}", - "delete-assets-text": "Attention, aprÚs la confirmation, tous les actifs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-assets-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 asset} other {# assets}}?", - "description": "Description", - "details": "Détails", - "enter-asset-type": "Entrez le type d'actif", - "events": "Evénements", - "idCopiedMessage": "L'Id d'asset a été copié dans le presse-papier", - "import": "Import actifs", - "make-private": "Rendre l'actif privé", - "make-private-asset-text": "AprÚs la confirmation, l'actif et toutes ses données seront rendus privés et ne seront pas accessibles par d'autres.", - "make-private-asset-title": "Êtes-vous sûr de vouloir rendre l'actif '{{assetName}}' privé '?", - "make-public": "Rendre l'actif public", - "make-public-asset-text": "AprÚs la confirmation, l'asset et toutes ses données seront rendus publics et accessibles aux autres.", - "make-public-asset-title": "Êtes-vous sûr de vouloir rendre l'actif '{{assetName}}' public '?", - "management": "Gestion d'actifs", - "name": "Nom", - "name-required": "Nom est requis.", - "name-starts-with": "Le nom de l'actif commence par", - "no-asset-types-matching": "Aucun type d'actif correspondant à {{entitySubtype}} n'a été trouvé. ", - "no-assets-matching": "Aucun actif correspondant à {{entity}} n'a été trouvé. ", - "no-assets-text": "Aucun actif trouvé", - "public": "Public", - "select-asset": "Sélectionner un actif", - "select-asset-type": "Sélectionner le type d'actif", - "type": "Type", - "type-required": "Le type est requis.", - "unassign-asset": "Retirer l'actif", - "unassign-asset-text": "AprÚs la confirmation, l'actif sera non attribué et ne sera pas accessible au client.", - "unassign-asset-title": "Êtes-vous sûr de vouloir retirer l'attribution de l'actif '{{assetName}}'?", - "unassign-assets": "Retirer les actifs", - "unassign-assets-action-title": "Retirer {count, plural, 1 {1 asset} other {# assets}} du client", - "unassign-assets-text": "AprÚs la confirmation, tous les actifs sélectionnés ne seront pas attribués et ne seront pas accessibles au client.", - "unassign-assets-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 asset} other {# assets}}?", - "unassign-from-customer": "Retirer du client", - "view-assets": "Afficher les actifs", - "label": "Label" - }, - "attribute": { - "add": "Ajouter un attribut", - "add-to-dashboard": "Ajouter au tableau de bord", - "add-widget-to-dashboard": "Ajouter un widget au tableau de bord", - "attributes": "Attributs", - "attributes-scope": "Étendue des attributs d'entité", - "delete-attributes": "Supprimer les attributs", - "delete-attributes-text": "Attention, aprÚs la confirmation, tous les attributs sélectionnés seront supprimés.", - "delete-attributes-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 attribut} other {# attributs}}?", - "enter-attribute-value": "Entrez la valeur de l'attribut", - "key": "Clé", - "key-required": "La Clé d'attribut est requise.", - "last-update-time": "DerniÚre mise à jour", - "latest-telemetry": "DerniÚre télémétrie", - "next-widget": "Widget suivant", - "prev-widget": "Widget précédent", - "scope-client": "Attributs du client", - "scope-latest-telemetry": "DerniÚre télémétrie", - "scope-server": "Attributs du serveur", - "scope-shared": "Attributs partagés", - "selected-attributes": "{count, plural, 1 {1 attribut} other {# attributs}} sélectionnés", - "selected-telemetry": "{count, plural, 1 {1 unité de télémétrie} other {# unités de télémétrie}} sélectionnées", - "show-on-widget": "Afficher sur le widget", - "value": "Valeur", - "value-required": "La valeur d'attribut est obligatoire.", - "widget-mode": "Mode du widget" - }, - "audit-log": { - "action-data": "Action data", - "audit": "Audit", - "audit-log-details": "Détails du journal d'audit", - "audit-logs": "Journaux d'audit", - "clear-search": "Effacer la recherche", - "details": "Détails", - "entity-name": "Nom de l'entité", - "entity-type": "Type d'entité", - "failure-details": "Détails de l'échec", - "no-audit-logs-prompt": "Aucun journal trouvé", - "search": "Rechercher les journaux d'audit", - "status": "État", - "status-failure": "Échec", - "status-success": "SuccÚs", - "timestamp": "Horodatage", - "type": "Type", - "type-activated": "Activé", - "type-added": "Ajouté", - "type-alarm-ack": "Acquitté", - "type-alarm-clear": "Effacé", - "type-assigned-to-customer": "Attribué au client", - "type-attributes-deleted": "Attributs supprimés", - "type-attributes-read": "Attributs lus", - "type-attributes-updated": "Attributs mis à jour", - "type-credentials-read": "Lecture des informations d'identification", - "type-credentials-updated": "Informations d'identification actualisées", - "type-deleted": "Supprimé", - "type-login": "Login", - "type-logout": "Connectez - Out", - "type-lockout": "Verrouillage", - "type-relation-add-or-update": "Relation mise à jour", - "type-relation-delete": "Relation supprimée", - "type-relations-delete": "Toutes les relations ont été supprimées", - "type-rpc-call": "Appel RPC", - "type-suspended": "Suspendu", - "type-unassigned-from-customer": "Non attribué du client", - "type-updated": "Mise à jour", - "user": "Utilisateur" - }, - "common": { - "enter-password": "Entrez le mot de passe", - "enter-search": "Entrez la recherche", - "enter-username": "Entrez le nom d'utilisateur", - "password": "Mot de passe", - "username": "Nom d'utilisateur" - }, - "confirm-on-exit": { - "html-message": "Vous avez des modifications non enregistrées.
Êtes-vous sûr de vouloir quitter cette page?", - "message": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter cette page?", - "title": "Modifications non enregistrées" - }, - "contact": { - "address": "Adresse", - "address2": "adresse 2", - "city": "Ville", - "country": "Pays", - "email": "Email", - "no-address": "Pas d'adresse", - "phone": "Téléphone", - "postal-code": "Code postal", - "postal-code-invalid": "Format de code postal / code postal invalide", - "state": "Province" - }, - "content-type": { - "binary": "Binaire (Base64)", - "json": "Json", - "text": "Texte" - }, - "custom": { - "widget-action": { - "action-cell-button": "Bouton de cellule d'action", - "marker-click": "Sur le marqueur cliquez", - "row-click": "Au rang, cliquez", - "polygon-click": "Cliquez sur le polygone", - "tooltip-tag-action": "Action de balise d'info-bulle", - "node-selected": "Sur le noeud sélectionné", - "element-click": "Sur l'élément HTML, cliquez sur", - "pie-slice-click": "Sur tranche cliquez", - "row-double-click": "Sur la ligne double clic" - } - }, - "customer": { - "add": "Ajouter un client", - "add-customer-text": "Ajouter un nouveau client", - "assets": "Actifs du client", - "copyId": "Copier l'id du client", - "customer": "Client", - "customer-details": "Détails du client", - "customer-required": "Le client est requis", - "customers": "Clients", - "dashboard": "Tableau de bord du client", - "dashboards": "tableaux de bord du client", - "default-customer": "Client par défaut", - "default-customer-required": "Le client par défaut est requis pour déboguer le tableau de bord au niveau du Tenant", - "delete": "Supprimer le client", - "delete-customer-text": "Faites attention, aprÚs la confirmation, le client et toutes les données associées deviendront irrécupérables.", - "delete-customer-title": "Êtes-vous sûr de vouloir supprimer le client '{{customerTitle}}'?", - "delete-customers-action-title": "Supprimer {count, plural, 1 {1 customer} other {# customers}}", - "delete-customers-text": "Faites attention, aprÚs la confirmation, tous les clients sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-customers-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 customer} other {# customers}}?", - "description": "Description", - "details": "Détails", - "devices": "Dispositifs du client", - "entity-views": "Vues de l'entité client", - "events": "Événements", - "idCopiedMessage": "L'Id du client a été copié dans le presse-papier", - "manage-assets": "Gérer les actifs", - "manage-customer-assets": "Gérer les actifs du client", - "manage-customer-dashboards": "Gérer les tableaux de bord du client", - "manage-customer-devices": "Gérer les dispositifs du client", - "manage-customer-users": "Gérer les utilisateurs du client", - "manage-dashboards": "Gérer les tableaux de bord", - "manage-devices": "Gérer les dispositifs", - "manage-public-assets": "Gérer les actifs publics", - "manage-public-dashboards": "Gérer les tableaux de bord publics", - "manage-public-devices": "Gérer les dispositifs publics", - "manage-users": "Gérer les utilisateurs", - "management": "Gestion des clients", - "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.", - "no-customers-text": "Aucun client trouvé", - "public-assets": "Actifs publics", - "public-dashboards": "Tableaux de bord publics", - "public-devices": "Dispositifs publics", - "public-entity-views": "Vues d'entités publiques", - "select-customer": "Sélectionner un client", - "select-default-customer": "Sélectionnez le client par défaut", - "title": "Titre", - "title-required": "Le titre est requis." - }, - "dashboard": { - "add": "Ajouter un tableau de bord", - "add-dashboard-text": "Ajouter un nouveau tableau de bord", - "add-state": "Ajouter un état du tableau de bord", - "add-widget": "Ajouter un nouveau widget", - "alias-resolution-error-title": "Erreur de configuration des alias de tableau de bord", - "assign-dashboard-to-customer": "Attribuer des tableaux de bord au client", - "assign-dashboard-to-customer-text": "Veuillez sélectionner les tableaux de bord à affecter au client", - "assign-dashboards": "Attribuer des tableaux de bord", - "assign-dashboards-text": "Attribuer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} aux clients", - "assign-new-dashboard": "Attribuer un nouveau tableau de bord", - "assign-to-customer": "Attribuer au client", - "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les tableaux de bord", - "assign-to-customers": "Attribuer des tableaux de bord aux clients", - "assign-to-customers-text": "Veuillez sélectionner les clients pour attribuer les tableaux de bord", - "assigned-customers": "clients affectés", - "assignedToCustomer": "Attribué au client", - "assignedToCustomers": "attribué aux clients", - "autofill-height": "Hauteur de remplissage automatique", - "background-color": "Couleur de fond", - "background-image": "Image d'arriére-plan", - "background-size-mode": "Mode de taille d'arriére-plan", - "close-toolbar": "Fermer la barre d'outils", - "columns-count": "Nombre de colonnes", - "columns-count-required": "Le nombre de colonnes est requis.", - "configuration-error": "Erreur de configuration", - "copy-public-link": "Copier le lien public", - "create-new": "Créer un nouveau tableau de bord", - "create-new-dashboard": "Créer un nouveau tableau de bord", - "create-new-widget": "Créer un nouveau widget", - "dashboard": "Tableau de bord", - "dashboard-details": "Détails du tableau de bord", - "dashboard-file": "Fichier du tableau de bord", - "dashboard-import-missing-aliases-title": "Configurer les alias utilisés par le tableau de bord importé", - "dashboard-required": "Le tableau de bord est requis.", - "dashboards": "Tableaux de bord", - "delete": "Supprimer le tableau de bord", - "delete-dashboard-text": "Faites attention, aprÚs la confirmation, le tableau de bord et toutes les données associées deviendront irrécupérables.", - "delete-dashboard-title": "Êtes-vous sûr de vouloir supprimer le tableau de bord '{{dashboardTitle}}'?", - "delete-dashboards": "Supprimer les tableaux de bord", - "delete-dashboards-action-title": "Supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}", - "delete-dashboards-text": "Attention, aprÚs la confirmation, tous les tableaux de bord sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-dashboards-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?", - "delete-state": "Supprimer l'état du tableau de bord", - "delete-state-text": "Etes-vous sûr de vouloir supprimer l'état du tableau de bord avec le nom '{{stateName}}'?", - "delete-state-title": "Supprimer l'état du tableau de bord", - "description": "Description", - "details": "Détails", - "display-dashboard-export": "Afficher l'exportation", - "display-dashboard-timewindow": "Afficher fenêtre de temps", - "display-dashboards-selection": "Afficher la sélection des tableaux de bord", - "display-entities-selection": "Afficher la sélection des entités", - "display-title": "Afficher le titre du tableau de bord", - "drop-image": "Déposer une image ou cliquez pour sélectionner un fichier à télécharger.", - "edit-state": "Modifier l'état du tableau de bord", - "export": "Exporter le tableau de bord", - "export-failed-error": "Impossible d'exporter le tableau de bord: {{error}}", - "hide-details": "Masquer les détails", - "horizontal-margin": "Marge horizontale", - "horizontal-margin-required": "Une valeur de marge horizontale est requise.", - "import": "Importer le tableau de bord", - "import-widget": "Importer un widget", - "invalid-aliases-config": "Impossible de trouver des dispositifs correspondant à certains filtres d'alias.
Veuillez contacter votre administrateur pour résoudre ce problÚme.", - "invalid-dashboard-file-error": "Impossible d'importer le tableau de bord: structure de données du tableau de bord non valide", - "invalid-widget-file-error": "Impossible d'importer le widget: structure de données de widget invalide.", - "is-root-state": "État racine", - "make-private": "Rendre privé le tableau de bord", - "make-private-dashboard": "Rendre privé le tableau de bord", - "make-private-dashboard-text": "AprÚs la confirmation, le tableau de bord sera rendu privé et ne sera plus accessible aux autres.", - "make-private-dashboard-title": "Êtes-vous sûr de vouloir rendre le tableau de bord '{{dashboardTitle}}' privé?", - "make-public": "Rendre public le tableau de bord", - "manage-assigned-customers": "Gérer les clients affectés", - "manage-states": "Gérer les états du tableau de bord", - "management": "Gestion du tableau de bord", - "max-columns-count-message": "Seulement 1000 colonnes maximum sont autorisées.", - "max-horizontal-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge horizontale maximale.", - "max-mobile-row-height-message": "Seuls 200 pixels sont autorisés en tant que valeur maximale de hauteur de ligne mobile.", - "max-vertical-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge verticale maximale.", - "min-columns-count-message": "Seul un nombre minimum de 10 colonnes est autorisé.", - "min-horizontal-margin-message": "Seul 0 est autorisé comme valeur de marge horizontale minimale.", - "min-mobile-row-height-message": "Seuls 5 pixels sont autorisés en tant que valeur minimale de hauteur de ligne mobile.", - "min-vertical-margin-message": "Seul 0 est autorisé comme valeur de marge verticale minimale.", - "mobile-layout": "ParamÚtres de mise en page mobiles", - "mobile-row-height": "Hauteur de ligne mobile, px", - "mobile-row-height-required": "Une valeur de hauteur de ligne mobile est requise.", - "new-dashboard-title": "Nouveau titre du tableau de bord", - "no-dashboards-matching": "Aucun tableau de bord correspondant à {{entity}} n'a été trouvé. ", - "no-dashboards-text": "Aucun tableau de bord trouvé", - "no-image": "Aucune image sélectionnée", - "no-widgets": "Aucun widget configuré", - "open-dashboard": "Ouvrir le tableau de bord", - "open-toolbar": "Ouvrir la barre d'outils du tableau de bord", - "public": "Public", - "public-dashboard-notice": " Remarque: N'oubliez pas de rendre publics les dispositifs associés pour accéder à leurs données.", - "public-dashboard-text": "Votre tableau de bord {{dashboardTitle}} est maintenant public et accessible via le lien public : ", - "public-dashboard-title": "Le tableau de bord est maintenant public", - "public-link": "Lien public", - "public-link-copied-message": "Le lien public du tableau de bord a été copié dans le presse-papier", - "search-states": "Recherche des états du tableau de bord", - "select-dashboard": "Sélectionner le tableau de bord", - "select-devices": "Selectionner les dispositifs", - "select-existing": "Sélectionnez un tableau de bord existant", - "select-state": "Sélectionnez l'état cible", - "select-widget-subtitle": "Liste des types de widgets disponibles", - "select-widget-title": "Sélectionner un widget", - "selected-states": "{count, plural, 1 {1 état du tableau de bord} other {# états du tableau de bord}} sélectionnés", - "set-background": "Définir l'arriÚre-plan", - "settings": "ParamÚtres", - "show-details": "Afficher les détails", - "socialshare-text": "'{{dashboardTitle}}' propulsé par ThingsBoard", - "socialshare-title": "'{{dashboardTitle}}' propulsé par ThingsBoard", - "state": "État du tableau de bord", - "state-controller": "ContrÃŽleur d'état", - "state-id": "ID d'état", - "state-id-exists": "L'état du tableau de bord avec le même Id existe déjà.", - "state-id-required": "L'Id d'état du tableau de bord est requis.", - "state-name": "Nom", - "state-name-required": "Le nom de l'état du tableau de bord est requis", - "states": "États du tableau de bord", - "title": "Titre", - "title-color": "Couleur du titre", - "title-required": "Le titre est requis.", - "toolbar-always-open": "Garder la barre d'outils ouverte", - "unassign-dashboard": "Retirer le tableau de bord", - "unassign-dashboard-text": "AprÚs la confirmation, le tableau de bord ne sera pas attribué et ne sera pas accessible au client.", - "unassign-dashboard-title": "Êtes-vous sûr de vouloir annuler l'affectation du tableau de bord '{{dashboardTitle}}'?", - "unassign-dashboards": "Retirer les tableaux de bord", - "unassign-dashboards-action-text": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} des clients", - "unassign-dashboards-action-title": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} du client", - "unassign-dashboards-text": "AprÚs la confirmation, tous les tableaux de bord sélectionnés ne seront pas attribués et ne seront pas accessibles au client.", - "unassign-dashboards-title": "Etes-vous sûr de vouloir annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?", - "unassign-from-customer": "Retirer du client", - "unassign-from-customers": "Retirer les tableaux de bord des clients", - "unassign-from-customers-text": "Veuillez sélectionner les clients à annuler l'affectation du ou des tableaux de bord", - "vertical-margin": "Marge verticale", - "vertical-margin-required": "Une valeur de marge verticale est requise", - "view-dashboards": "Afficher les tableaux de bord", - "widget-file": "Fichier du Widget", - "widget-import-missing-aliases-title": "Configurer les alias utilisés par le widget importé", - "widgets-margins": "Marge entre les widgets" - }, - "datakey": { - "advanced": "Avancé", - "alarm": "Champs d'alarme", - "alarm-fields-required": "Les champs d'alarme sont obligatoires.", - "attributes": "Attributs", - "color": "Couleur", - "configuration": "Configuration de la clé de données", - "data-generation-func": "Fonction de génération de données", - "decimals": "Nombre de chiffres aprÚs virgule flottante", - "function-types": "Types de fonctions", - "function-types-required": "Les types de fonctions sont obligatoires", - "label": "Label", - "maximum-function-types": "Maximum {count, plural, 1 {1 type de fonction est autorisé.} other {# types de fonctions sont autorisés}}", - "maximum-timeseries-or-attributes": "Maximum {count, plural, 1 {1 timeseries / attribut est autorisé.} other {# timeseries / attributs sont autorisés}}", - "prev-orig-value-description": "valeur précédente d'origine;", - "prev-value-description": "résultat de l'appel de fonction précédent;", - "settings": "ParamÚtres", - "time-description": "horodatage de la valeur actuelle;", - "time-prev-description": "horodatage de la valeur précédente;", - "timeseries": "Timeseries", - "timeseries-or-attributes-required": "Les timeseries / attributs d'entité sont obligatoires.", - "timeseries-required": "Les Timeseries de l'entité sont obligatoires.", - "units": "Symbole spécial à afficher à cÃŽté de la valeur", - "use-data-post-processing-func": "Utiliser la fonction de post-traitement des données", - "value-description": "la valeur actuelle;" - }, - "datasource": { - "add-datasource-prompt": "Veuillez ajouter une source de données", - "name": "Nom", - "type": "Type de source de données" - }, - "datetime": { - "date-from": "Date de", - "date-to": "Date à", - "time-from": "Heure de", - "time-to": "Heure à" - }, - "details": { - "edit-mode": "Mode édition", - "toggle-edit-mode": "Activer le mode édition" - }, - "device": { - "access-token": "Jeton d'accÚs", - "access-token-invalid": "La longueur du jeton d'accÚs doit être comprise entre 1 et 20 caractéres.", - "access-token-required": "Le jeton d'accÚs est requis.", - "accessTokenCopiedMessage": "Le jeton d'accÚs au dispositif a été copié dans le presse-papier", - "add": "Ajouter un dispositif", - "add-alias": "Ajouter un alias de dispositif", - "add-device-text": "Ajouter un nouveau dispositif", - "alias": "Alias", - "alias-required": "Un alias du dispositif est requis.", - "aliases": "Alias des dispositifs", - "any-device": "N'importe quel dispositif", - "assign-device-to-customer": "Affecter des dispositifs au client", - "assign-device-to-customer-text": "Veuillez sélectionner les dispositif à affecter au client", - "assign-devices": "Attribuer des dispositifs", - "assign-devices-text": "Attribuer {count, plural, 1 {1 dispositif} other {# dispositifs}} au client", - "assign-new-device": "Attribuer un nouveau dispositif", - "assign-to-customer": "Attribuer au client", - "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les dispositifs", - "assignedToCustomer": "Attribué au client", - "configure-alias": "Configurer '{{alias}}' alias", - "copyAccessToken": "Copier le jeton d'accÚs", - "copyId": "Copier l'Id du dispositif", - "create-new-alias": "Créez un nouveau!", - "create-new-key": "Créez un nouveau!", - "credentials": "Informations d'identification", - "credentials-type": "Type d'identification", - "delete": "Supprimer le dispositif", - "delete-device-text": "Faites attention, aprÚs la confirmation, le dispositif et toutes les données associées deviendront irrécupérables.", - "delete-device-title": "Êtes-vous sûr de vouloir supprimer le dispositif '{{deviceName}}'?", - "delete-devices": "Supprimer les dispositifs", - "delete-devices-action-title": "Supprimer {count, plural, 1 {1 device} other {# devices}}", - "delete-devices-text": "Faites attention, aprÚs la confirmation, tous les dispositifs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-devices-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 device} other {# devices}}?", - "description": "Description", - "details": "Détails", - "device": "Dispositif", - "device-alias": "Alias ​​du dispositif", - "device-credentials": "Informations d'identification du dispositif", - "device-details": "Détails du dispositif", - "device-list": "Liste des dispositifs", - "device-list-empty": "Aucun dispositif sélectionné.", - "device-name-filter-no-device-matched": "Aucun dispositif commençant par '{{device}} n'a été trouvé.", - "device-name-filter-required": "Le filtre de nom de dispositif est requis.", - "device-public": "Le dispositif est public", - "device-required": "Le dispositif est requis.", - "device-type": "Type de dispositif", - "device-type-list-empty": "Aucun type de dispositif sélectionné.", - "device-type-required": "Le type de dispositif est requis.", - "device-types": "Types de dispositif", - "devices": "Dispositifs", - "duplicate-alias-error": "Alias ??en double trouvé '{{alias}}'.
Les alias de dispositifs doivent être uniques dans le tableau de bord.", - "enter-device-type": "Entrez le type de dispositif", - "events": "Événements", - "idCopiedMessage": "l'Id du dispositif a été copié dans le presse-papiers", - "is-gateway": "Est une passerelle", - "label": "Label", - "make-private": "Rendre le dispositif privé", - "make-private-device-text": "AprÚs la confirmation, le dispositif et toutes ses données seront rendues privées et ne seront pas accessibles par d'autres.", - "make-private-device-title": "Êtes-vous sûr de vouloir rendre le dispositif {{deviceName}} privé?", - "make-public": "Rendre le dispositif public", - "make-public-device-text": "AprÚs la confirmation, le dispositif et toutes ses données seront rendus publics et accessibles par d'autres.", - "make-public-device-title": "Êtes-vous sûr de vouloir rendre le dispositif {{deviceName}} 'public?", - "manage-credentials": "Gérer les informations d'identification", - "management": "Gestion des dispositifs", - "name": "Nom", - "name-required": "Le nom est requis.", - "name-starts-with": "Le nom du dispositif commence par", - "no-alias-matching": "'{{alias}}' introuvable.", - "no-aliases-found": "Aucun alias trouvé.", - "no-device-types-matching": "Aucun type de dispositif correspondant à {{entitySubtype}} n'a été trouvé.", - "no-devices-matching": "Aucun dispositif correspondant à '{{entity}} n'a été trouvé.", - "no-devices-text": "Aucun dispositif trouvé", - "no-key-matching": "'{{key}}' introuvable.", - "no-keys-found": "Aucune clé trouvée", - "public": "Public", - "remove-alias": "Supprimer l'alias du dispositif", - "rsa-key": "Clé publique RSA", - "rsa-key-required": "La clé publique RSA est requise.", - "secret": "Secret", - "secret-required": "Code secret est requis.", - "select-device": "Selectionner un dispositif", - "select-device-type": "Sélectionner le type d'appareil", - "unable-delete-device-alias-text": "L'alias du dispositif '{{deviceAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", - "unable-delete-device-alias-title": "Impossible de supprimer l'alias du dispositif", - "unassign-device": "Annuler l'affectation du dispositif", - "unassign-device-text": "AprÚs la confirmation, le dispositif ne sera pas attribué et ne sera pas accessible au client.", - "unassign-device-title": "Êtes-vous sûr de vouloir annuler l'affection du dispositif {{deviceName}} '?", - "unassign-devices": "Annuler l'affectation des dispositifs", - "unassign-devices-action-title": "Annuler l'affectation de {count, plural, 1 {1 device} other {#devices}} du client", - "unassign-devices-text": "AprÚs la confirmation, tous les dispositifs sélectionnés ne seront pas attribues et ne seront pas accessibles par le client.", - "unassign-devices-title": "Voulez-vous vraiment annuler l'affectation de {count, plural, 1 {1 device} other {# devices}}?", - "unassign-from-customer": "Retirer du client", - "use-device-name-filter": "Utiliser le filtre", - "view-credentials": "Afficher les informations d'identification", - "view-devices": "Afficher les dispositifs" - }, - "dialog": { - "close": "Fermer le dialogue" - }, - "entity": { - "add-alias": "Ajouter un alias d'entité", - "alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'", - "alias": "Alias", - "alias-required": "Un alias d'entité est requis.", - "aliases": "alias d'entité", - "all-subtypes": "Tout", - "any-entity": "Toute entité", - "asset-name-starts-with": "Les Assets dont le nom commence par '{{prefix}}'", - "columns-to-display": "Colonnes à afficher", - "configure-alias": "Configurer '{{alias}}' alias", - "create-new-alias": "Créez un nouveau!", - "create-new-key": "Créez un nouveau!", - "customer-name-starts-with": "Les clients dont les noms commencent par '{{prefix}}'", - "dashboard-name-starts-with": "Les tableaux de bord dont les noms commencent par '{{prefix}}'", - "details": "Détails de l'entité", - "device-name-starts-with": "Dispositifs dont le nom commence par '{{prefix}}'", - "duplicate-alias-error": "Alias ​​en double trouvé '{{alias}}'.
Les alias d'entité doivent être uniques dans le tableau de bord.", - "enter-entity-type": "Entrez le type d'entité", - "entities": "Entités", - "entity": "Entité", - "entity-alias": "Alias de l'entité", - "entity-list": "Liste d'entités", - "entity-list-empty": "Aucune entité sélectionnée.", - "entity-name": "Nom de l'entité", - "entity-name-filter-no-entity-matched": "Aucune entité commençant par '{{entity}}' n'a été trouvée.", - "entity-name-filter-required": "Le filtre de nom d'entité est requis.", - "entity-type": "Type d'entité", - "entity-type-list": "Liste de types d'entités", - "entity-type-list-empty": "Aucun type d'entité sélectionné.", - "entity-types": "Types d'entité", - "entity-view-name-starts-with": "Les vues d'entité dont le nom commence par '{{prefix}}'", - "key": "Clé", - "key-name": "Nom de la clé", - "list-of-alarms": "{count, plural, 1 {Une alarme} other {Liste de # alarmes}}", - "list-of-assets": "{count, plural, 1 {Un Asset} other {Liste de # Assets}}", - "list-of-customers": "{count, plural, 1 {Un client} other {Liste de # clients}}", - "list-of-dashboards": "{count, plural, 1 {Un tableau de bord} other {Liste de # tableaux de bord}}", - "list-of-devices": "{count, plural, 1 {Un dispositif} other {Liste de # dispositifs}}", - "list-of-plugins": "{count, plural, 1 {Un plugin} other {Liste de # plugins}}", - "list-of-rulechains": "{count, plural, 1 {Une chaîne de rÚgles} other {Liste de # chaînes de rÚgles}}", - "list-of-rulenodes": "{count, plural, 1 {Un noeud de rÚgles} other {Liste de # noeuds de rÚgles}}", - "list-of-rules": "{count, plural, 1 {Une rÚgle} other {Liste de # rÚgles}}", - "list-of-tenants": "{count, plural, 1 {Un tenant} other {Liste de # tenants}}", - "list-of-users": "{count, plural, 1 {Un utilisateur} other {Liste de # utilisateurs}}", - "missing-entity-filter-error": "Le filtre est manquant pour l'alias '{{alias}}'.", - "name-starts-with": "Nom commence par", - "no-alias-matching": "'{{alias}}' introuvable.", - "no-aliases-found": "Aucun alias trouvé.", - "no-data": "Aucune donnée à afficher", - "no-entities-matching": "Aucune entité correspondant à '{{entity}}' n'a été trouvée.", - "no-entities-prompt": "Aucune entité trouvée", - "no-entity-types-matching": "Aucun type d'entité correspondant à {{entityType}} n'a été trouvé. ", - "no-key-matching": "'{{key}}' introuvable.", - "no-keys-found": "Aucune clé trouvée", - "plugin-name-starts-with": "Plugins dont les noms commencent par '{{prefix}}'", - "remove-alias": "Supprimer l'alias d'entité", - "rule-name-starts-with": "Régles dont les noms commencent par '{{prefix}}'", - "rulechain-name-starts-with": "Chaînes de régles dont les noms commencent par '{{prefix}}'", - "rulenode-name-starts-with": "Les noeuds de régles dont le nom commence par '{{prefix}}'", - "search": "Recherche d'entités", - "select-entities": "Sélectionner des entités", - "selected-entities": "{count, plural, 1 {1 entité} other {# entités}} sélectionnées", - "tenant-name-starts-with": "Les Tenant dont le nom commence par '{{prefix}}'", - "type": "Type", - "type-alarm": "Alarme", - "type-alarms": "Alarmes", - "type-asset": "Actif", - "type-assets": "Actifs", - "type-current-customer": "Client actuel", - "type-customer": "Client", - "type-customers": "Clients", - "type-dashboard": "Tableau de bord", - "type-dashboards": "Tableaux de bord", - "type-device": "Dispositif", - "type-devices": "Dispositifs", - "type-entity-view": "Vue d'entité", - "type-entity-views": "Vues d'entités", - "type-plugin": "Plugin", - "type-plugins": "Plugins", - "type-required": "Le type d'entité est obligatoire.", - "type-rule": "Régle", - "type-rulechain": "Chaîne de régles", - "type-rulechains": "Chaînes de régles", - "type-rulenode": "Noeud de régle", - "type-rulenodes": "Noeuds de régle", - "type-rules": "Régles", - "type-tenant": "Tenant", - "type-tenants": "Tenants", - "type-user": "Utilisateur", - "type-users": "Utilisateurs", - "unable-delete-entity-alias-text": "L'alias d'entité '{{entityAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", - "unable-delete-entity-alias-title": "Impossible de supprimer l'alias d'entité", - "use-entity-name-filter": "Utiliser un filtre", - "user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'" - }, - "entity-field": { - "address": "Adresse", - "address2": "Adresse 2", - "city": "Ville", - "country": "Pays", - "created-time": "Heure de création", - "email": "Email", - "first-name": "Prénom", - "last-name": "Nom de famille", - "name": "Nom", - "phone": "Téléphone", - "state": "Prov", - "title": "Titre", - "type": "Type", - "zip": "Code postal" - }, - "entity-view": { - "add": "Ajouter une vue d'entité", - "add-alias": "Ajouter un alias de vue d'entité", - "add-entity-view-text": "Ajouter une nouvelle vue d'entité", - "alias": "Alias", - "alias-required": "Un alias de vue d'entité est requis.", - "aliases": "Alias de vue d'entité", - "any-entity-view": "Toute vue d'entité", - "assign-entity-view-to-customer": "Attribuer une (des) vue (s) d'entité à un client", - "assign-entity-view-to-customer-text": "Veuillez sélectionner les vues d'entité à affecter au client", - "assign-entity-views": "Attribuer des vues d'entité", - "assign-entity-views-text": "Attribuer { count, plural, 1 {1 entityView} other {# entityViews} } au client", - "assign-new-entity-view": "Attribuer une nouvelle vue d'entité", - "assign-to-customer": "Attribuer au client", - "assign-to-customer-text": "Veuillez sélectionner le client auquel attribuer la ou les vues d'entité.", - "assignedToCustomer": "Assigné au client", - "attributes-propagation": "Propagation des attributs", - "attributes-propagation-hint": "La vue d'entité copiera automatiquement les attributs spécifiés de l'entité cible chaque fois que vous enregistrez ou mettez à jour cette vue d'entité. Pour des raisons de performances, les attributs d'entité cible ne sont pas propagés à la vue d'entité à chaque changement d'attribut. Vous pouvez activer la propagation automatique en configurant le noeud de rÚgle \" copier pour afficher \" dans votre chaîne de rÚgles et en liant les messages \"Post attributs \" et \"attributs mis à jour \" au nouveau noeud de rÚgle.", - "client-attributes": "Attributs du client", - "client-attributes-placeholder": "Attributs du client", - "configure-alias": "Configurez l'alias '{{alias}}'", - "copyId": "Copier l'ID de la vue d'entité", - "create-new-alias": "Créer un nouveau!", - "create-new-key": "Créer un nouveau!", - "date-limits": "Limites de date", - "delete": "Supprimer la vue d'entité", - "delete-entity-view-text": "Attention, aprÚs la confirmation, la vue de l'entité et toutes les données associées deviendront irrécupérables.", - "delete-entity-view-title": "Êtes-vous sûr de vouloir supprimer la vue de l'entité '{{entityViewName}}'?", - "delete-entity-views": "Supprimer les vues d'entité", - "delete-entity-views-action-title": "Supprimer { count, plural, 1 {1 entityView} other {# entityViews} }", - "delete-entity-views-text": "Attention, aprÚs la confirmation, toutes les vues d'entité sélectionnées seront supprimées et toutes les données associées deviendront irrécupérables.", - "delete-entity-views-title": "Êtes-vous sûr de vouloir voir l'entité { count, plural, 1 {1 entityView} other {# entityViews} }?", - "description": "Description", - "details": "Détails", - "duplicate-alias-error": "Alias '{{alias}}' existe déjà.
Les alias de vue d'entité doivent être uniques dans le tableau de bord.", - "end-date": "Date de fin", - "end-ts": "Heure de fin", - "enter-entity-view-type": "Entrer le type de vue d'entité", - "entity-view": "Vue d'entité", - "entity-view-alias": "Alias de vue d'entité", - "entity-view-details": "Détails de la vue d'entité", - "entity-view-list": "Liste de vues d'entités", - "entity-view-list-empty": "Aucune vue d'entité sélectionnée.", - "entity-view-name-filter-no-entity-view-matched": "Aucune vue d'entité commençant par '{{entityView}}' n'a été trouvée.", - "entity-view-name-filter-required": "Un filtre de nom de vue d'entité est requis.", - "entity-view-required": "Une vue d'entité est requise.", - "entity-view-type": "Type de vue d'entité", - "entity-view-type-list-empty": "Aucun type de vue d'entité sélectionné.", - "entity-view-type-required": "Le type d'entité est requis.", - "entity-view-types": "Types de vues d'entité", - "entity-views": "Vues d'entité", - "events": "Événements", - "make-private": "Rendre la vue d'entité privée", - "make-private-entity-view-text": "AprÚs la confirmation, la vue de l'entité et toutes ses données seront rendues privées et ne seront pas accessibles par d'autres", - "make-private-entity-view-title": "Êtes-vous sûr de vouloir rendre la vue d'entité '{{entityViewName}}' privée?", - "make-public": "Rendre la vue d'entité publique", - "make-public-entity-view-text": "AprÚs la confirmation, la vue de l'entité et toutes ses données seront rendues publiques et accessibles à d'autres", - "make-public-entity-view-title": "Voulez-vous vraiment que la vue de l'entité '{{entityViewName}}' soit publique?", - "management": "Gestion de vue d'entité", - "name": "Nom", - "name-required": "Un nom est requis.", - "name-starts-with": "Le nom de la vue d'entité commence par", - "no-alias-matching": "'{{alias}}' non trouvé.", - "no-aliases-found": "Aucun alias trouvé.", - "no-entity-view-types-matching": "Aucun type de vue d'entité correspondant à '{{entitySubtype}}' n'a été trouvé.", - "no-entity-views-matching": "Aucune vue d'entité correspondant à '{{entity}}' n'a été trouvée.", - "no-entity-views-text": "Aucune vue d'entité trouvée.", - "no-key-matching": "'{{key}}' non trouvé.", - "no-keys-found": "Aucune clé trouvée.", - "remove-alias": "Supprimer un alias de vue d'entité", - "select-entity-view": "Sélectionner une vue d'entité", - "select-entity-view-type": "Sélectionner le type de vue d'entité", - "server-attributes": "Attributs du serveur", - "server-attributes-placeholder": "Attributs du serveur", - "shared-attributes": "Attributs partagés", - "shared-attributes-placeholder": "Attributs partagés", - "start-date": "Date de début", - "start-ts": "Heure de début", - "target-entity": "Entité cible", - "timeseries": "Séries chronologiques", - "timeseries-data": "Données de séries chronologiques", - "timeseries-data-hint": "Configurez les clés de données de séries chronologiques de l'entité cible qui seront accessibles à la vue de l'entité. Ces données temporelles sont en lecture seule.", - "timeseries-placeholder": "Séries chronologiques", - "unable-entity-view-device-alias-text": "L'alias de dispositif '{{entityViewAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", - "unable-entity-view-device-alias-title": "Impossible de supprimer l'alias de la vue d'entité.", - "unassign-entity-view": "Annuler l'affectation de la vue d'entité", - "unassign-entity-view-text": "AprÚs la confirmation, la vue de l'entité sera non attribuée et ne sera pas accessible par le client.", - "unassign-entity-view-title": "Voulez-vous vraiment annuler l'attribution de la vue d'entité '{{entityViewName}}'?", - "unassign-entity-views": "Annuler l'attribution des vues d'entité", - "unassign-entity-views-action-title": "Annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} } du client", - "unassign-entity-views-text": "AprÚs la confirmation, toutes les vues des entités sélectionnées seront non attribuées et ne seront pas accessibles par le client.", - "unassign-entity-views-title": "Êtes-vous sûr de vouloir annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} }?", - "unassign-from-customer": "Annuler l'attribution au client", - "use-entity-view-name-filter": "Use filter", - "view-entity-views": "Voir les vues d'entité" - }, - "error": { - "unable-to-connect": "Impossible de se connecter au serveur! Veuillez vérifier votre connexion Internet.", - "unhandled-error-code": "Code d'erreur non géré: {{errorCode}}", - "unknown-error": "Erreur inconnue" - }, - "event": { - "alarm": "Alarme", - "body": "Corps", - "data": "Données", - "data-type": "Type de données", - "entity": "Entité", - "error": "erreur", - "errors-occurred": "Des erreurs sont survenues", - "event": "événement", - "event-time": "Heure de l'événement", - "event-type": "Type d'événement", - "failed": "Échec", - "message-id": "Message Id", - "message-type": "Type de message", - "messages-processed": "Messages traités", - "metadata": "Métadonnées", - "method": "Méthode", - "no-events-prompt": "Aucun événement trouvé", - "relation-type": "Type de relation", - "server": "Serveur", - "status": "État", - "success": "SuccÚs", - "type": "Type", - "type-debug-rule-chain": "Debug", - "type-debug-rule-node": "Debug", - "type-error": "Erreur", - "type-lc-event": "Evénement du cycle de vie", - "type-stats": "Statistiques" - }, - "extension": { - "add": "Ajouter une extension", - "add-attribute": "Ajouter un attribut", - "add-attribute-request": "Ajouter une demande d'attribut", - "add-attribute-update": "Ajouter une mise à jour d'attribut", - "add-broker": "Ajouter un Broker", - "add-config": "Ajouter une configuration de convertisseur", - "add-connect-request": "Ajouter une demande de connexion", - "add-converter": "Ajouter un convertisseur", - "add-device": "Ajouter un dispositif", - "add-disconnect-request": "Ajouter une demande de déconnexion", - "add-map": "Ajouter un élément de mappage", - "add-server-side-rpc-request": "Ajouter une requête RPC cÃŽté serveur", - "add-timeseries": "Ajouter des timeseries", - "anonymous": "Anonyme", - "attr-json-key-expression": "Expression json de la clé d'attribut", - "attr-topic-key-expression": "Expression du topic de la clé d'attribut", - "attribute-filter": "Filtre d'attribut", - "attribute-key-expression": "Expression de clé d'attribut", - "attribute-requests": "Demandes d'attributs", - "attribute-updates": "Mises à jour des attributs", - "attributes": "Attributs", - "basic": "Basic", - "brokers": "Brokers", - "ca-cert": "Fichier de certificat CA", - "cert": "Fichier de certificat *", - "client-scope": "Portée client", - "configuration": "Configuration", - "connect-requests": "Demandes de connexion", - "converter-configurations": "Configurations du convertisseur", - "converter-id": "ID du convertisseur", - "converter-json": "Json", - "converter-json-parse": "Impossible d'analyser le convertisseur json.", - "converter-json-required": "Le convertisseur json est requis.", - "converter-type": "Type de convertisseur", - "converters": "Convertisseurs", - "credentials": "Informations d'identification", - "custom": "Sur mesure", - "delete": "Supprimer l'extension", - "delete-extension-text": "Attention, aprÚs la confirmation, l'extension et toutes les données associées deviendront irrécupérables.", - "delete-extension-title": "Êtes-vous sûr de vouloir supprimer l'extension '{{extensionId}}'?", - "delete-extensions-text": "Attention, aprÚs la confirmation, toutes les extensions sélectionnées seront supprimées.", - "delete-extensions-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 extension} other {# extensions}}?", - "device-name-expression": "expression du nom du dispositif", - "device-name-filter": "Filtre de nom de dispositif", - "device-type-expression": "expression de type de dispositif", - "disconnect-requests": "Demandes de déconnection", - "drop-file": "Déposez un fichier ou cliquez pour sélectionner un fichier à télécharger.", - "edit": "Modifier l'extension", - "export-extension": "Exporter l'extension", - "export-extensions-configuration": "Exporter la configuration des extensions", - "extension-id": "Id de l'extension", - "extension-type": "Type d'extension", - "extensions": "Extensions", - "field-required": "Le champ est obligatoire", - "file": "Fichier d'extensions", - "filter-expression": "Expression du filtre", - "host": "HÃŽte", - "id": "Id", - "import-extension": "Importer une extension", - "import-extensions": "Importer des extensions", - "import-extensions-configuration": "Importer la configuration des extensions", - "invalid-file-error": "Fichier d'extension non valide", - "json-name-expression": "Expression json du nom du dispositif", - "json-parse": "Impossible d'analyser json transformer.", - "json-required": "Transformer json est requis.", - "json-type-expression": "Expression json du type de dispositif", - "key": "Clé", - "mapping": "Mappage", - "method-filter": "Filtre de méthode", - "modbus-add-server": "Ajouter serveur/esclave", - "modbus-add-server-prompt": "Veuillez ajouter serveur/esclave", - "modbus-attributes-poll-period": "Période d'interrogation des attributs (ms)", - "modbus-baudrate": "Débit en bauds", - "modbus-byte-order": "Ordre des octets", - "modbus-databits": "Bits de données", - "modbus-databits-range": "Les bits de données doivent être compris entre 7 et 8.", - "modbus-device-name": "Nom du dispositif", - "modbus-encoding": "Encodage", - "modbus-function": "Fonction", - "modbus-parity": "parité", - "modbus-poll-period": "Période d'interrogation (ms)", - "modbus-poll-period-range": "La période d'interrogation doit être une valeur positive.", - "modbus-port-name": "Nom du port série", - "modbus-register-address": "Adresse du registre", - "modbus-register-address-range": "L'adresse du registre doit être comprise entre 0 et 65535.", - "modbus-register-bit-index": "Bit index", - "modbus-register-bit-index-range": "L'index de bit doit être compris entre 0 et 15.", - "modbus-register-count": "Nombre de registre", - "modbus-register-count-range": "Le nombre de registres doit être une valeur positive.", - "modbus-server": "Serveurs / esclaves", - "modbus-stopbits": "Bits d'arrêt", - "modbus-stopbits-range": "Les bits d'arrêt doivent être compris entre 1 et 2.", - "modbus-tag": "Tag", - "modbus-timeseries-poll-period": "Période d'interrogation des Timeseries (ms)", - "modbus-transport": "Transport", - "modbus-unit-id": "Id de l'unité", - "modbus-unit-id-range": "L'ID de l'unité doit être compris entre 1 et 247.", - "no-file": "Aucun fichier sélectionné.", - "opc-add-server": "Ajouter un serveur", - "opc-add-server-prompt": "Veuillez ajouter un serveur", - "opc-application-name": "Nom de l'application", - "opc-application-uri": "Uri de l'application", - "opc-device-name-pattern": "modÚle de nom du dispositif", - "opc-device-node-pattern": "modÚle de noeud de dispositif", - "opc-identity": "Identité", - "opc-keystore": "Magasin de clés", - "opc-keystore-alias": "Alias", - "opc-keystore-key-password": "Mot de passe de la clé", - "opc-keystore-location": "Emplacement *", - "opc-keystore-password": "Mot de passe", - "opc-keystore-type": "Type", - "opc-scan-period-in-seconds": "Période d'analyse en secondes", - "opc-security": "Sécurité", - "opc-server": "Serveurs", - "opc-type": "Type", - "password": "Mot de passe", - "pem": "PEM", - "port": "Port", - "port-range": "Le port doit être compris entre 1 et 65535.", - "private-key": "Fichier de clé privée *", - "request-id-expression": "Expression de demande d'id", - "request-id-json-expression": "Expression json de la demande d'id", - "request-id-topic-expression": "Expression de la demande d'id du topic", - "request-topic-expression": "Expression de la demande du topic", - "response-timeout": "Délai de réponse en millisecondes", - "response-topic-expression": "Expression du topic de la réponse", - "retry-interval": "Intervalle de nouvelle tentative en millisecondes", - "selected-extensions": "{count, plural, 1 {1 extension} other {# extensions}} sélectionné", - "server-side-rpc": "RPC cÃŽté serveur", - "ssl": "Ssl", - "sync": { - "last-sync-time": "DerniÚre heure de synchronisation", - "not-available": "Non disponible", - "not-sync": "Non sync", - "status": "Status", - "sync": "Sync" - }, - "timeout": "Délai d'attente en millisecondes", - "timeseries": "Timeseries", - "to-double": "Au double", - "token": "Jeton de sécurité", - "topic": "Topic", - "topic-expression": "Expression du topic", - "topic-filter": "Filtre du topic", - "topic-name-expression": "Expression du nom du dispositif (topic)", - "topic-type-expression": "Expression de type de dispositif (topic)", - "transformer": "Transformer", - "transformer-json": "JSON *", - "type": "Type", - "unique-id-required": "L'identifiant d'extension actuel existe déjà.", - "username": "Nom d'utilisateur", - "value": "Valeur", - "value-expression": "Expression de la valeur" - }, - "fullscreen": { - "exit": "Quitter le plein écran", - "expand": "Afficher en plein écran", - "fullscreen": "Plein écran", - "toggle": "Activer le mode plein écran" - }, - "function": { - "function": "Fonction" - }, - "grid": { - "add-item-text": "Ajouter un nouvel élément", - "delete-item": "Supprimer l'élément", - "delete-item-text": "Faites attention, aprÚs la confirmation, cet élément et toutes les données associées deviendront irrécupérables.", - "delete-item-title": "Êtes-vous sûr de vouloir supprimer cet élément?", - "delete-items": "Supprimer les éléments", - "delete-items-action-title": "Supprimer {count, plural, 1 {1 élément} other {# éléments}}", - "delete-items-text": "Attention, aprÚs la confirmation, tous les éléments sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-items-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 élément} other {# éléments}}?", - "item-details": "Détails de l'élément", - "no-items-text": "Aucun élément trouvé", - "scroll-to-top": "Défiler vers le haut" - }, - "help": { - "goto-help-page": "Aller à la page d'aide" - }, - "home": { - "avatar": "Avatar", - "home": "Accueil", - "logout": "Déconnexion", - "menu": "Menu", - "open-user-menu": "Ouvrir le menu utilisateur", - "profile": "Profile" - }, - "icon": { - "icon": "IcÃŽne", - "material-icons": "IcÃŽnes matérielles", - "select-icon": "Sélectionner l'icÃŽne", - "show-all": "Afficher toutes les icÃŽnes" - }, - "import": { - "drop-file": "Déposez un fichier JSON ou cliquez pour sélectionner un fichier à télécharger.", - "no-file": "Aucun fichier sélectionné" - }, - "item": { - "selected": "Sélectionné" - }, - "js-func": { - "no-return-error": "La fonction doit renvoyer une valeur!", - "return-type-mismatch": "La fonction doit renvoyer une valeur de type '{{type}}' !", - "tidy": "Nettoyer" - }, - "key-val": { - "add-entry": "Ajouter une entrée", - "key": "Clé", - "no-data": "Aucune entrée", - "remove-entry": "Supprimer l'entrée", - "value": "Valeur" - }, - "language": { - "language": "Language", - "locales": { - "de_DE": "Allemand", - "en_US": "Anglais", - "fr_FR": "Français", - "es_ES": "Espagnol", - "it_IT": "Italien", - "ko_KR": "Coréen", - "ru_RU": "Russe", - "zh_CN": "Chinois", - "ja_JA": "Japonaise", - "tr_TR": "Turc", - "fa_IR": "Persane", - "uk_UA": "Ukrainien", - "cs_CZ": "TchÚque", - "el_GR": "Grec", - "lv_LV": "Letton" - } - }, - "layout": { - "color": "Couleur", - "layout": "Mise en page", - "main": "Principal", - "manage": "Gérer les mises en page", - "right": "Droite", - "select": "Sélectionner la mise en page cible", - "settings": "ParamÚtres de mise en page" - }, - "legend": { - "avg": "moy", - "max": "max", - "min": "min", - "position": "Position de la légende", - "settings": "ParamÚtres de la légende", - "show-avg": "Afficher la valeur moyenne", - "show-max": "Afficher la valeur maximale", - "show-min": "Afficher la valeur min", - "show-total": "Afficher la valeur totale", - "total": "total" - }, - "login": { - "create-password": "Créer un mot de passe", - "email": "Email", - "forgot-password": "Mot de passe oublié?", - "login": "Login", - "new-password": "Nouveau mot de passe", - "new-password-again": "nouveau mot de passe", - "password-again": "Mot de passe à nouveau", - "password-link-sent-message": "Le lien de réinitialisation du mot de passe a été envoyé avec succÚs!", - "password-reset": "Mot de passe réinitialisé", - "passwords-mismatch-error": "Les mots de passe saisis doivent être identiques!", - "remember-me": "Se souvenir de moi", - "request-password-reset": "Demander la réinitialisation du mot de passe", - "reset-password": "Réinitialiser le mot de passe", - "sign-in": "Veuillez vous connecter", - "username": "Nom d'utilisateur (courriel)" - }, - "position": { - "bottom": "Bas", - "left": "Gauche", - "right": "Droite", - "top": "Haut" - }, - "profile": { - "change-password": "Modifier le mot de passe", - "current-password": "Mot de passe actuel", - "last-login-time": "DerniÚre connexion", - "profile": "Profile" - }, - "relation": { - "add": "Ajouter une relation", - "add-relation-filter": "Ajouter un filtre de relation", - "additional-info": "Informations supplémentaires (JSON)", - "any-relation": "toute relation", - "any-relation-type": "N'importe quel type", - "delete": "Supprimer la relation", - "delete-from-relation-text": "Attention, aprÚs la confirmation, l'entité actuelle ne sera pas liée à l'entité '{{entityName}}'.", - "delete-from-relation-title": "Êtes-vous sûr de vouloir supprimer la relation de l'entité '{{entityName}}'?", - "delete-from-relations-text": "Attention, aprÚs la confirmation, toutes les relations sélectionnées seront supprimées et l'entité actuelle ne sera pas liée aux entités correspondantes.", - "delete-from-relations-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?", - "delete-to-relation-text": "Attention, aprÚs la confirmation, l'entité '{{entityName}} ne sera plus liée à l'entité actuelle.", - "delete-to-relation-title": "Êtes-vous sûr de vouloir supprimer la relation avec l'entité '{{entityName}}'?", - "delete-to-relations-text": "Attention, aprÚs la confirmation, toutes les relations sélectionnées seront supprimées et les entités correspondantes ne seront pas liées à l'entité en cours.", - "delete-to-relations-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?", - "direction": "Sens", - "direction-type": { - "FROM": "de", - "TO": "à" - }, - "edit": "Modifier la relation", - "from-entity": "De l'entité", - "from-entity-name": "Du nom d'entité", - "from-entity-type": "Du type d'entité", - "from-relations": "Relations sortantes", - "invalid-additional-info": "Impossible d'analyser les informations supplémentaires json.", - "relation-filters": "Filtres de relation", - "relation-type": "Type de relation", - "relation-type-required": "Le type de relation est requis.", - "relations": "Relations", - "remove-relation-filter": "Supprimer le filtre de relation", - "search-direction": { - "FROM": "De", - "TO": "Vers" - }, - "selected-relations": "{count, plural, 1 {1 relation} other {# relations}} sélectionné", - "to-entity": "Vers l'entité", - "to-entity-name": "vers le nom de l'entité", - "to-entity-type": "Vers le type d'entité", - "to-relations": "Relations entrantes", - "type": "Type" - }, - "rulechain": { - "add": "Ajouter une chaîne de rÚgles", - "add-rulechain-text": "Ajouter une nouvelle chaîne de rÚgles", - "copyId": "Copier l'identifiant de la chaîne de rÚgles", - "create-new-rulechain": "Créer une nouvelle chaîne de rÚgles", - "debug-mode": "Mode de débogage", - "delete": "Supprimer la chaîne de rÚgles", - "delete-rulechain-text": "Attention, aprÚs la confirmation, la chaîne de rÚgles et toutes les données associées deviendront irrécupérables.", - "delete-rulechain-title": "Voulez-vous vraiment supprimer la chaîne de rÚgles '{{ruleChainName}}'?", - "delete-rulechains-action-title": "Supprimer {count, plural, 1 {1 chaîne de rÚgles} other {# chaînes de rÚgles}}", - "delete-rulechains-text": "Attention, aprÚs la confirmation, toutes les chaînes de rÚgles sélectionnées seront supprimées et toutes les données associées deviendront irrécupérables.", - "delete-rulechains-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 chaîne de rÚgles} other {# chaînes de rÚgles}}?", - "description": "Description", - "details": "Détails", - "events": "Evénements", - "export": "Exporter la chaîne de rÚgles", - "export-failed-error": "Impossible d'exporter la chaîne de rÚgles: {{error}}", - "idCopiedMessage": "L'ID de la chaîne de rÚgles a été copié dans le presse-papier", - "import": "Importer la chaîne de rÚgles", - "invalid-rulechain-file-error": "Impossible d'importer la chaîne de rÚgles: structure de données de la chaîne de rÚgles non valide", - "management": "Gestion des rÚgles", - "name": "Nom", - "name-required": "Le nom est requis.", - "no-rulechains-matching": "Aucune chaîne de rÚgles correspondant à {{entity}} n'a été trouvée.", - "no-rulechains-text": "Aucune chaîne de rÚgles trouvée", - "root": "Racine", - "rulechain": "Chaîne de rÚgles", - "rulechain-details": "Détails de la chaîne de rÚgles", - "rulechain-file": "Fichier de chaîne de rÚgles", - "rulechain-required": "Chaîne de rÚgles requise", - "rulechains": "Chaînes de rÚgles", - "select-rulechain": "Sélectionner la chaîne de rÚgles", - "set-root": "Rend la chaîne de rÚgles racine (root) ", - "set-root-rulechain-text": "AprÚs la confirmation, la chaîne de rÚgles deviendra racine (root) et gérera tous les messages de transport entrants.", - "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de rÚgles '{{ruleChainName}} soit racine (root) ?", - "system": "SystÚme" - }, - "rulenode": { - "add": "Ajouter un noeud de rÚgle", - "add-link": "Ajouter un lien", - "configuration": "Configuration", - "copy-selected": "Copier les éléments sélectionnés", - "create-new-link-label": "Créez un nouveau!", - "custom-link-label": "Etiquette de lien personnalisée", - "custom-link-label-required": "Une étiquette de lien personnalisée est requise", - "debug-mode": "Mode de débogage", - "delete": "Supprimer le noeud de rÚgle", - "delete-selected": "Supprimer les éléments sélectionnés", - "delete-selected-objects": "Supprimer les nœuds et les connexions sélectionnés", - "description": "Description", - "deselect-all": "Désélectionner tout", - "deselect-all-objects": "Désélectionnez tous les nœuds et toutes les connexions", - "details": "Détails", - "directive-is-not-loaded": "La directive de configuration définie '{{directiveName}} n'est pas disponible.", - "events": "Événements", - "help": "Aide", - "invalid-target-rulechain": "Impossible de résoudre la chaîne de rÚgles cible!", - "link": "Lien", - "link-details": "Détails du lien du noeud de la rÚgle", - "link-label": "Étiquette du lien", - "link-label-required": "L'étiquette du lien est obligatoire", - "link-labels": "Étiquettes de lien", - "link-labels-required": "Les étiquettes de lien sont obligatoires", - "message": "Message", - "message-type": "Type de message", - "message-type-required": "Le type de message est obligatoire", - "metadata": "Métadonnées", - "metadata-required": "Les entrées de métadonnées ne peuvent pas être vides.", - "name": "Nom", - "name-required": "Le nom est requis.", - "no-link-label-matching": "'{{label}}' introuvable.", - "no-link-labels-found": "Aucune étiquette de lien trouvée", - "open-node-library": "Ouvrir la bibliothÚque de noeud", - "output": "Output", - "rulenode-details": "Détails du noeud de la régle", - "search": "Recherche de noeuds", - "select-all": "Tout sélectionner", - "select-all-objects": "Sélectionnez tous les noeuds et connexions", - "select-message-type": "Sélectionner le type de message", - "test": "Test", - "test-script-function": "Tester le script", - "type": "Type", - "type-action": "Action", - "type-action-details": "Effectuer une action spéciale", - "type-enrichment": "Enrichissement", - "type-enrichment-details": "Ajouter des informations supplémentaires dans les métadonnées de message", - "type-external": "Externe", - "type-external-details": "Interagit avec le systéme externe", - "type-filter": "Filtre", - "type-filter-details": "Filtrer les messages entrants avec des conditions configurées", - "type-input": "Input", - "type-input-details": "Entrée logique de la chaîne de rÚgles, transmet les messages entrants au prochain nœud de rÚgle associé", - "type-rule-chain": "Chaîne de régles", - "type-rule-chain-details": "Transmet les messages entrants à la chaîne de régles spécifiée", - "type-transformation": "Transformation", - "type-transformation-details": "Modifier le payload du message et les métadonnées ", - "type-unknown": "Inconnu", - "type-unknown-details": "Noeud de rÚgle non résolu", - "ui-resources-load-error": "Impossible de charger les ressources de configuration de l'interface utilisateur." - }, - "tenant": { - "add": "Ajouter un Tenant", - "add-tenant-text": "Ajouter un nouveau Tenant", - "admins": "Admins", - "copyId": "Copier l'Id du Tenant", - "delete": "Supprimer le Tenant", - "delete-tenant-text": "Attention, aprÚs la confirmation, le Tenant et toutes les données associées deviendront irrécupérables.", - "delete-tenant-title": "Êtes-vous sûr de vouloir supprimer le tenant '{{tenantTitle}}'?", - "delete-tenants-action-title": "Supprimer {count, plural, 1 {1 tenant} other {# tenants}}", - "delete-tenants-text": "Attention, aprÚs la confirmation, tous les Tenants sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-tenants-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 tenant} other {# tenants}}?", - "description": "Description", - "details": "Détails", - "events": "Événements", - "idCopiedMessage": "L'Id du Tenant a été copié dans le Presse-papiers", - "manage-tenant-admins": "Gérer les administrateurs du Tenant", - "management": "Gestion des Tenants", - "no-tenants-matching": "Aucun Tenant correspondant à {{entity}} n'a été trouvé. ", - "no-tenants-text": "Aucun Tenant trouvé", - "select-tenant": "Sélectionner un Tenant", - "tenant": "Tenant", - "tenant-details": "Détails du Tenant", - "tenant-required": "Tenant requis", - "tenants": "Tenants", - "title": "Titre", - "title-required": "Le titre est requis." - }, - "timeinterval": { - "advanced": "Avancé", - "days": "Jours", - "days-interval": "{days, plural, 1 {1 jour} other {# jours}}", - "hours": "Heures", - "hours-interval": "{hours, plural, 1 {1 heure} other {# heures}}", - "minutes": "Minutes", - "minutes-interval": "{minutes, plural, 1 {1 minute} other {# minutes}}", - "seconds": "Secondes", - "seconds-interval": "{seconds, plural, 1 {1 seconde} other {# secondes}}" - }, - "timewindow": { - "date-range": "Plage de dates", - "days": "{days, plural, 1 {jour} other {# jours}}", - "edit": "Modifier timewindow", - "history": "Historique", - "hours": "{hours, plural, 0 {heure} 1 {1 heure} other {# heures}}", - "last": "Dernier", - "last-prefix": "dernier", - "minutes": "{minutes, plural, 0 {minute} 1 {1 minute} other {# minutes}}", - "period": "de {{startTime}} à {{endTime}}", - "realtime": "Temps réel", - "seconds": "{seconds, plural, 0 {second} 1 {1 second} other {# seconds}}", - "time-period": "Période", - "hide": "Masquer" - }, - "user": { - "activation-email-sent-message": "Le courriel d'activation a été envoyé avec succÚs!", - "activation-link": "Lien d'activation utilisateur", - "activation-link-copied-message": "le lien d'activation de l'utilisateur a été copié dans le presse-papier", - "activation-link-text": "Pour activer l'utilisateur, utilisez le lien d'activation suivant: ", - "activation-method": "Méthode d'activation", - "add": "Ajouter un utilisateur", - "add-user-text": "Ajouter un nouvel utilisateur", - "always-fullscreen": "Toujours en plein écran", - "anonymous": "Anonyme", - "copy-activation-link": "Copier le lien d'activation", - "customer": "Client", - "customer-users": "Utilisateurs du client", - "default-dashboard": "Tableau de bord par défaut", - "delete": "Supprimer l'utilisateur", - "delete-user-text": "Attention, aprÚs la confirmation, l'utilisateur et toutes les données associées deviendront irrécupérables.", - "delete-user-title": "Êtes-vous sûr de vouloir supprimer l'utilisateur '{{userEmail}}'?", - "delete-users-action-title": "Supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}", - "delete-users-text": "Attention, aprÚs la confirmation, tous les utilisateurs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-users-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}?", - "description": "Description", - "details": "Détails", - "disable-account": "Désactiver le compte d'utilisateur", - "disable-account-message": "Le compte d'utilisateur a été désactivé avec succÚs!", - "display-activation-link": "Afficher le lien d'activation", - "email": "Email", - "email-required": "Email est requis.", - "enable-account": "Activer le compte d'utilisateur", - "enable-account-message": "Le compte d'utilisateur a été activé avec succÚs!", - "first-name": "Prénom", - "invalid-email-format": "Format de courrier électronique non valide", - "last-name": "Nom de famille", - "login-as-customer-user": "Se connecter en tant qu'utilisateur client", - "login-as-tenant-admin": "Connectez-vous en tant qu'administrateur Tenant", - "no-users-matching": "Aucun utilisateur correspondant à '{{entity}}' n'a été trouvé.", - "no-users-text": "Aucun utilisateur trouvé", - "resend-activation": "Renvoyer l'activation", - "select-user": "Sélectionner l'utilisateur", - "send-activation-mail": "Envoyer un mail d'activation", - "sys-admin": "Administrateur du systÚme", - "tenant-admin": "Administrateur du Tenant", - "tenant-admins": "administrateurs du Tenant", - "user": "utilisateur", - "user-details": "Détails de l'utilisateur", - "user-required": "L'utilisateur est requis", - "users": "Utilisateurs" - }, - "value": { - "boolean": "booléen", - "boolean-value": "Valeur booléenne", - "double": "Double", - "double-value": "Valeur double", - "false": "Faux", - "integer": "Entier", - "integer-value": "Valeur entiÚre", - "invalid-integer-value": "Valeur entiÚre invalide", - "long": "Long", - "string": "String", - "string-value": "Valeur String", - "true": "Vrai", - "type": "Type de valeur" - }, - "widget": { - "add": "Ajouter un widget", - "add-resource": "Ajouter une ressource", - "add-widget-type": "Ajouter un nouveau type de widget", - "alarm": "Widget d'alarme", - "css": "CSS", - "datakey-settings-schema": "Schéma des paramÚtres de Data key", - "edit": "Modifier le widget", - "editor": " Editeur de widget", - "export": "Exporter widget", - "html": "HTML", - "javascript": "Javascript", - "latest-values": "DerniÚres valeurs", - "management": "Gestion des widgets", - "missing-widget-title-error": "Le titre du widget doit être spécifié!", - "no-data-found": "Aucune donnée trouvée", - "remove": "Supprimer le widget", - "remove-resource": "Supprimer une ressource", - "remove-widget-text": "AprÚs la confirmation, le widget et toutes les données associées deviendront irrécupérables.", - "remove-widget-title": "Êtes-vous sûr de vouloir supprimer le widget '{{widgetTitle}}'?", - "remove-widget-type": "Supprimer le type de widget", - "remove-widget-type-text": "AprÚs la confirmation, le type de widget et toutes les données associées deviendront irrécupérables.", - "remove-widget-type-title": "Êtes-vous sûr de vouloir supprimer le type de widget '{{widgetName}}'?", - "resource-url": "URL JavaScript / CSS", - "resources": "Ressources", - "rpc": "Widget de contrÃŽle", - "run": "Exécuter un widget", - "save": "Enregistrer le widget", - "save-widget-type-as": "Enregistrer le type de widget sous", - "save-widget-type-as-text": "Veuillez saisir un nouveau titre de widget et / ou sélectionner un ensemble de widgets cibles", - "saveAs": "Enregistrer le widget sous", - "search-data": "Rechercher des données", - "select-widget-type": "Sélectionnez le type de widget", - "select-widgets-bundle": "Sélectionner un ensemble de widgets", - "settings-schema": "Schéma des paramétres", - "static": "Widget statique", - "tidy": "Nettoyer", - "timeseries": "Séries chronologiques", - "title": "Titre du widget", - "title-required": "Le titre du widget est requis.", - "toggle-fullscreen": "Basculer le mode plein écran", - "type": "Type de widget", - "unable-to-save-widget-error": "Impossible de sauvegarder le widget! Le widget a des erreurs!", - "undo": "Annuler les modifications du widget", - "widget-bundle": "Ensemble de widget", - "widget-library": "BibliothÚque de widgets", - "widget-saved": "Widget enregistré", - "widget-template-load-failed-error": "Impossible de charger le modéle de widget!", - "widget-type-load-error": "Le widget n'a pas été chargé à cause des erreurs suivantes:", - "widget-type-load-failed-error": "Impossible de charger le type de widget!", - "widget-type-not-found": "ProblÚme de chargement de la configuration du widget.
Le type de widget associé a probablement été supprimé." - }, - "widget-action": { - "custom": "Action personnalisée", - "header-button": "Bouton d'en-tête de widget", - "open-dashboard": "Naviguer vers un autre tableau de bord", - "open-dashboard-state": "Naviguer vers un nouvel état du tableau de bord", - "open-right-layout": "Ouvrir la disposition du tableau de bord droite (vue mobile)", - "set-entity-from-widget": "Définir l'entité à partir du widget", - "target-dashboard": "Tableau de bord cible", - "target-dashboard-state": "État du tableau de bord cible", - "target-dashboard-state-required": "L'état du tableau de bord cible est requis", - "update-dashboard-state": "Mettre à jour l'état actuel du tableau de bord" - }, - "widget-config": { - "action": "Action", - "action-icon": "IcÃŽne", - "action-name": "Nom", - "action-name-not-unique": "Une autre action portant le même nom existe déjà.
Le nom de l'action doit être unique dans la même source d'action.", - "action-name-required": "Le nom de l'action est requis", - "action-source": "Source de l'action", - "action-source-required": "Une source d'action est requise.", - "action-type": "Type", - "action-type-required": "Le type d'action est requis.", - "actions": "Actions", - "add-action": "Ajouter une action", - "add-datasource": "Ajouter une source de données", - "advanced": "Avancé", - "alarm-source": "Source d'alarme", - "background-color": "couleur de fond", - "data": "Données", - "datasource-parameters": "ParamÚtres", - "datasource-type": "Type", - "datasources": "Sources de données", - "decimals": "Nombre de chiffres aprÚs virgule flottante", - "delete-action": "Supprimer l'action", - "delete-action-text": "Êtes-vous sûr de vouloir supprimer l'action du widget nommé '{{actionName}}'?", - "delete-action-title": "Supprimer l'action du widget", - "display-timewindow": "Afficher fenêtre de temps", - "display-legend": "Afficher la légende", - "display-title": "Afficher le titre", - "drop-shadow": "Ombre portée", - "edit-action": "Modifier l'action", - "enable-fullscreen": "Activer le plein écran", - "general-settings": "ParamÚtres généraux", - "height": "Hauteur", - "margin": "Marge", - "maximum-datasources": "Maximum {count, plural, 1 {1 datasource est autorisé.} other {# datasources sont autorisés}}", - "mobile-mode-settings": "ParamÚtres du mode mobile", - "order": "Ordre", - "padding": "Padding", - "remove-datasource": "Supprimer la source de données", - "search-actions": "Recherche d'actions", - "settings": "ParamÚtres", - "target-device": "Dispositif cible", - "text-color": "Couleur du texte", - "timewindow": "Fenêtre de temps", - "title": "Titre", - "title-style": "Style de titre", - "title-tooltip": "Tooltip de titre", - "units": "Symbole spécial à afficher à cÃŽté de la valeur", - "use-dashboard-timewindow": "Utiliser la fenêtre de temps du tableau de bord", - "widget-style": "Style du widget", - "display-icon": "Afficher l'icÃŽne du titre", - "icon-color": "Couleur de l'icÃŽne", - "icon-size": "Taille de l'icÃŽne" - }, - "widget-type": { - "create-new-widget-type": "Créer un nouveau type de widget", - "export": "Exporter le type de widget", - "export-failed-error": "Impossible d'exporter le type de widget: {{error}}", - "import": "Importer le type de widget", - "invalid-widget-type-file-error": "Impossible d'importer le type de widget: structure de données de type widget invalide.", - "widget-type-file": "Fichier de type Widget" - }, - "widgets": { - "date-range-navigator": { - "localizationMap": { - "Sun": "Dim.", - "Mon": "Lun.", - "Tue": "Mar.", - "Wed": "Mer.", - "Thu": "Jeu.", - "Fri": "Ven.", - "Sat": "Sam.", - "Jan": "Janv.", - "Feb": "Févr.", - "Mar": "Mars", - "Apr": "Avr.", - "May": "Mai", - "Jun": "Juin", - "Jul": "Juil.", - "Aug": "Août", - "Sep": "Sept.", - "Oct": "Oct.", - "Nov": "Nov.", - "Dec": "Déc.", - "January": "Janvier", - "February": "Février", - "March": "Mars", - "April": "Avril", - "June": "Juin", - "July": "Juillet", - "August": "Août", - "September": "Septembre", - "October": "Octobre", - "November": "Novembre", - "December": "Décembre", - "Custom Date Range": "Plage de dates personnalisée", - "Date Range Template": "ModÚle de plage de dates", - "Today": "Aujourd'hui", - "Yesterday": "Hier", - "This Week": "Cette semaine", - "Last Week": "La semaine derniÚre", - "This Month": "Ce mois-ci", - "Last Month": "Le mois dernier", - "Year": "Année", - "This Year": "Cette année", - "Last Year": "L'année derniÚre", - "Date picker": "Sélecteur de date", - "Hour": "Heure", - "Day": "Journée", - "Week": "La semaine", - "2 weeks": "2 Semaines", - "Month": "Mois", - "3 months": "3 Mois", - "6 months": "6 Mois", - "Custom interval": "Intervalle personnalisé", - "Interval": "Intervalle", - "Step size": "Taille de pas", - "Ok": "Ok" - } - }, - "input-widgets": { - "attribute-not-allowed": "Le paramÚtre d'attribut ne peut pas être utilisé dans ce widget", - "date": "Date", - "discard-changes": "Annuler les modifications", - "entity-attribute-required": "L'attribut d'entité est requis", - "entity-timeseries-required": "Entité timeseries est requis", - "not-allowed-entity": "L'entité sélectionnée ne peut pas avoir d'attributs partagés", - "no-attribute-selected": "Aucun attribut n'est sélectionné", - "no-datakey-selected": "Aucune date n'est sélectionnée", - "no-entity-selected": "Aucune entité sélectionnée", - "no-image": "Pas d'image", - "no-support-web-camera": "Pas de webcam supportée", - "no-timeseries-selected": "Aucune série temporelle sélectionnée", - "switch-attribute-value": "Changer la valeur de l'attribut d'entité", - "switch-camera": "Changer de caméra", - "switch-timeseries-value": "Changer la valeur de l'entité série temporelle", - "take-photo": "Prendre une photo", - "time": "Temps", - "timeseries-not-allowed": "Le paramÚtre série temporelle ne peut pas être utilisé dans ce widget", - "update-failed": "Mise à jour a échoué", - "update-successful": "Mise à jour réussie", - "update-attribute": "Attribut de mise à jour", - "update-timeseries": "Mise à jour de la série temporelle", - "value": "Valeur" - } - }, - "widgets-bundle": { - "add": "Ajouter un groupe de widgets", - "add-widgets-bundle-text": "Ajouter un nouveau groupe de widgets", - "create-new-widgets-bundle": "Créer un nouveau groupe de widgets", - "current": "Groupe actuel", - "delete": "Supprimer le groupe de widgets", - "delete-widgets-bundle-text": "Attention, aprÚs la confirmation, le groupe de widgets et toutes les données associées deviendront irrécupérables.", - "delete-widgets-bundle-title": "Êtes-vous sûr de vouloir supprimer le groupe de widgets '{{widgetsBundleTitle}}'?", - "delete-widgets-bundles-action-title": "Supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}", - "delete-widgets-bundles-text": "Attention, aprÚs la confirmation, tous les groupes de widgets sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", - "delete-widgets-bundles-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}?", - "details": "Détails", - "empty": "Le groupe de widgets est vide", - "export": "Exporter le groupe de widgets", - "export-failed-error": "Impossible d'exporter le groupe de widgets: {{error}}", - "import": "Importer un groupe de widgets", - "invalid-widgets-bundle-file-error": "Impossible d'importer un groupe de widgets: structure de données du groupe de widgets non valides.", - "no-widgets-bundles-matching": "Aucun groupe de widgets correspondant à {{widgetsBundle}} n'a été trouvé.", - "no-widgets-bundles-text": "Aucun groupe de widgets trouvé", - "system": "SystÚme", - "title": "Titre", - "title-required": "Le titre est requis.", - "widgets-bundle-details": "Détails des groupes de widgets", - "widgets-bundle-file": "Fichier de groupe de widgets", - "widgets-bundle-required": "Un groupe de widgets est requis.", - "widgets-bundles": "Groupes de widgets" - } -} +{ + "access": { + "access-forbidden": "AccÚs interdit", + "access-forbidden-text": "Vous n'avez pas accÚs à cet emplacement!
Essayez de vous connecter avec un autre utilisateur si vous souhaitez toujours accéder à cet emplacement.", + "refresh-token-expired": "La session a expiré", + "refresh-token-failed": "Impossible de rafraîchir la session", + "unauthorized": "non autorisé", + "unauthorized-access": "accÚs non autorisé", + "unauthorized-access-text": "Vous devez vous connecter pour avoir accÚs à cette ressource!" + }, + "action": { + "activate": "Activer", + "add": "Ajouter", + "apply": "Appliquer", + "apply-changes": "Appliquer les modifications", + "assign": "Attribuer", + "back": "retour", + "cancel": "Annuler", + "clear-search": "Effacer la recherche", + "close": "Fermer", + "continue": "Continue", + "copy": "Copier", + "copy-reference": "Copier la référence", + "create": "Créer", + "decline-changes": "Refuser les modifications", + "delete": "Supprimer", + "discard-changes": "Annuler les modifications", + "drag": "Drag", + "edit": "Modifier", + "edit-mode": "Mode édition", + "enter-edit-mode": "Entrer en mode édition", + "export": "Exporter", + "import": "Importer", + "make-private": "Rendre privé", + "no": "Non", + "ok": "OK", + "paste": "coller", + "paste-reference": "Coller référence", + "refresh": "Rafraîchir", + "remove": "Supprimer", + "run": "Exécuter", + "save": "Enregistrer", + "saveAs": "Enregistrer sous", + "search": "Rechercher", + "share": "Partager", + "share-via": "Partager via {{provider}}", + "sign-in": "Connectez-vous!", + "suspend": "Suspendre", + "unassign": "Retirer", + "undo": "Annuler", + "update": "mise à jour", + "view": "Afficher", + "yes": "Oui" + }, + "admin": { + "base-url": "URL de base", + "base-url-required": "L'URL de base est requise.", + "enable-tls": "Activer TLS", + "tls-version": "Version TLS", + "general": "Général", + "general-settings": "ParamÚtres généraux", + "mail-from": "Mail de", + "mail-from-required": "Mail de est requis.", + "outgoing-mail": "courrier sortant", + "outgoing-mail-settings": "ParamÚtres de courrier sortant", + "send-test-mail": "Envoyer un mail de test", + "smtp-host": "HÃŽte SMTP", + "smtp-host-required": "L'hÃŽte SMTP est requis.", + "smtp-port": "Port SMTP", + "smtp-port-invalid": "Cela ne ressemble pas à un port smtp valide.", + "smtp-port-required": "Vous devez fournir un port smtp.", + "smtp-protocol": "Protocole SMTP", + "system-settings": "ParamÚtres systÚme", + "test-mail-sent": "Le courrier de test a été envoyé avec succés!", + "timeout-invalid": "Cela ne ressemble pas à un délai d'expiration valide.", + "timeout-msec": "Délai (msec)", + "timeout-required": "Le délai est requis.", + "security-settings": "Les paramÚtres de sécurité", + "password-policy": "Politique de mot de passe", + "minimum-password-length": "Longueur minimale du mot de passe", + "minimum-password-length-required": "La longueur minimale du mot de passe est requise", + "minimum-password-length-range": "La longueur minimale du mot de passe doit être comprise entre 5 et 50.", + "minimum-uppercase-letters": "Nombre minimum de lettres majuscules", + "minimum-uppercase-letters-range": "Le nombre minimum de lettres majuscules ne peut pas être négatif", + "minimum-lowercase-letters": "Nombre minimum de lettres minuscules", + "minimum-lowercase-letters-range": "Le nombre minimum de lettres minuscules ne peut pas être négatif", + "minimum-digits": "Nombre minimum de chiffres", + "minimum-digits-range": "Le nombre minimum de chiffres ne peut pas être négatif", + "minimum-special-characters": "Nombre minimum de caractÚres spéciaux", + "minimum-special-characters-range": "Le nombre minimum de caractÚres spéciaux ne peut pas être négatif", + "password-expiration-period-days": "Délai d'expiration du mot de passe en jours", + "password-expiration-period-days-range": "La période d'expiration du mot de passe en jours ne peut pas être négative", + "password-reuse-frequency-days": "Fréquence de réutilisation du mot de passe en jours", + "password-reuse-frequency-days-range": "La fréquence de réutilisation du mot de passe en jours ne peut être négative", + "general-policy": "Politique générale", + "max-failed-login-attempts": "Nombre maximal de tentatives de connexion infructueuses avant que le compte ne soit verrouillé", + "minimum-max-failed-login-attempts-range": "Le nombre maximal de tentatives de connexion ayant échoué ne peut pas être négatif", + "user-lockout-notification-email": "En cas de verrouillage du compte d'utilisateur, envoyez une notification par courrier électronique." + }, + "aggregation": { + "aggregation": "agrégation", + "avg": "Moyenne", + "count": "Compte", + "function": "Fonction d'agrégation de données", + "group-interval": "Intervalle de regroupement", + "limit": "Valeurs maximales", + "max": "Max", + "min": "Min", + "none": "Aucune", + "sum": "Somme" + }, + "alarm": { + "ack-time": "Heure d'acquittement", + "acknowledge": "Acquitter", + "aknowledge-alarm-text": "Êtes-vous sûr de vouloir reconnaître l'alarme?", + "aknowledge-alarm-title": "Reconnaître l'alarme", + "aknowledge-alarms-text": "Êtes-vous sûr de vouloir acquitter {count, plural, 1 {1 alarme} other {# alarmes}}?", + "aknowledge-alarms-title": "Acquitter {count, plural, 1 {1 alarme} other {# alarmes}}", + "alarm": "Alarme", + "alarm-details": "Détails de l'alarme", + "alarm-required": "Une alarme est requise", + "alarm-status": "État d'alarme", + "alarm-status-filter": "Filtre d'état d'alarme", + "alarms": "Alarmes", + "clear": "Effacer", + "clear-alarm-text": "Êtes-vous sûr de vouloir effacer l'alarme?", + "clear-alarm-title": "Effacer l'alarme", + "clear-alarms-text": "Êtes-vous sûr de vouloir effacer {count, plural, 1 {1 alarme} other {# alarmes}}?", + "clear-alarms-title": "Effacer {count, plural, 1 {1 alarme} other {# alarmes}}", + "clear-time": "Heure d'éffacement", + "created-time": "Heure de création", + "details": "Détails", + "display-status": { + "ACTIVE_ACK": "Active acquittée", + "ACTIVE_UNACK": "Active non acquittée", + "CLEARED_ACK": "effacée acquittée", + "CLEARED_UNACK": "effacée non acquittée" + }, + "end-time": "Heure de fin", + "min-polling-interval-message": "Un intervalle d'interrogation d'au moins 1 seconde est autorisé.", + "no-alarms-matching": "Aucune alarme correspondant à {{entity}} n'a été trouvée. ", + "no-alarms-prompt": "Aucune alarme", + "no-data": "Aucune donnée à afficher", + "originator": "Source", + "originator-type": "Type de Source", + "polling-interval": "Intervalle d'interrogation des alarmes (sec)", + "polling-interval-required": "L'intervalle d'interrogation des alarmes est requis.", + "search": "Rechercher des alarmes", + "search-status": { + "ACK": "acquitté", + "ACTIVE": "active", + "ANY": "Toutes", + "CLEARED": "effacée", + "UNACK": "non acquittée" + }, + "select-alarm": "Sélectionnez une alarme", + "selected-alarms": "{count, plural, 1 {1 alarme} other {# alarmes}} sélectionnées", + "severity": "Gravité", + "severity-critical": "Critique", + "severity-indeterminate": "indéterminée", + "severity-major": "Majeure", + "severity-minor": "mineure", + "severity-warning": "Avertissement", + "start-time": "Heure de début", + "status": "État", + "type": "Type" + }, + "alias": { + "add": "Ajouter un alias", + "all-entities": "Toutes les entités", + "any-relation": "toutes", + "default-entity-parameter-name": "Par défaut", + "default-state-entity": "Entité d'état par défaut", + "duplicate-alias": "Un alias portant le même nom existe déjà.", + "edit": "Modifier l'alias", + "entity-filter": "Filtre d'entité", + "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.", + "filter-type": "Type de filtre", + "filter-type-asset-search-query": "requête de recherche d'actifs", + "filter-type-asset-search-query-description": "Actifs de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-asset-type": "type d'actif", + "filter-type-asset-type-and-name-description": "Actifs de type '{{assetType}}' et dont le nom commence par '{{prefix}}'", + "filter-type-asset-type-description": "Actifs de type '{{assetType}}'", + "filter-type-device-search-query": "Requête de recherche de dispositif", + "filter-type-device-search-query-description": "Dispositifs de types {{deviceTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-device-type": "Type de dispositif", + "filter-type-device-type-and-name-description": "Dispositifs de type '{{deviceType}}' et dont le nom commence par '{{prefix}}'", + "filter-type-device-type-description": "Dispositifs de type '{{deviceType}}'", + "filter-type-entity-list": "Liste d'entités", + "filter-type-entity-name": "Nom d'entité", + "filter-type-entity-view-search-query": "Requête de recherche vue d'entité", + "filter-type-entity-view-search-query-description": "Vues d'entité avec les types {{entityViewTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-entity-view-type": "Type de vue d'entité", + "filter-type-entity-view-type-and-name-description": "Vues d'entité de type '{{entityView}}' et dont le nom commence par '{{prefix}}'", + "filter-type-entity-view-type-description": "Vues d'entité de type '{{entityView}}'", + "filter-type-relations-query": "Interrogation des relations", + "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-required": "Le type de filtre est requis.", + "filter-type-single-entity": "Entité unique", + "filter-type-state-entity": "Entité de l'état du tableau de bord", + "filter-type-state-entity-description": "Entité extraite des paramétres d'état du tableau de bord", + "max-relation-level": "Niveau de relation maximum", + "name": "Nom de l'alias", + "name-required": "Le nom d'alias est requis", + "no-entity-filter-specified": "Aucun filtre d'entité spécifié", + "resolve-multiple": "Résoudre en plusieurs entités", + "root-entity": "Entité racine", + "root-state-entity": "Utiliser l'entité d'état du tableau de bord en tant que racine", + "state-entity": "Entité d'état du tableau de bord", + "state-entity-parameter-name": "Nom du paramétre d'entité d'état", + "unlimited-level": "niveau illimité" + }, + "asset": { + "add": "Ajouter un actif", + "add-asset-text": "Ajouter un nouvel actif", + "any-asset": "Tout actif", + "asset": "Actif", + "asset-details": "Détails de l'actif", + "asset-file": "Actif file", + "asset-public": "L'actif est public", + "asset-required": "Actif requis", + "asset-type": "Type d'actif", + "asset-type-list-empty": "Aucun type d'actif sélectionné.", + "asset-type-required": "Le type d'actif est requis.", + "asset-types": "Types d'actif", + "assets": "Actifs", + "assign-asset-to-customer": "Attribuer des actifs au client", + "assign-asset-to-customer-text": "Veuillez sélectionner les actifs à attribuer au client", + "assign-assets": "Attribuer des actifs", + "assign-assets-text": "Attribuer {count, plural, 1 {1 asset} other {# assets}} au client", + "assign-new-asset": "Attribuer un nouvel Asset", + "assign-to-customer": "Attribuer au client", + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les actifs", + "assignedToCustomer": "attribué au client", + "copyId": "Copier l'Id de l'actif", + "delete": "Supprimer un actif", + "delete-asset-text": "Faites attention, aprÚs la confirmation, l'actif et toutes les données associées deviendront irrécupérables.", + "delete-asset-title": "Êtes-vous sûr de vouloir supprimer l'actif '{{assetName}}'?", + "delete-assets": "Supprimer des actifs", + "delete-assets-action-title": "Supprimer {count, plural, 1 {1 asset} other {# assets}}", + "delete-assets-text": "Attention, aprÚs la confirmation, tous les actifs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-assets-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 asset} other {# assets}}?", + "description": "Description", + "details": "Détails", + "enter-asset-type": "Entrez le type d'actif", + "events": "Evénements", + "idCopiedMessage": "L'Id d'asset a été copié dans le presse-papier", + "import": "Import actifs", + "make-private": "Rendre l'actif privé", + "make-private-asset-text": "AprÚs la confirmation, l'actif et toutes ses données seront rendus privés et ne seront pas accessibles par d'autres.", + "make-private-asset-title": "Êtes-vous sûr de vouloir rendre l'actif '{{assetName}}' privé '?", + "make-public": "Rendre l'actif public", + "make-public-asset-text": "AprÚs la confirmation, l'asset et toutes ses données seront rendus publics et accessibles aux autres.", + "make-public-asset-title": "Êtes-vous sûr de vouloir rendre l'actif '{{assetName}}' public '?", + "management": "Gestion d'actifs", + "name": "Nom", + "name-required": "Nom est requis.", + "name-starts-with": "Le nom de l'actif commence par", + "no-asset-types-matching": "Aucun type d'actif correspondant à {{entitySubtype}} n'a été trouvé. ", + "no-assets-matching": "Aucun actif correspondant à {{entity}} n'a été trouvé. ", + "no-assets-text": "Aucun actif trouvé", + "public": "Public", + "select-asset": "Sélectionner un actif", + "select-asset-type": "Sélectionner le type d'actif", + "type": "Type", + "type-required": "Le type est requis.", + "unassign-asset": "Retirer l'actif", + "unassign-asset-text": "AprÚs la confirmation, l'actif sera non attribué et ne sera pas accessible au client.", + "unassign-asset-title": "Êtes-vous sûr de vouloir retirer l'attribution de l'actif '{{assetName}}'?", + "unassign-assets": "Retirer les actifs", + "unassign-assets-action-title": "Retirer {count, plural, 1 {1 asset} other {# assets}} du client", + "unassign-assets-text": "AprÚs la confirmation, tous les actifs sélectionnés ne seront pas attribués et ne seront pas accessibles au client.", + "unassign-assets-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 asset} other {# assets}}?", + "unassign-from-customer": "Retirer du client", + "view-assets": "Afficher les actifs", + "label": "Label" + }, + "attribute": { + "add": "Ajouter un attribut", + "add-to-dashboard": "Ajouter au tableau de bord", + "add-widget-to-dashboard": "Ajouter un widget au tableau de bord", + "attributes": "Attributs", + "attributes-scope": "Étendue des attributs d'entité", + "delete-attributes": "Supprimer les attributs", + "delete-attributes-text": "Attention, aprÚs la confirmation, tous les attributs sélectionnés seront supprimés.", + "delete-attributes-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 attribut} other {# attributs}}?", + "enter-attribute-value": "Entrez la valeur de l'attribut", + "key": "Clé", + "key-required": "La Clé d'attribut est requise.", + "last-update-time": "DerniÚre mise à jour", + "latest-telemetry": "DerniÚre télémétrie", + "next-widget": "Widget suivant", + "prev-widget": "Widget précédent", + "scope-client": "Attributs du client", + "scope-latest-telemetry": "DerniÚre télémétrie", + "scope-server": "Attributs du serveur", + "scope-shared": "Attributs partagés", + "selected-attributes": "{count, plural, 1 {1 attribut} other {# attributs}} sélectionnés", + "selected-telemetry": "{count, plural, 1 {1 unité de télémétrie} other {# unités de télémétrie}} sélectionnées", + "show-on-widget": "Afficher sur le widget", + "value": "Valeur", + "value-required": "La valeur d'attribut est obligatoire.", + "widget-mode": "Mode du widget" + }, + "audit-log": { + "action-data": "Action data", + "audit": "Audit", + "audit-log-details": "Détails du journal d'audit", + "audit-logs": "Journaux d'audit", + "clear-search": "Effacer la recherche", + "details": "Détails", + "entity-name": "Nom de l'entité", + "entity-type": "Type d'entité", + "failure-details": "Détails de l'échec", + "no-audit-logs-prompt": "Aucun journal trouvé", + "search": "Rechercher les journaux d'audit", + "status": "État", + "status-failure": "Échec", + "status-success": "SuccÚs", + "timestamp": "Horodatage", + "type": "Type", + "type-activated": "Activé", + "type-added": "Ajouté", + "type-alarm-ack": "Acquitté", + "type-alarm-clear": "Effacé", + "type-assigned-to-customer": "Attribué au client", + "type-attributes-deleted": "Attributs supprimés", + "type-attributes-read": "Attributs lus", + "type-attributes-updated": "Attributs mis à jour", + "type-credentials-read": "Lecture des informations d'identification", + "type-credentials-updated": "Informations d'identification actualisées", + "type-deleted": "Supprimé", + "type-login": "Login", + "type-logout": "Connectez - Out", + "type-lockout": "Verrouillage", + "type-relation-add-or-update": "Relation mise à jour", + "type-relation-delete": "Relation supprimée", + "type-relations-delete": "Toutes les relations ont été supprimées", + "type-rpc-call": "Appel RPC", + "type-suspended": "Suspendu", + "type-unassigned-from-customer": "Non attribué du client", + "type-updated": "Mise à jour", + "user": "Utilisateur" + }, + "common": { + "enter-password": "Entrez le mot de passe", + "enter-search": "Entrez la recherche", + "enter-username": "Entrez le nom d'utilisateur", + "password": "Mot de passe", + "username": "Nom d'utilisateur" + }, + "confirm-on-exit": { + "html-message": "Vous avez des modifications non enregistrées.
Êtes-vous sûr de vouloir quitter cette page?", + "message": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter cette page?", + "title": "Modifications non enregistrées" + }, + "contact": { + "address": "Adresse", + "address2": "adresse 2", + "city": "Ville", + "country": "Pays", + "email": "Email", + "no-address": "Pas d'adresse", + "phone": "Téléphone", + "postal-code": "Code postal", + "postal-code-invalid": "Format de code postal / code postal invalide", + "state": "Province" + }, + "content-type": { + "binary": "Binaire (Base64)", + "json": "Json", + "text": "Texte" + }, + "custom": { + "widget-action": { + "action-cell-button": "Bouton de cellule d'action", + "marker-click": "Sur le marqueur cliquez", + "row-click": "Au rang, cliquez", + "polygon-click": "Cliquez sur le polygone", + "tooltip-tag-action": "Action de balise d'info-bulle", + "node-selected": "Sur le noeud sélectionné", + "element-click": "Sur l'élément HTML, cliquez sur", + "pie-slice-click": "Sur tranche cliquez", + "row-double-click": "Sur la ligne double clic" + } + }, + "customer": { + "add": "Ajouter un client", + "add-customer-text": "Ajouter un nouveau client", + "assets": "Actifs du client", + "copyId": "Copier l'id du client", + "customer": "Client", + "customer-details": "Détails du client", + "customer-required": "Le client est requis", + "customers": "Clients", + "dashboard": "Tableau de bord du client", + "dashboards": "tableaux de bord du client", + "default-customer": "Client par défaut", + "default-customer-required": "Le client par défaut est requis pour déboguer le tableau de bord au niveau du Tenant", + "delete": "Supprimer le client", + "delete-customer-text": "Faites attention, aprÚs la confirmation, le client et toutes les données associées deviendront irrécupérables.", + "delete-customer-title": "Êtes-vous sûr de vouloir supprimer le client '{{customerTitle}}'?", + "delete-customers-action-title": "Supprimer {count, plural, 1 {1 customer} other {# customers}}", + "delete-customers-text": "Faites attention, aprÚs la confirmation, tous les clients sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-customers-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 customer} other {# customers}}?", + "description": "Description", + "details": "Détails", + "devices": "Dispositifs du client", + "entity-views": "Vues de l'entité client", + "events": "Événements", + "idCopiedMessage": "L'Id du client a été copié dans le presse-papier", + "manage-assets": "Gérer les actifs", + "manage-customer-assets": "Gérer les actifs du client", + "manage-customer-dashboards": "Gérer les tableaux de bord du client", + "manage-customer-devices": "Gérer les dispositifs du client", + "manage-customer-users": "Gérer les utilisateurs du client", + "manage-dashboards": "Gérer les tableaux de bord", + "manage-devices": "Gérer les dispositifs", + "manage-public-assets": "Gérer les actifs publics", + "manage-public-dashboards": "Gérer les tableaux de bord publics", + "manage-public-devices": "Gérer les dispositifs publics", + "manage-users": "Gérer les utilisateurs", + "management": "Gestion des clients", + "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.", + "no-customers-text": "Aucun client trouvé", + "public-assets": "Actifs publics", + "public-dashboards": "Tableaux de bord publics", + "public-devices": "Dispositifs publics", + "public-entity-views": "Vues d'entités publiques", + "select-customer": "Sélectionner un client", + "select-default-customer": "Sélectionnez le client par défaut", + "title": "Titre", + "title-required": "Le titre est requis." + }, + "dashboard": { + "add": "Ajouter un tableau de bord", + "add-dashboard-text": "Ajouter un nouveau tableau de bord", + "add-state": "Ajouter un état du tableau de bord", + "add-widget": "Ajouter un nouveau widget", + "alias-resolution-error-title": "Erreur de configuration des alias de tableau de bord", + "assign-dashboard-to-customer": "Attribuer des tableaux de bord au client", + "assign-dashboard-to-customer-text": "Veuillez sélectionner les tableaux de bord à affecter au client", + "assign-dashboards": "Attribuer des tableaux de bord", + "assign-dashboards-text": "Attribuer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} aux clients", + "assign-new-dashboard": "Attribuer un nouveau tableau de bord", + "assign-to-customer": "Attribuer au client", + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les tableaux de bord", + "assign-to-customers": "Attribuer des tableaux de bord aux clients", + "assign-to-customers-text": "Veuillez sélectionner les clients pour attribuer les tableaux de bord", + "assigned-customers": "clients affectés", + "assignedToCustomer": "Attribué au client", + "assignedToCustomers": "attribué aux clients", + "autofill-height": "Hauteur de remplissage automatique", + "background-color": "Couleur de fond", + "background-image": "Image d'arriére-plan", + "background-size-mode": "Mode de taille d'arriére-plan", + "close-toolbar": "Fermer la barre d'outils", + "columns-count": "Nombre de colonnes", + "columns-count-required": "Le nombre de colonnes est requis.", + "configuration-error": "Erreur de configuration", + "copy-public-link": "Copier le lien public", + "create-new": "Créer un nouveau tableau de bord", + "create-new-dashboard": "Créer un nouveau tableau de bord", + "create-new-widget": "Créer un nouveau widget", + "dashboard": "Tableau de bord", + "dashboard-details": "Détails du tableau de bord", + "dashboard-file": "Fichier du tableau de bord", + "dashboard-import-missing-aliases-title": "Configurer les alias utilisés par le tableau de bord importé", + "dashboard-required": "Le tableau de bord est requis.", + "dashboards": "Tableaux de bord", + "delete": "Supprimer le tableau de bord", + "delete-dashboard-text": "Faites attention, aprÚs la confirmation, le tableau de bord et toutes les données associées deviendront irrécupérables.", + "delete-dashboard-title": "Êtes-vous sûr de vouloir supprimer le tableau de bord '{{dashboardTitle}}'?", + "delete-dashboards": "Supprimer les tableaux de bord", + "delete-dashboards-action-title": "Supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}", + "delete-dashboards-text": "Attention, aprÚs la confirmation, tous les tableaux de bord sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-dashboards-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?", + "delete-state": "Supprimer l'état du tableau de bord", + "delete-state-text": "Etes-vous sûr de vouloir supprimer l'état du tableau de bord avec le nom '{{stateName}}'?", + "delete-state-title": "Supprimer l'état du tableau de bord", + "description": "Description", + "details": "Détails", + "display-dashboard-export": "Afficher l'exportation", + "display-dashboard-timewindow": "Afficher fenêtre de temps", + "display-dashboards-selection": "Afficher la sélection des tableaux de bord", + "display-entities-selection": "Afficher la sélection des entités", + "display-title": "Afficher le titre du tableau de bord", + "drop-image": "Déposer une image ou cliquez pour sélectionner un fichier à télécharger.", + "edit-state": "Modifier l'état du tableau de bord", + "export": "Exporter le tableau de bord", + "export-failed-error": "Impossible d'exporter le tableau de bord: {{error}}", + "hide-details": "Masquer les détails", + "horizontal-margin": "Marge horizontale", + "horizontal-margin-required": "Une valeur de marge horizontale est requise.", + "import": "Importer le tableau de bord", + "import-widget": "Importer un widget", + "invalid-aliases-config": "Impossible de trouver des dispositifs correspondant à certains filtres d'alias.
Veuillez contacter votre administrateur pour résoudre ce problÚme.", + "invalid-dashboard-file-error": "Impossible d'importer le tableau de bord: structure de données du tableau de bord non valide", + "invalid-widget-file-error": "Impossible d'importer le widget: structure de données de widget invalide.", + "is-root-state": "État racine", + "make-private": "Rendre privé le tableau de bord", + "make-private-dashboard": "Rendre privé le tableau de bord", + "make-private-dashboard-text": "AprÚs la confirmation, le tableau de bord sera rendu privé et ne sera plus accessible aux autres.", + "make-private-dashboard-title": "Êtes-vous sûr de vouloir rendre le tableau de bord '{{dashboardTitle}}' privé?", + "make-public": "Rendre public le tableau de bord", + "manage-assigned-customers": "Gérer les clients affectés", + "manage-states": "Gérer les états du tableau de bord", + "management": "Gestion du tableau de bord", + "max-columns-count-message": "Seulement 1000 colonnes maximum sont autorisées.", + "max-horizontal-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge horizontale maximale.", + "max-mobile-row-height-message": "Seuls 200 pixels sont autorisés en tant que valeur maximale de hauteur de ligne mobile.", + "max-vertical-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge verticale maximale.", + "min-columns-count-message": "Seul un nombre minimum de 10 colonnes est autorisé.", + "min-horizontal-margin-message": "Seul 0 est autorisé comme valeur de marge horizontale minimale.", + "min-mobile-row-height-message": "Seuls 5 pixels sont autorisés en tant que valeur minimale de hauteur de ligne mobile.", + "min-vertical-margin-message": "Seul 0 est autorisé comme valeur de marge verticale minimale.", + "mobile-layout": "ParamÚtres de mise en page mobiles", + "mobile-row-height": "Hauteur de ligne mobile, px", + "mobile-row-height-required": "Une valeur de hauteur de ligne mobile est requise.", + "new-dashboard-title": "Nouveau titre du tableau de bord", + "no-dashboards-matching": "Aucun tableau de bord correspondant à {{entity}} n'a été trouvé. ", + "no-dashboards-text": "Aucun tableau de bord trouvé", + "no-image": "Aucune image sélectionnée", + "no-widgets": "Aucun widget configuré", + "open-dashboard": "Ouvrir le tableau de bord", + "open-toolbar": "Ouvrir la barre d'outils du tableau de bord", + "public": "Public", + "public-dashboard-notice": " Remarque: N'oubliez pas de rendre publics les dispositifs associés pour accéder à leurs données.", + "public-dashboard-text": "Votre tableau de bord {{dashboardTitle}} est maintenant public et accessible via le lien public : ", + "public-dashboard-title": "Le tableau de bord est maintenant public", + "public-link": "Lien public", + "public-link-copied-message": "Le lien public du tableau de bord a été copié dans le presse-papier", + "search-states": "Recherche des états du tableau de bord", + "select-dashboard": "Sélectionner le tableau de bord", + "select-devices": "Selectionner les dispositifs", + "select-existing": "Sélectionnez un tableau de bord existant", + "select-state": "Sélectionnez l'état cible", + "select-widget-subtitle": "Liste des types de widgets disponibles", + "select-widget-title": "Sélectionner un widget", + "selected-states": "{count, plural, 1 {1 état du tableau de bord} other {# états du tableau de bord}} sélectionnés", + "set-background": "Définir l'arriÚre-plan", + "settings": "ParamÚtres", + "show-details": "Afficher les détails", + "socialshare-text": "'{{dashboardTitle}}' propulsé par ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' propulsé par ThingsBoard", + "state": "État du tableau de bord", + "state-controller": "ContrÃŽleur d'état", + "state-id": "ID d'état", + "state-id-exists": "L'état du tableau de bord avec le même Id existe déjà.", + "state-id-required": "L'Id d'état du tableau de bord est requis.", + "state-name": "Nom", + "state-name-required": "Le nom de l'état du tableau de bord est requis", + "states": "États du tableau de bord", + "title": "Titre", + "title-color": "Couleur du titre", + "title-required": "Le titre est requis.", + "toolbar-always-open": "Garder la barre d'outils ouverte", + "unassign-dashboard": "Retirer le tableau de bord", + "unassign-dashboard-text": "AprÚs la confirmation, le tableau de bord ne sera pas attribué et ne sera pas accessible au client.", + "unassign-dashboard-title": "Êtes-vous sûr de vouloir annuler l'affectation du tableau de bord '{{dashboardTitle}}'?", + "unassign-dashboards": "Retirer les tableaux de bord", + "unassign-dashboards-action-text": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} des clients", + "unassign-dashboards-action-title": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} du client", + "unassign-dashboards-text": "AprÚs la confirmation, tous les tableaux de bord sélectionnés ne seront pas attribués et ne seront pas accessibles au client.", + "unassign-dashboards-title": "Etes-vous sûr de vouloir annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?", + "unassign-from-customer": "Retirer du client", + "unassign-from-customers": "Retirer les tableaux de bord des clients", + "unassign-from-customers-text": "Veuillez sélectionner les clients à annuler l'affectation du ou des tableaux de bord", + "vertical-margin": "Marge verticale", + "vertical-margin-required": "Une valeur de marge verticale est requise", + "view-dashboards": "Afficher les tableaux de bord", + "widget-file": "Fichier du Widget", + "widget-import-missing-aliases-title": "Configurer les alias utilisés par le widget importé", + "widgets-margins": "Marge entre les widgets" + }, + "datakey": { + "advanced": "Avancé", + "alarm": "Champs d'alarme", + "alarm-fields-required": "Les champs d'alarme sont obligatoires.", + "attributes": "Attributs", + "color": "Couleur", + "configuration": "Configuration de la clé de données", + "data-generation-func": "Fonction de génération de données", + "decimals": "Nombre de chiffres aprÚs virgule flottante", + "function-types": "Types de fonctions", + "function-types-required": "Les types de fonctions sont obligatoires", + "label": "Label", + "maximum-function-types": "Maximum {count, plural, 1 {1 type de fonction est autorisé.} other {# types de fonctions sont autorisés}}", + "maximum-timeseries-or-attributes": "Maximum {count, plural, 1 {1 timeseries / attribut est autorisé.} other {# timeseries / attributs sont autorisés}}", + "prev-orig-value-description": "valeur précédente d'origine;", + "prev-value-description": "résultat de l'appel de fonction précédent;", + "settings": "ParamÚtres", + "time-description": "horodatage de la valeur actuelle;", + "time-prev-description": "horodatage de la valeur précédente;", + "timeseries": "Timeseries", + "timeseries-or-attributes-required": "Les timeseries / attributs d'entité sont obligatoires.", + "timeseries-required": "Les Timeseries de l'entité sont obligatoires.", + "units": "Symbole spécial à afficher à cÃŽté de la valeur", + "use-data-post-processing-func": "Utiliser la fonction de post-traitement des données", + "value-description": "la valeur actuelle;" + }, + "datasource": { + "add-datasource-prompt": "Veuillez ajouter une source de données", + "name": "Nom", + "type": "Type de source de données" + }, + "datetime": { + "date-from": "Date de", + "date-to": "Date à", + "time-from": "Heure de", + "time-to": "Heure à" + }, + "details": { + "edit-mode": "Mode édition", + "toggle-edit-mode": "Activer le mode édition" + }, + "device": { + "access-token": "Jeton d'accÚs", + "access-token-invalid": "La longueur du jeton d'accÚs doit être comprise entre 1 et 20 caractéres.", + "access-token-required": "Le jeton d'accÚs est requis.", + "accessTokenCopiedMessage": "Le jeton d'accÚs au dispositif a été copié dans le presse-papier", + "add": "Ajouter un dispositif", + "add-alias": "Ajouter un alias de dispositif", + "add-device-text": "Ajouter un nouveau dispositif", + "alias": "Alias", + "alias-required": "Un alias du dispositif est requis.", + "aliases": "Alias des dispositifs", + "any-device": "N'importe quel dispositif", + "assign-device-to-customer": "Affecter des dispositifs au client", + "assign-device-to-customer-text": "Veuillez sélectionner les dispositif à affecter au client", + "assign-devices": "Attribuer des dispositifs", + "assign-devices-text": "Attribuer {count, plural, 1 {1 dispositif} other {# dispositifs}} au client", + "assign-new-device": "Attribuer un nouveau dispositif", + "assign-to-customer": "Attribuer au client", + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les dispositifs", + "assignedToCustomer": "Attribué au client", + "configure-alias": "Configurer '{{alias}}' alias", + "copyAccessToken": "Copier le jeton d'accÚs", + "copyId": "Copier l'Id du dispositif", + "create-new-alias": "Créez un nouveau!", + "create-new-key": "Créez un nouveau!", + "credentials": "Informations d'identification", + "credentials-type": "Type d'identification", + "delete": "Supprimer le dispositif", + "delete-device-text": "Faites attention, aprÚs la confirmation, le dispositif et toutes les données associées deviendront irrécupérables.", + "delete-device-title": "Êtes-vous sûr de vouloir supprimer le dispositif '{{deviceName}}'?", + "delete-devices": "Supprimer les dispositifs", + "delete-devices-action-title": "Supprimer {count, plural, 1 {1 device} other {# devices}}", + "delete-devices-text": "Faites attention, aprÚs la confirmation, tous les dispositifs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-devices-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 device} other {# devices}}?", + "description": "Description", + "details": "Détails", + "device": "Dispositif", + "device-alias": "Alias ​​du dispositif", + "device-credentials": "Informations d'identification du dispositif", + "device-details": "Détails du dispositif", + "device-list": "Liste des dispositifs", + "device-list-empty": "Aucun dispositif sélectionné.", + "device-name-filter-no-device-matched": "Aucun dispositif commençant par '{{device}} n'a été trouvé.", + "device-name-filter-required": "Le filtre de nom de dispositif est requis.", + "device-public": "Le dispositif est public", + "device-required": "Le dispositif est requis.", + "device-type": "Type de dispositif", + "device-type-list-empty": "Aucun type de dispositif sélectionné.", + "device-type-required": "Le type de dispositif est requis.", + "device-types": "Types de dispositif", + "devices": "Dispositifs", + "duplicate-alias-error": "Alias ??en double trouvé '{{alias}}'.
Les alias de dispositifs doivent être uniques dans le tableau de bord.", + "enter-device-type": "Entrez le type de dispositif", + "events": "Événements", + "idCopiedMessage": "l'Id du dispositif a été copié dans le presse-papiers", + "is-gateway": "Est une passerelle", + "label": "Label", + "make-private": "Rendre le dispositif privé", + "make-private-device-text": "AprÚs la confirmation, le dispositif et toutes ses données seront rendues privées et ne seront pas accessibles par d'autres.", + "make-private-device-title": "Êtes-vous sûr de vouloir rendre le dispositif {{deviceName}} privé?", + "make-public": "Rendre le dispositif public", + "make-public-device-text": "AprÚs la confirmation, le dispositif et toutes ses données seront rendus publics et accessibles par d'autres.", + "make-public-device-title": "Êtes-vous sûr de vouloir rendre le dispositif {{deviceName}} 'public?", + "manage-credentials": "Gérer les informations d'identification", + "management": "Gestion des dispositifs", + "name": "Nom", + "name-required": "Le nom est requis.", + "name-starts-with": "Le nom du dispositif commence par", + "no-alias-matching": "'{{alias}}' introuvable.", + "no-aliases-found": "Aucun alias trouvé.", + "no-device-types-matching": "Aucun type de dispositif correspondant à {{entitySubtype}} n'a été trouvé.", + "no-devices-matching": "Aucun dispositif correspondant à '{{entity}} n'a été trouvé.", + "no-devices-text": "Aucun dispositif trouvé", + "no-key-matching": "'{{key}}' introuvable.", + "no-keys-found": "Aucune clé trouvée", + "public": "Public", + "remove-alias": "Supprimer l'alias du dispositif", + "rsa-key": "Clé publique RSA", + "rsa-key-required": "La clé publique RSA est requise.", + "secret": "Secret", + "secret-required": "Code secret est requis.", + "select-device": "Selectionner un dispositif", + "select-device-type": "Sélectionner le type d'appareil", + "unable-delete-device-alias-text": "L'alias du dispositif '{{deviceAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", + "unable-delete-device-alias-title": "Impossible de supprimer l'alias du dispositif", + "unassign-device": "Annuler l'affectation du dispositif", + "unassign-device-text": "AprÚs la confirmation, le dispositif ne sera pas attribué et ne sera pas accessible au client.", + "unassign-device-title": "Êtes-vous sûr de vouloir annuler l'affection du dispositif {{deviceName}} '?", + "unassign-devices": "Annuler l'affectation des dispositifs", + "unassign-devices-action-title": "Annuler l'affectation de {count, plural, 1 {1 device} other {#devices}} du client", + "unassign-devices-text": "AprÚs la confirmation, tous les dispositifs sélectionnés ne seront pas attribues et ne seront pas accessibles par le client.", + "unassign-devices-title": "Voulez-vous vraiment annuler l'affectation de {count, plural, 1 {1 device} other {# devices}}?", + "unassign-from-customer": "Retirer du client", + "use-device-name-filter": "Utiliser le filtre", + "view-credentials": "Afficher les informations d'identification", + "view-devices": "Afficher les dispositifs" + }, + "dialog": { + "close": "Fermer le dialogue" + }, + "entity": { + "add-alias": "Ajouter un alias d'entité", + "alarm-name-starts-with": "Les actifs dont le nom commence par '{{prefix}}'", + "alias": "Alias", + "alias-required": "Un alias d'entité est requis.", + "aliases": "alias d'entité", + "all-subtypes": "Tout", + "any-entity": "Toute entité", + "asset-name-starts-with": "Les Assets dont le nom commence par '{{prefix}}'", + "columns-to-display": "Colonnes à afficher", + "configure-alias": "Configurer '{{alias}}' alias", + "create-new-alias": "Créez un nouveau!", + "create-new-key": "Créez un nouveau!", + "customer-name-starts-with": "Les clients dont les noms commencent par '{{prefix}}'", + "dashboard-name-starts-with": "Les tableaux de bord dont les noms commencent par '{{prefix}}'", + "details": "Détails de l'entité", + "device-name-starts-with": "Dispositifs dont le nom commence par '{{prefix}}'", + "duplicate-alias-error": "Alias ​​en double trouvé '{{alias}}'.
Les alias d'entité doivent être uniques dans le tableau de bord.", + "enter-entity-type": "Entrez le type d'entité", + "entities": "Entités", + "entity": "Entité", + "entity-alias": "Alias de l'entité", + "entity-list": "Liste d'entités", + "entity-list-empty": "Aucune entité sélectionnée.", + "entity-name": "Nom de l'entité", + "entity-name-filter-no-entity-matched": "Aucune entité commençant par '{{entity}}' n'a été trouvée.", + "entity-name-filter-required": "Le filtre de nom d'entité est requis.", + "entity-type": "Type d'entité", + "entity-type-list": "Liste de types d'entités", + "entity-type-list-empty": "Aucun type d'entité sélectionné.", + "entity-types": "Types d'entité", + "entity-view-name-starts-with": "Les vues d'entité dont le nom commence par '{{prefix}}'", + "key": "Clé", + "key-name": "Nom de la clé", + "list-of-alarms": "{count, plural, 1 {Une alarme} other {Liste de # alarmes}}", + "list-of-assets": "{count, plural, 1 {Un Asset} other {Liste de # Assets}}", + "list-of-customers": "{count, plural, 1 {Un client} other {Liste de # clients}}", + "list-of-dashboards": "{count, plural, 1 {Un tableau de bord} other {Liste de # tableaux de bord}}", + "list-of-devices": "{count, plural, 1 {Un dispositif} other {Liste de # dispositifs}}", + "list-of-plugins": "{count, plural, 1 {Un plugin} other {Liste de # plugins}}", + "list-of-rulechains": "{count, plural, 1 {Une chaîne de rÚgles} other {Liste de # chaînes de rÚgles}}", + "list-of-rulenodes": "{count, plural, 1 {Un noeud de rÚgles} other {Liste de # noeuds de rÚgles}}", + "list-of-rules": "{count, plural, 1 {Une rÚgle} other {Liste de # rÚgles}}", + "list-of-tenants": "{count, plural, 1 {Un tenant} other {Liste de # tenants}}", + "list-of-users": "{count, plural, 1 {Un utilisateur} other {Liste de # utilisateurs}}", + "missing-entity-filter-error": "Le filtre est manquant pour l'alias '{{alias}}'.", + "name-starts-with": "Nom commence par", + "no-alias-matching": "'{{alias}}' introuvable.", + "no-aliases-found": "Aucun alias trouvé.", + "no-data": "Aucune donnée à afficher", + "no-entities-matching": "Aucune entité correspondant à '{{entity}}' n'a été trouvée.", + "no-entities-prompt": "Aucune entité trouvée", + "no-entity-types-matching": "Aucun type d'entité correspondant à {{entityType}} n'a été trouvé. ", + "no-key-matching": "'{{key}}' introuvable.", + "no-keys-found": "Aucune clé trouvée", + "plugin-name-starts-with": "Plugins dont les noms commencent par '{{prefix}}'", + "remove-alias": "Supprimer l'alias d'entité", + "rule-name-starts-with": "Régles dont les noms commencent par '{{prefix}}'", + "rulechain-name-starts-with": "Chaînes de régles dont les noms commencent par '{{prefix}}'", + "rulenode-name-starts-with": "Les noeuds de régles dont le nom commence par '{{prefix}}'", + "search": "Recherche d'entités", + "select-entities": "Sélectionner des entités", + "selected-entities": "{count, plural, 1 {1 entité} other {# entités}} sélectionnées", + "tenant-name-starts-with": "Les Tenant dont le nom commence par '{{prefix}}'", + "type": "Type", + "type-alarm": "Alarme", + "type-alarms": "Alarmes", + "type-asset": "Actif", + "type-assets": "Actifs", + "type-current-customer": "Client actuel", + "type-customer": "Client", + "type-customers": "Clients", + "type-dashboard": "Tableau de bord", + "type-dashboards": "Tableaux de bord", + "type-device": "Dispositif", + "type-devices": "Dispositifs", + "type-entity-view": "Vue d'entité", + "type-entity-views": "Vues d'entités", + "type-plugin": "Plugin", + "type-plugins": "Plugins", + "type-required": "Le type d'entité est obligatoire.", + "type-rule": "Régle", + "type-rulechain": "Chaîne de régles", + "type-rulechains": "Chaînes de régles", + "type-rulenode": "Noeud de régle", + "type-rulenodes": "Noeuds de régle", + "type-rules": "Régles", + "type-tenant": "Tenant", + "type-tenants": "Tenants", + "type-user": "Utilisateur", + "type-users": "Utilisateurs", + "unable-delete-entity-alias-text": "L'alias d'entité '{{entityAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", + "unable-delete-entity-alias-title": "Impossible de supprimer l'alias d'entité", + "use-entity-name-filter": "Utiliser un filtre", + "user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'" + }, + "entity-field": { + "address": "Adresse", + "address2": "Adresse 2", + "city": "Ville", + "country": "Pays", + "created-time": "Heure de création", + "email": "Email", + "first-name": "Prénom", + "last-name": "Nom de famille", + "name": "Nom", + "phone": "Téléphone", + "state": "Prov", + "title": "Titre", + "type": "Type", + "zip": "Code postal" + }, + "entity-view": { + "add": "Ajouter une vue d'entité", + "add-alias": "Ajouter un alias de vue d'entité", + "add-entity-view-text": "Ajouter une nouvelle vue d'entité", + "alias": "Alias", + "alias-required": "Un alias de vue d'entité est requis.", + "aliases": "Alias de vue d'entité", + "any-entity-view": "Toute vue d'entité", + "assign-entity-view-to-customer": "Attribuer une (des) vue (s) d'entité à un client", + "assign-entity-view-to-customer-text": "Veuillez sélectionner les vues d'entité à affecter au client", + "assign-entity-views": "Attribuer des vues d'entité", + "assign-entity-views-text": "Attribuer { count, plural, 1 {1 entityView} other {# entityViews} } au client", + "assign-new-entity-view": "Attribuer une nouvelle vue d'entité", + "assign-to-customer": "Attribuer au client", + "assign-to-customer-text": "Veuillez sélectionner le client auquel attribuer la ou les vues d'entité.", + "assignedToCustomer": "Assigné au client", + "attributes-propagation": "Propagation des attributs", + "attributes-propagation-hint": "La vue d'entité copiera automatiquement les attributs spécifiés de l'entité cible chaque fois que vous enregistrez ou mettez à jour cette vue d'entité. Pour des raisons de performances, les attributs d'entité cible ne sont pas propagés à la vue d'entité à chaque changement d'attribut. Vous pouvez activer la propagation automatique en configurant le noeud de rÚgle \" copier pour afficher \" dans votre chaîne de rÚgles et en liant les messages \"Post attributs \" et \"attributs mis à jour \" au nouveau noeud de rÚgle.", + "client-attributes": "Attributs du client", + "client-attributes-placeholder": "Attributs du client", + "configure-alias": "Configurez l'alias '{{alias}}'", + "copyId": "Copier l'ID de la vue d'entité", + "create-new-alias": "Créer un nouveau!", + "create-new-key": "Créer un nouveau!", + "date-limits": "Limites de date", + "delete": "Supprimer la vue d'entité", + "delete-entity-view-text": "Attention, aprÚs la confirmation, la vue de l'entité et toutes les données associées deviendront irrécupérables.", + "delete-entity-view-title": "Êtes-vous sûr de vouloir supprimer la vue de l'entité '{{entityViewName}}'?", + "delete-entity-views": "Supprimer les vues d'entité", + "delete-entity-views-action-title": "Supprimer { count, plural, 1 {1 entityView} other {# entityViews} }", + "delete-entity-views-text": "Attention, aprÚs la confirmation, toutes les vues d'entité sélectionnées seront supprimées et toutes les données associées deviendront irrécupérables.", + "delete-entity-views-title": "Êtes-vous sûr de vouloir voir l'entité { count, plural, 1 {1 entityView} other {# entityViews} }?", + "description": "Description", + "details": "Détails", + "duplicate-alias-error": "Alias '{{alias}}' existe déjà.
Les alias de vue d'entité doivent être uniques dans le tableau de bord.", + "end-date": "Date de fin", + "end-ts": "Heure de fin", + "enter-entity-view-type": "Entrer le type de vue d'entité", + "entity-view": "Vue d'entité", + "entity-view-alias": "Alias de vue d'entité", + "entity-view-details": "Détails de la vue d'entité", + "entity-view-list": "Liste de vues d'entités", + "entity-view-list-empty": "Aucune vue d'entité sélectionnée.", + "entity-view-name-filter-no-entity-view-matched": "Aucune vue d'entité commençant par '{{entityView}}' n'a été trouvée.", + "entity-view-name-filter-required": "Un filtre de nom de vue d'entité est requis.", + "entity-view-required": "Une vue d'entité est requise.", + "entity-view-type": "Type de vue d'entité", + "entity-view-type-list-empty": "Aucun type de vue d'entité sélectionné.", + "entity-view-type-required": "Le type d'entité est requis.", + "entity-view-types": "Types de vues d'entité", + "entity-views": "Vues d'entité", + "events": "Événements", + "make-private": "Rendre la vue d'entité privée", + "make-private-entity-view-text": "AprÚs la confirmation, la vue de l'entité et toutes ses données seront rendues privées et ne seront pas accessibles par d'autres", + "make-private-entity-view-title": "Êtes-vous sûr de vouloir rendre la vue d'entité '{{entityViewName}}' privée?", + "make-public": "Rendre la vue d'entité publique", + "make-public-entity-view-text": "AprÚs la confirmation, la vue de l'entité et toutes ses données seront rendues publiques et accessibles à d'autres", + "make-public-entity-view-title": "Voulez-vous vraiment que la vue de l'entité '{{entityViewName}}' soit publique?", + "management": "Gestion de vue d'entité", + "name": "Nom", + "name-required": "Un nom est requis.", + "name-starts-with": "Le nom de la vue d'entité commence par", + "no-alias-matching": "'{{alias}}' non trouvé.", + "no-aliases-found": "Aucun alias trouvé.", + "no-entity-view-types-matching": "Aucun type de vue d'entité correspondant à '{{entitySubtype}}' n'a été trouvé.", + "no-entity-views-matching": "Aucune vue d'entité correspondant à '{{entity}}' n'a été trouvée.", + "no-entity-views-text": "Aucune vue d'entité trouvée.", + "no-key-matching": "'{{key}}' non trouvé.", + "no-keys-found": "Aucune clé trouvée.", + "remove-alias": "Supprimer un alias de vue d'entité", + "select-entity-view": "Sélectionner une vue d'entité", + "select-entity-view-type": "Sélectionner le type de vue d'entité", + "server-attributes": "Attributs du serveur", + "server-attributes-placeholder": "Attributs du serveur", + "shared-attributes": "Attributs partagés", + "shared-attributes-placeholder": "Attributs partagés", + "start-date": "Date de début", + "start-ts": "Heure de début", + "target-entity": "Entité cible", + "timeseries": "Séries chronologiques", + "timeseries-data": "Données de séries chronologiques", + "timeseries-data-hint": "Configurez les clés de données de séries chronologiques de l'entité cible qui seront accessibles à la vue de l'entité. Ces données temporelles sont en lecture seule.", + "timeseries-placeholder": "Séries chronologiques", + "unable-entity-view-device-alias-text": "L'alias de dispositif '{{entityViewAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants:
{{widgetsList}}", + "unable-entity-view-device-alias-title": "Impossible de supprimer l'alias de la vue d'entité.", + "unassign-entity-view": "Annuler l'affectation de la vue d'entité", + "unassign-entity-view-text": "AprÚs la confirmation, la vue de l'entité sera non attribuée et ne sera pas accessible par le client.", + "unassign-entity-view-title": "Voulez-vous vraiment annuler l'attribution de la vue d'entité '{{entityViewName}}'?", + "unassign-entity-views": "Annuler l'attribution des vues d'entité", + "unassign-entity-views-action-title": "Annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} } du client", + "unassign-entity-views-text": "AprÚs la confirmation, toutes les vues des entités sélectionnées seront non attribuées et ne seront pas accessibles par le client.", + "unassign-entity-views-title": "Êtes-vous sûr de vouloir annuler l'attribution { count, plural, 1 {1 entityView} other {# entityViews} }?", + "unassign-from-customer": "Annuler l'attribution au client", + "use-entity-view-name-filter": "Use filter", + "view-entity-views": "Voir les vues d'entité" + }, + "error": { + "unable-to-connect": "Impossible de se connecter au serveur! Veuillez vérifier votre connexion Internet.", + "unhandled-error-code": "Code d'erreur non géré: {{errorCode}}", + "unknown-error": "Erreur inconnue" + }, + "event": { + "alarm": "Alarme", + "body": "Corps", + "data": "Données", + "data-type": "Type de données", + "entity": "Entité", + "error": "erreur", + "errors-occurred": "Des erreurs sont survenues", + "event": "événement", + "event-time": "Heure de l'événement", + "event-type": "Type d'événement", + "failed": "Échec", + "message-id": "Message Id", + "message-type": "Type de message", + "messages-processed": "Messages traités", + "metadata": "Métadonnées", + "method": "Méthode", + "no-events-prompt": "Aucun événement trouvé", + "relation-type": "Type de relation", + "server": "Serveur", + "status": "État", + "success": "SuccÚs", + "type": "Type", + "type-debug-rule-chain": "Debug", + "type-debug-rule-node": "Debug", + "type-error": "Erreur", + "type-lc-event": "Evénement du cycle de vie", + "type-stats": "Statistiques" + }, + "extension": { + "add": "Ajouter une extension", + "add-attribute": "Ajouter un attribut", + "add-attribute-request": "Ajouter une demande d'attribut", + "add-attribute-update": "Ajouter une mise à jour d'attribut", + "add-broker": "Ajouter un Broker", + "add-config": "Ajouter une configuration de convertisseur", + "add-connect-request": "Ajouter une demande de connexion", + "add-converter": "Ajouter un convertisseur", + "add-device": "Ajouter un dispositif", + "add-disconnect-request": "Ajouter une demande de déconnexion", + "add-map": "Ajouter un élément de mappage", + "add-server-side-rpc-request": "Ajouter une requête RPC cÃŽté serveur", + "add-timeseries": "Ajouter des timeseries", + "anonymous": "Anonyme", + "attr-json-key-expression": "Expression json de la clé d'attribut", + "attr-topic-key-expression": "Expression du topic de la clé d'attribut", + "attribute-filter": "Filtre d'attribut", + "attribute-key-expression": "Expression de clé d'attribut", + "attribute-requests": "Demandes d'attributs", + "attribute-updates": "Mises à jour des attributs", + "attributes": "Attributs", + "basic": "Basic", + "brokers": "Brokers", + "ca-cert": "Fichier de certificat CA", + "cert": "Fichier de certificat *", + "client-scope": "Portée client", + "configuration": "Configuration", + "connect-requests": "Demandes de connexion", + "converter-configurations": "Configurations du convertisseur", + "converter-id": "ID du convertisseur", + "converter-json": "Json", + "converter-json-parse": "Impossible d'analyser le convertisseur json.", + "converter-json-required": "Le convertisseur json est requis.", + "converter-type": "Type de convertisseur", + "converters": "Convertisseurs", + "credentials": "Informations d'identification", + "custom": "Sur mesure", + "delete": "Supprimer l'extension", + "delete-extension-text": "Attention, aprÚs la confirmation, l'extension et toutes les données associées deviendront irrécupérables.", + "delete-extension-title": "Êtes-vous sûr de vouloir supprimer l'extension '{{extensionId}}'?", + "delete-extensions-text": "Attention, aprÚs la confirmation, toutes les extensions sélectionnées seront supprimées.", + "delete-extensions-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 extension} other {# extensions}}?", + "device-name-expression": "expression du nom du dispositif", + "device-name-filter": "Filtre de nom de dispositif", + "device-type-expression": "expression de type de dispositif", + "disconnect-requests": "Demandes de déconnection", + "drop-file": "Déposez un fichier ou cliquez pour sélectionner un fichier à télécharger.", + "edit": "Modifier l'extension", + "export-extension": "Exporter l'extension", + "export-extensions-configuration": "Exporter la configuration des extensions", + "extension-id": "Id de l'extension", + "extension-type": "Type d'extension", + "extensions": "Extensions", + "field-required": "Le champ est obligatoire", + "file": "Fichier d'extensions", + "filter-expression": "Expression du filtre", + "host": "HÃŽte", + "id": "Id", + "import-extension": "Importer une extension", + "import-extensions": "Importer des extensions", + "import-extensions-configuration": "Importer la configuration des extensions", + "invalid-file-error": "Fichier d'extension non valide", + "json-name-expression": "Expression json du nom du dispositif", + "json-parse": "Impossible d'analyser json transformer.", + "json-required": "Transformer json est requis.", + "json-type-expression": "Expression json du type de dispositif", + "key": "Clé", + "mapping": "Mappage", + "method-filter": "Filtre de méthode", + "modbus-add-server": "Ajouter serveur/esclave", + "modbus-add-server-prompt": "Veuillez ajouter serveur/esclave", + "modbus-attributes-poll-period": "Période d'interrogation des attributs (ms)", + "modbus-baudrate": "Débit en bauds", + "modbus-byte-order": "Ordre des octets", + "modbus-databits": "Bits de données", + "modbus-databits-range": "Les bits de données doivent être compris entre 7 et 8.", + "modbus-device-name": "Nom du dispositif", + "modbus-encoding": "Encodage", + "modbus-function": "Fonction", + "modbus-parity": "parité", + "modbus-poll-period": "Période d'interrogation (ms)", + "modbus-poll-period-range": "La période d'interrogation doit être une valeur positive.", + "modbus-port-name": "Nom du port série", + "modbus-register-address": "Adresse du registre", + "modbus-register-address-range": "L'adresse du registre doit être comprise entre 0 et 65535.", + "modbus-register-bit-index": "Bit index", + "modbus-register-bit-index-range": "L'index de bit doit être compris entre 0 et 15.", + "modbus-register-count": "Nombre de registre", + "modbus-register-count-range": "Le nombre de registres doit être une valeur positive.", + "modbus-server": "Serveurs / esclaves", + "modbus-stopbits": "Bits d'arrêt", + "modbus-stopbits-range": "Les bits d'arrêt doivent être compris entre 1 et 2.", + "modbus-tag": "Tag", + "modbus-timeseries-poll-period": "Période d'interrogation des Timeseries (ms)", + "modbus-transport": "Transport", + "modbus-unit-id": "Id de l'unité", + "modbus-unit-id-range": "L'ID de l'unité doit être compris entre 1 et 247.", + "no-file": "Aucun fichier sélectionné.", + "opc-add-server": "Ajouter un serveur", + "opc-add-server-prompt": "Veuillez ajouter un serveur", + "opc-application-name": "Nom de l'application", + "opc-application-uri": "Uri de l'application", + "opc-device-name-pattern": "modÚle de nom du dispositif", + "opc-device-node-pattern": "modÚle de noeud de dispositif", + "opc-identity": "Identité", + "opc-keystore": "Magasin de clés", + "opc-keystore-alias": "Alias", + "opc-keystore-key-password": "Mot de passe de la clé", + "opc-keystore-location": "Emplacement *", + "opc-keystore-password": "Mot de passe", + "opc-keystore-type": "Type", + "opc-scan-period-in-seconds": "Période d'analyse en secondes", + "opc-security": "Sécurité", + "opc-server": "Serveurs", + "opc-type": "Type", + "password": "Mot de passe", + "pem": "PEM", + "port": "Port", + "port-range": "Le port doit être compris entre 1 et 65535.", + "private-key": "Fichier de clé privée *", + "request-id-expression": "Expression de demande d'id", + "request-id-json-expression": "Expression json de la demande d'id", + "request-id-topic-expression": "Expression de la demande d'id du topic", + "request-topic-expression": "Expression de la demande du topic", + "response-timeout": "Délai de réponse en millisecondes", + "response-topic-expression": "Expression du topic de la réponse", + "retry-interval": "Intervalle de nouvelle tentative en millisecondes", + "selected-extensions": "{count, plural, 1 {1 extension} other {# extensions}} sélectionné", + "server-side-rpc": "RPC cÃŽté serveur", + "ssl": "Ssl", + "sync": { + "last-sync-time": "DerniÚre heure de synchronisation", + "not-available": "Non disponible", + "not-sync": "Non sync", + "status": "Status", + "sync": "Sync" + }, + "timeout": "Délai d'attente en millisecondes", + "timeseries": "Timeseries", + "to-double": "Au double", + "token": "Jeton de sécurité", + "topic": "Topic", + "topic-expression": "Expression du topic", + "topic-filter": "Filtre du topic", + "topic-name-expression": "Expression du nom du dispositif (topic)", + "topic-type-expression": "Expression de type de dispositif (topic)", + "transformer": "Transformer", + "transformer-json": "JSON *", + "type": "Type", + "unique-id-required": "L'identifiant d'extension actuel existe déjà.", + "username": "Nom d'utilisateur", + "value": "Valeur", + "value-expression": "Expression de la valeur" + }, + "fullscreen": { + "exit": "Quitter le plein écran", + "expand": "Afficher en plein écran", + "fullscreen": "Plein écran", + "toggle": "Activer le mode plein écran" + }, + "function": { + "function": "Fonction" + }, + "grid": { + "add-item-text": "Ajouter un nouvel élément", + "delete-item": "Supprimer l'élément", + "delete-item-text": "Faites attention, aprÚs la confirmation, cet élément et toutes les données associées deviendront irrécupérables.", + "delete-item-title": "Êtes-vous sûr de vouloir supprimer cet élément?", + "delete-items": "Supprimer les éléments", + "delete-items-action-title": "Supprimer {count, plural, 1 {1 élément} other {# éléments}}", + "delete-items-text": "Attention, aprÚs la confirmation, tous les éléments sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-items-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 élément} other {# éléments}}?", + "item-details": "Détails de l'élément", + "no-items-text": "Aucun élément trouvé", + "scroll-to-top": "Défiler vers le haut" + }, + "help": { + "goto-help-page": "Aller à la page d'aide" + }, + "home": { + "avatar": "Avatar", + "home": "Accueil", + "logout": "Déconnexion", + "menu": "Menu", + "open-user-menu": "Ouvrir le menu utilisateur", + "profile": "Profile" + }, + "icon": { + "icon": "IcÃŽne", + "material-icons": "IcÃŽnes matérielles", + "select-icon": "Sélectionner l'icÃŽne", + "show-all": "Afficher toutes les icÃŽnes" + }, + "import": { + "drop-file": "Déposez un fichier JSON ou cliquez pour sélectionner un fichier à télécharger.", + "no-file": "Aucun fichier sélectionné" + }, + "item": { + "selected": "Sélectionné" + }, + "js-func": { + "no-return-error": "La fonction doit renvoyer une valeur!", + "return-type-mismatch": "La fonction doit renvoyer une valeur de type '{{type}}' !", + "tidy": "Nettoyer" + }, + "key-val": { + "add-entry": "Ajouter une entrée", + "key": "Clé", + "no-data": "Aucune entrée", + "remove-entry": "Supprimer l'entrée", + "value": "Valeur" + }, + "language": { + "language": "Language", + "locales": { + "de_DE": "Allemand", + "en_US": "Anglais", + "fr_FR": "Français", + "es_ES": "Espagnol", + "it_IT": "Italien", + "ko_KR": "Coréen", + "ru_RU": "Russe", + "zh_CN": "Chinois", + "ja_JA": "Japonaise", + "tr_TR": "Turc", + "fa_IR": "Persane", + "uk_UA": "Ukrainien", + "cs_CZ": "TchÚque", + "el_GR": "Grec", + "lv_LV": "Letton" + } + }, + "layout": { + "color": "Couleur", + "layout": "Mise en page", + "main": "Principal", + "manage": "Gérer les mises en page", + "right": "Droite", + "select": "Sélectionner la mise en page cible", + "settings": "ParamÚtres de mise en page" + }, + "legend": { + "avg": "moy", + "max": "max", + "min": "min", + "position": "Position de la légende", + "settings": "ParamÚtres de la légende", + "show-avg": "Afficher la valeur moyenne", + "show-max": "Afficher la valeur maximale", + "show-min": "Afficher la valeur min", + "show-total": "Afficher la valeur totale", + "total": "total" + }, + "login": { + "create-password": "Créer un mot de passe", + "email": "Email", + "forgot-password": "Mot de passe oublié?", + "login": "Login", + "new-password": "Nouveau mot de passe", + "new-password-again": "nouveau mot de passe", + "password-again": "Mot de passe à nouveau", + "password-link-sent-message": "Le lien de réinitialisation du mot de passe a été envoyé avec succÚs!", + "password-reset": "Mot de passe réinitialisé", + "passwords-mismatch-error": "Les mots de passe saisis doivent être identiques!", + "remember-me": "Se souvenir de moi", + "request-password-reset": "Demander la réinitialisation du mot de passe", + "reset-password": "Réinitialiser le mot de passe", + "sign-in": "Veuillez vous connecter", + "username": "Nom d'utilisateur (courriel)" + }, + "position": { + "bottom": "Bas", + "left": "Gauche", + "right": "Droite", + "top": "Haut" + }, + "profile": { + "change-password": "Modifier le mot de passe", + "current-password": "Mot de passe actuel", + "last-login-time": "DerniÚre connexion", + "profile": "Profile" + }, + "relation": { + "add": "Ajouter une relation", + "add-relation-filter": "Ajouter un filtre de relation", + "additional-info": "Informations supplémentaires (JSON)", + "any-relation": "toute relation", + "any-relation-type": "N'importe quel type", + "delete": "Supprimer la relation", + "delete-from-relation-text": "Attention, aprÚs la confirmation, l'entité actuelle ne sera pas liée à l'entité '{{entityName}}'.", + "delete-from-relation-title": "Êtes-vous sûr de vouloir supprimer la relation de l'entité '{{entityName}}'?", + "delete-from-relations-text": "Attention, aprÚs la confirmation, toutes les relations sélectionnées seront supprimées et l'entité actuelle ne sera pas liée aux entités correspondantes.", + "delete-from-relations-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?", + "delete-to-relation-text": "Attention, aprÚs la confirmation, l'entité '{{entityName}} ne sera plus liée à l'entité actuelle.", + "delete-to-relation-title": "Êtes-vous sûr de vouloir supprimer la relation avec l'entité '{{entityName}}'?", + "delete-to-relations-text": "Attention, aprÚs la confirmation, toutes les relations sélectionnées seront supprimées et les entités correspondantes ne seront pas liées à l'entité en cours.", + "delete-to-relations-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?", + "direction": "Sens", + "direction-type": { + "FROM": "de", + "TO": "à" + }, + "edit": "Modifier la relation", + "from-entity": "De l'entité", + "from-entity-name": "Du nom d'entité", + "from-entity-type": "Du type d'entité", + "from-relations": "Relations sortantes", + "invalid-additional-info": "Impossible d'analyser les informations supplémentaires json.", + "relation-filters": "Filtres de relation", + "relation-type": "Type de relation", + "relation-type-required": "Le type de relation est requis.", + "relations": "Relations", + "remove-relation-filter": "Supprimer le filtre de relation", + "search-direction": { + "FROM": "De", + "TO": "Vers" + }, + "selected-relations": "{count, plural, 1 {1 relation} other {# relations}} sélectionné", + "to-entity": "Vers l'entité", + "to-entity-name": "vers le nom de l'entité", + "to-entity-type": "Vers le type d'entité", + "to-relations": "Relations entrantes", + "type": "Type" + }, + "rulechain": { + "add": "Ajouter une chaîne de rÚgles", + "add-rulechain-text": "Ajouter une nouvelle chaîne de rÚgles", + "copyId": "Copier l'identifiant de la chaîne de rÚgles", + "create-new-rulechain": "Créer une nouvelle chaîne de rÚgles", + "debug-mode": "Mode de débogage", + "delete": "Supprimer la chaîne de rÚgles", + "delete-rulechain-text": "Attention, aprÚs la confirmation, la chaîne de rÚgles et toutes les données associées deviendront irrécupérables.", + "delete-rulechain-title": "Voulez-vous vraiment supprimer la chaîne de rÚgles '{{ruleChainName}}'?", + "delete-rulechains-action-title": "Supprimer {count, plural, 1 {1 chaîne de rÚgles} other {# chaînes de rÚgles}}", + "delete-rulechains-text": "Attention, aprÚs la confirmation, toutes les chaînes de rÚgles sélectionnées seront supprimées et toutes les données associées deviendront irrécupérables.", + "delete-rulechains-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 chaîne de rÚgles} other {# chaînes de rÚgles}}?", + "description": "Description", + "details": "Détails", + "events": "Evénements", + "export": "Exporter la chaîne de rÚgles", + "export-failed-error": "Impossible d'exporter la chaîne de rÚgles: {{error}}", + "idCopiedMessage": "L'ID de la chaîne de rÚgles a été copié dans le presse-papier", + "import": "Importer la chaîne de rÚgles", + "invalid-rulechain-file-error": "Impossible d'importer la chaîne de rÚgles: structure de données de la chaîne de rÚgles non valide", + "management": "Gestion des rÚgles", + "name": "Nom", + "name-required": "Le nom est requis.", + "no-rulechains-matching": "Aucune chaîne de rÚgles correspondant à {{entity}} n'a été trouvée.", + "no-rulechains-text": "Aucune chaîne de rÚgles trouvée", + "root": "Racine", + "rulechain": "Chaîne de rÚgles", + "rulechain-details": "Détails de la chaîne de rÚgles", + "rulechain-file": "Fichier de chaîne de rÚgles", + "rulechain-required": "Chaîne de rÚgles requise", + "rulechains": "Chaînes de rÚgles", + "select-rulechain": "Sélectionner la chaîne de rÚgles", + "set-root": "Rend la chaîne de rÚgles racine (root) ", + "set-root-rulechain-text": "AprÚs la confirmation, la chaîne de rÚgles deviendra racine (root) et gérera tous les messages de transport entrants.", + "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de rÚgles '{{ruleChainName}} soit racine (root) ?", + "system": "SystÚme" + }, + "rulenode": { + "add": "Ajouter un noeud de rÚgle", + "add-link": "Ajouter un lien", + "configuration": "Configuration", + "copy-selected": "Copier les éléments sélectionnés", + "create-new-link-label": "Créez un nouveau!", + "custom-link-label": "Etiquette de lien personnalisée", + "custom-link-label-required": "Une étiquette de lien personnalisée est requise", + "debug-mode": "Mode de débogage", + "delete": "Supprimer le noeud de rÚgle", + "delete-selected": "Supprimer les éléments sélectionnés", + "delete-selected-objects": "Supprimer les nœuds et les connexions sélectionnés", + "description": "Description", + "deselect-all": "Désélectionner tout", + "deselect-all-objects": "Désélectionnez tous les nœuds et toutes les connexions", + "details": "Détails", + "directive-is-not-loaded": "La directive de configuration définie '{{directiveName}} n'est pas disponible.", + "events": "Événements", + "help": "Aide", + "invalid-target-rulechain": "Impossible de résoudre la chaîne de rÚgles cible!", + "link": "Lien", + "link-details": "Détails du lien du noeud de la rÚgle", + "link-label": "Étiquette du lien", + "link-label-required": "L'étiquette du lien est obligatoire", + "link-labels": "Étiquettes de lien", + "link-labels-required": "Les étiquettes de lien sont obligatoires", + "message": "Message", + "message-type": "Type de message", + "message-type-required": "Le type de message est obligatoire", + "metadata": "Métadonnées", + "metadata-required": "Les entrées de métadonnées ne peuvent pas être vides.", + "name": "Nom", + "name-required": "Le nom est requis.", + "no-link-label-matching": "'{{label}}' introuvable.", + "no-link-labels-found": "Aucune étiquette de lien trouvée", + "open-node-library": "Ouvrir la bibliothÚque de noeud", + "output": "Output", + "rulenode-details": "Détails du noeud de la régle", + "search": "Recherche de noeuds", + "select-all": "Tout sélectionner", + "select-all-objects": "Sélectionnez tous les noeuds et connexions", + "select-message-type": "Sélectionner le type de message", + "test": "Test", + "test-script-function": "Tester le script", + "type": "Type", + "type-action": "Action", + "type-action-details": "Effectuer une action spéciale", + "type-enrichment": "Enrichissement", + "type-enrichment-details": "Ajouter des informations supplémentaires dans les métadonnées de message", + "type-external": "Externe", + "type-external-details": "Interagit avec le systéme externe", + "type-filter": "Filtre", + "type-filter-details": "Filtrer les messages entrants avec des conditions configurées", + "type-input": "Input", + "type-input-details": "Entrée logique de la chaîne de rÚgles, transmet les messages entrants au prochain nœud de rÚgle associé", + "type-rule-chain": "Chaîne de régles", + "type-rule-chain-details": "Transmet les messages entrants à la chaîne de régles spécifiée", + "type-transformation": "Transformation", + "type-transformation-details": "Modifier le payload du message et les métadonnées ", + "type-unknown": "Inconnu", + "type-unknown-details": "Noeud de rÚgle non résolu", + "ui-resources-load-error": "Impossible de charger les ressources de configuration de l'interface utilisateur." + }, + "tenant": { + "add": "Ajouter un Tenant", + "add-tenant-text": "Ajouter un nouveau Tenant", + "admins": "Admins", + "copyId": "Copier l'Id du Tenant", + "delete": "Supprimer le Tenant", + "delete-tenant-text": "Attention, aprÚs la confirmation, le Tenant et toutes les données associées deviendront irrécupérables.", + "delete-tenant-title": "Êtes-vous sûr de vouloir supprimer le tenant '{{tenantTitle}}'?", + "delete-tenants-action-title": "Supprimer {count, plural, 1 {1 tenant} other {# tenants}}", + "delete-tenants-text": "Attention, aprÚs la confirmation, tous les Tenants sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-tenants-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 tenant} other {# tenants}}?", + "description": "Description", + "details": "Détails", + "events": "Événements", + "idCopiedMessage": "L'Id du Tenant a été copié dans le Presse-papiers", + "manage-tenant-admins": "Gérer les administrateurs du Tenant", + "management": "Gestion des Tenants", + "no-tenants-matching": "Aucun Tenant correspondant à {{entity}} n'a été trouvé. ", + "no-tenants-text": "Aucun Tenant trouvé", + "select-tenant": "Sélectionner un Tenant", + "tenant": "Tenant", + "tenant-details": "Détails du Tenant", + "tenant-required": "Tenant requis", + "tenants": "Tenants", + "title": "Titre", + "title-required": "Le titre est requis." + }, + "timeinterval": { + "advanced": "Avancé", + "days": "Jours", + "days-interval": "{days, plural, 1 {1 jour} other {# jours}}", + "hours": "Heures", + "hours-interval": "{hours, plural, 1 {1 heure} other {# heures}}", + "minutes": "Minutes", + "minutes-interval": "{minutes, plural, 1 {1 minute} other {# minutes}}", + "seconds": "Secondes", + "seconds-interval": "{seconds, plural, 1 {1 seconde} other {# secondes}}" + }, + "timewindow": { + "date-range": "Plage de dates", + "days": "{days, plural, 1 {jour} other {# jours}}", + "edit": "Modifier timewindow", + "history": "Historique", + "hours": "{hours, plural, 0 {heure} 1 {1 heure} other {# heures}}", + "last": "Dernier", + "last-prefix": "dernier", + "minutes": "{minutes, plural, 0 {minute} 1 {1 minute} other {# minutes}}", + "period": "de {{startTime}} à {{endTime}}", + "realtime": "Temps réel", + "seconds": "{seconds, plural, 0 {second} 1 {1 second} other {# seconds}}", + "time-period": "Période", + "hide": "Masquer" + }, + "user": { + "activation-email-sent-message": "Le courriel d'activation a été envoyé avec succÚs!", + "activation-link": "Lien d'activation utilisateur", + "activation-link-copied-message": "le lien d'activation de l'utilisateur a été copié dans le presse-papier", + "activation-link-text": "Pour activer l'utilisateur, utilisez le lien d'activation suivant: ", + "activation-method": "Méthode d'activation", + "add": "Ajouter un utilisateur", + "add-user-text": "Ajouter un nouvel utilisateur", + "always-fullscreen": "Toujours en plein écran", + "anonymous": "Anonyme", + "copy-activation-link": "Copier le lien d'activation", + "customer": "Client", + "customer-users": "Utilisateurs du client", + "default-dashboard": "Tableau de bord par défaut", + "delete": "Supprimer l'utilisateur", + "delete-user-text": "Attention, aprÚs la confirmation, l'utilisateur et toutes les données associées deviendront irrécupérables.", + "delete-user-title": "Êtes-vous sûr de vouloir supprimer l'utilisateur '{{userEmail}}'?", + "delete-users-action-title": "Supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}", + "delete-users-text": "Attention, aprÚs la confirmation, tous les utilisateurs sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-users-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}?", + "description": "Description", + "details": "Détails", + "disable-account": "Désactiver le compte d'utilisateur", + "disable-account-message": "Le compte d'utilisateur a été désactivé avec succÚs!", + "display-activation-link": "Afficher le lien d'activation", + "email": "Email", + "email-required": "Email est requis.", + "enable-account": "Activer le compte d'utilisateur", + "enable-account-message": "Le compte d'utilisateur a été activé avec succÚs!", + "first-name": "Prénom", + "invalid-email-format": "Format de courrier électronique non valide", + "last-name": "Nom de famille", + "login-as-customer-user": "Se connecter en tant qu'utilisateur client", + "login-as-tenant-admin": "Connectez-vous en tant qu'administrateur Tenant", + "no-users-matching": "Aucun utilisateur correspondant à '{{entity}}' n'a été trouvé.", + "no-users-text": "Aucun utilisateur trouvé", + "resend-activation": "Renvoyer l'activation", + "select-user": "Sélectionner l'utilisateur", + "send-activation-mail": "Envoyer un mail d'activation", + "sys-admin": "Administrateur du systÚme", + "tenant-admin": "Administrateur du Tenant", + "tenant-admins": "administrateurs du Tenant", + "user": "utilisateur", + "user-details": "Détails de l'utilisateur", + "user-required": "L'utilisateur est requis", + "users": "Utilisateurs" + }, + "value": { + "boolean": "booléen", + "boolean-value": "Valeur booléenne", + "double": "Double", + "double-value": "Valeur double", + "false": "Faux", + "integer": "Entier", + "integer-value": "Valeur entiÚre", + "invalid-integer-value": "Valeur entiÚre invalide", + "long": "Long", + "string": "String", + "string-value": "Valeur String", + "true": "Vrai", + "type": "Type de valeur" + }, + "widget": { + "add": "Ajouter un widget", + "add-resource": "Ajouter une ressource", + "add-widget-type": "Ajouter un nouveau type de widget", + "alarm": "Widget d'alarme", + "css": "CSS", + "datakey-settings-schema": "Schéma des paramÚtres de Data key", + "edit": "Modifier le widget", + "editor": " Editeur de widget", + "export": "Exporter widget", + "html": "HTML", + "javascript": "Javascript", + "latest-values": "DerniÚres valeurs", + "management": "Gestion des widgets", + "missing-widget-title-error": "Le titre du widget doit être spécifié!", + "no-data-found": "Aucune donnée trouvée", + "remove": "Supprimer le widget", + "remove-resource": "Supprimer une ressource", + "remove-widget-text": "AprÚs la confirmation, le widget et toutes les données associées deviendront irrécupérables.", + "remove-widget-title": "Êtes-vous sûr de vouloir supprimer le widget '{{widgetTitle}}'?", + "remove-widget-type": "Supprimer le type de widget", + "remove-widget-type-text": "AprÚs la confirmation, le type de widget et toutes les données associées deviendront irrécupérables.", + "remove-widget-type-title": "Êtes-vous sûr de vouloir supprimer le type de widget '{{widgetName}}'?", + "resource-url": "URL JavaScript / CSS", + "resources": "Ressources", + "rpc": "Widget de contrÃŽle", + "run": "Exécuter un widget", + "save": "Enregistrer le widget", + "save-widget-type-as": "Enregistrer le type de widget sous", + "save-widget-type-as-text": "Veuillez saisir un nouveau titre de widget et / ou sélectionner un ensemble de widgets cibles", + "saveAs": "Enregistrer le widget sous", + "search-data": "Rechercher des données", + "select-widget-type": "Sélectionnez le type de widget", + "select-widgets-bundle": "Sélectionner un ensemble de widgets", + "settings-schema": "Schéma des paramétres", + "static": "Widget statique", + "tidy": "Nettoyer", + "timeseries": "Séries chronologiques", + "title": "Titre du widget", + "title-required": "Le titre du widget est requis.", + "toggle-fullscreen": "Basculer le mode plein écran", + "type": "Type de widget", + "unable-to-save-widget-error": "Impossible de sauvegarder le widget! Le widget a des erreurs!", + "undo": "Annuler les modifications du widget", + "widget-bundle": "Ensemble de widget", + "widget-library": "BibliothÚque de widgets", + "widget-saved": "Widget enregistré", + "widget-template-load-failed-error": "Impossible de charger le modéle de widget!", + "widget-type-load-error": "Le widget n'a pas été chargé à cause des erreurs suivantes:", + "widget-type-load-failed-error": "Impossible de charger le type de widget!", + "widget-type-not-found": "ProblÚme de chargement de la configuration du widget.
Le type de widget associé a probablement été supprimé." + }, + "widget-action": { + "custom": "Action personnalisée", + "header-button": "Bouton d'en-tête de widget", + "open-dashboard": "Naviguer vers un autre tableau de bord", + "open-dashboard-state": "Naviguer vers un nouvel état du tableau de bord", + "open-right-layout": "Ouvrir la disposition du tableau de bord droite (vue mobile)", + "set-entity-from-widget": "Définir l'entité à partir du widget", + "target-dashboard": "Tableau de bord cible", + "target-dashboard-state": "État du tableau de bord cible", + "target-dashboard-state-required": "L'état du tableau de bord cible est requis", + "update-dashboard-state": "Mettre à jour l'état actuel du tableau de bord" + }, + "widget-config": { + "action": "Action", + "action-icon": "IcÃŽne", + "action-name": "Nom", + "action-name-not-unique": "Une autre action portant le même nom existe déjà.
Le nom de l'action doit être unique dans la même source d'action.", + "action-name-required": "Le nom de l'action est requis", + "action-source": "Source de l'action", + "action-source-required": "Une source d'action est requise.", + "action-type": "Type", + "action-type-required": "Le type d'action est requis.", + "actions": "Actions", + "add-action": "Ajouter une action", + "add-datasource": "Ajouter une source de données", + "advanced": "Avancé", + "alarm-source": "Source d'alarme", + "background-color": "couleur de fond", + "data": "Données", + "datasource-parameters": "ParamÚtres", + "datasource-type": "Type", + "datasources": "Sources de données", + "decimals": "Nombre de chiffres aprÚs virgule flottante", + "delete-action": "Supprimer l'action", + "delete-action-text": "Êtes-vous sûr de vouloir supprimer l'action du widget nommé '{{actionName}}'?", + "delete-action-title": "Supprimer l'action du widget", + "display-timewindow": "Afficher fenêtre de temps", + "display-legend": "Afficher la légende", + "display-title": "Afficher le titre", + "drop-shadow": "Ombre portée", + "edit-action": "Modifier l'action", + "enable-fullscreen": "Activer le plein écran", + "general-settings": "ParamÚtres généraux", + "height": "Hauteur", + "margin": "Marge", + "maximum-datasources": "Maximum {count, plural, 1 {1 datasource est autorisé.} other {# datasources sont autorisés}}", + "mobile-mode-settings": "ParamÚtres du mode mobile", + "order": "Ordre", + "padding": "Padding", + "remove-datasource": "Supprimer la source de données", + "search-actions": "Recherche d'actions", + "settings": "ParamÚtres", + "target-device": "Dispositif cible", + "text-color": "Couleur du texte", + "timewindow": "Fenêtre de temps", + "title": "Titre", + "title-style": "Style de titre", + "title-tooltip": "Tooltip de titre", + "units": "Symbole spécial à afficher à cÃŽté de la valeur", + "use-dashboard-timewindow": "Utiliser la fenêtre de temps du tableau de bord", + "widget-style": "Style du widget", + "display-icon": "Afficher l'icÃŽne du titre", + "icon-color": "Couleur de l'icÃŽne", + "icon-size": "Taille de l'icÃŽne" + }, + "widget-type": { + "create-new-widget-type": "Créer un nouveau type de widget", + "export": "Exporter le type de widget", + "export-failed-error": "Impossible d'exporter le type de widget: {{error}}", + "import": "Importer le type de widget", + "invalid-widget-type-file-error": "Impossible d'importer le type de widget: structure de données de type widget invalide.", + "widget-type-file": "Fichier de type Widget" + }, + "widgets": { + "date-range-navigator": { + "localizationMap": { + "Sun": "Dim.", + "Mon": "Lun.", + "Tue": "Mar.", + "Wed": "Mer.", + "Thu": "Jeu.", + "Fri": "Ven.", + "Sat": "Sam.", + "Jan": "Janv.", + "Feb": "Févr.", + "Mar": "Mars", + "Apr": "Avr.", + "May": "Mai", + "Jun": "Juin", + "Jul": "Juil.", + "Aug": "Août", + "Sep": "Sept.", + "Oct": "Oct.", + "Nov": "Nov.", + "Dec": "Déc.", + "January": "Janvier", + "February": "Février", + "March": "Mars", + "April": "Avril", + "June": "Juin", + "July": "Juillet", + "August": "Août", + "September": "Septembre", + "October": "Octobre", + "November": "Novembre", + "December": "Décembre", + "Custom Date Range": "Plage de dates personnalisée", + "Date Range Template": "ModÚle de plage de dates", + "Today": "Aujourd'hui", + "Yesterday": "Hier", + "This Week": "Cette semaine", + "Last Week": "La semaine derniÚre", + "This Month": "Ce mois-ci", + "Last Month": "Le mois dernier", + "Year": "Année", + "This Year": "Cette année", + "Last Year": "L'année derniÚre", + "Date picker": "Sélecteur de date", + "Hour": "Heure", + "Day": "Journée", + "Week": "La semaine", + "2 weeks": "2 Semaines", + "Month": "Mois", + "3 months": "3 Mois", + "6 months": "6 Mois", + "Custom interval": "Intervalle personnalisé", + "Interval": "Intervalle", + "Step size": "Taille de pas", + "Ok": "Ok" + } + }, + "input-widgets": { + "attribute-not-allowed": "Le paramÚtre d'attribut ne peut pas être utilisé dans ce widget", + "date": "Date", + "discard-changes": "Annuler les modifications", + "entity-attribute-required": "L'attribut d'entité est requis", + "entity-timeseries-required": "Entité timeseries est requis", + "not-allowed-entity": "L'entité sélectionnée ne peut pas avoir d'attributs partagés", + "no-attribute-selected": "Aucun attribut n'est sélectionné", + "no-datakey-selected": "Aucune date n'est sélectionnée", + "no-entity-selected": "Aucune entité sélectionnée", + "no-image": "Pas d'image", + "no-support-web-camera": "Pas de webcam supportée", + "no-timeseries-selected": "Aucune série temporelle sélectionnée", + "switch-attribute-value": "Changer la valeur de l'attribut d'entité", + "switch-camera": "Changer de caméra", + "switch-timeseries-value": "Changer la valeur de l'entité série temporelle", + "take-photo": "Prendre une photo", + "time": "Temps", + "timeseries-not-allowed": "Le paramÚtre série temporelle ne peut pas être utilisé dans ce widget", + "update-failed": "Mise à jour a échoué", + "update-successful": "Mise à jour réussie", + "update-attribute": "Attribut de mise à jour", + "update-timeseries": "Mise à jour de la série temporelle", + "value": "Valeur" + } + }, + "widgets-bundle": { + "add": "Ajouter un groupe de widgets", + "add-widgets-bundle-text": "Ajouter un nouveau groupe de widgets", + "create-new-widgets-bundle": "Créer un nouveau groupe de widgets", + "current": "Groupe actuel", + "delete": "Supprimer le groupe de widgets", + "delete-widgets-bundle-text": "Attention, aprÚs la confirmation, le groupe de widgets et toutes les données associées deviendront irrécupérables.", + "delete-widgets-bundle-title": "Êtes-vous sûr de vouloir supprimer le groupe de widgets '{{widgetsBundleTitle}}'?", + "delete-widgets-bundles-action-title": "Supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}", + "delete-widgets-bundles-text": "Attention, aprÚs la confirmation, tous les groupes de widgets sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.", + "delete-widgets-bundles-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}?", + "details": "Détails", + "empty": "Le groupe de widgets est vide", + "export": "Exporter le groupe de widgets", + "export-failed-error": "Impossible d'exporter le groupe de widgets: {{error}}", + "import": "Importer un groupe de widgets", + "invalid-widgets-bundle-file-error": "Impossible d'importer un groupe de widgets: structure de données du groupe de widgets non valides.", + "no-widgets-bundles-matching": "Aucun groupe de widgets correspondant à {{widgetsBundle}} n'a été trouvé.", + "no-widgets-bundles-text": "Aucun groupe de widgets trouvé", + "system": "SystÚme", + "title": "Titre", + "title-required": "Le titre est requis.", + "widgets-bundle-details": "Détails des groupes de widgets", + "widgets-bundle-file": "Fichier de groupe de widgets", + "widgets-bundle-required": "Un groupe de widgets est requis.", + "widgets-bundles": "Groupes de widgets" + } +} diff --git a/ui/src/app/locale/locale.constant-it_IT.json b/ui/src/app/locale/locale.constant-it_IT.json index 1c65d04096..f3a6be8d96 100644 --- a/ui/src/app/locale/locale.constant-it_IT.json +++ b/ui/src/app/locale/locale.constant-it_IT.json @@ -84,6 +84,7 @@ "timeout-required": "Timeout obbligatorio.", "timeout-invalid": "Timeout non valido.", "enable-tls": "Abilita TLS", + "tls-version" : "Versione TLS", "send-test-mail": "Invia mail di test", "security-settings": "Settaggi di sicurezza", "password-policy": "Politica password", diff --git a/ui/src/app/locale/locale.constant-ja_JA.json b/ui/src/app/locale/locale.constant-ja_JA.json index e1ebd4d6b3..4a789094f5 100644 --- a/ui/src/app/locale/locale.constant-ja_JA.json +++ b/ui/src/app/locale/locale.constant-ja_JA.json @@ -1,1528 +1,1529 @@ -{ - "access": { - "unauthorized": "無蚱可", - "unauthorized-access": "䞍正アクセス", - "unauthorized-access-text": "このリ゜ヌスにアクセスするにはサむンむンする必芁がありたす。", - "access-forbidden": "アクセス犁止", - "access-forbidden-text": "あなたはこの堎所ぞのアクセス暩を持っおいたせんこの堎所にアクセスしたい堎合は、別のナヌザヌずサむンむンしおみおください。", - "refresh-token-expired": "セッションが終了したした", - "refresh-token-failed": "セッションをリフレッシュできたせん" - }, - "action": { - "activate": "アクティブ化する", - "suspend": "サスペンド", - "save": "セヌブ", - "saveAs": "名前を付けお保存", - "cancel": "キャンセル", - "ok": "[OK]", - "delete": "削陀", - "add": "远加", - "yes": "はい", - "no": "いいえ", - "update": "曎新", - "remove": "削陀する", - "search": "サヌチ", - "clear-search": "怜玢をクリアする", - "assign": "割り圓おたす", - "unassign": "割り圓お解陀", - "share": "シェア", - "make-private": "プラむベヌトにする", - "apply": "適甚", - "apply-changes": "倉曎を適甚する", - "edit-mode": "線集モヌド", - "enter-edit-mode": "線集モヌドに入る", - "decline-changes": "倉曎を拒吊する", - "close": "閉じる", - "back": "バック", - "run": "走る", - "sign-in": "サむンむン", - "edit": "線集", - "view": "ビュヌ", - "create": "䜜成する", - "drag": "ドラッグ", - "refresh": "リフレッシュ", - "undo": "元に戻す", - "copy": "コピヌ", - "paste": "ペヌスト", - "copy-reference": "コピヌリファレンス", - "paste-reference": "参照貌り付け", - "import": "むンポヌト", - "export": "茞出する", - "share-via": "{{provider}}" - }, - "aggregation": { - "aggregation": "集箄", - "function": "デヌタ集玄機胜", - "limit": "最倧倀", - "group-interval": "グルヌプ化の間隔", - "min": "分", - "max": "最倧", - "avg": "平均", - "sum": "和", - "count": "カりント", - "none": "なし" - }, - "admin": { - "general": "䞀般", - "general-settings": "䞀般蚭定", - "outgoing-mail": "送信メヌル", - "outgoing-mail-settings": "送信メヌルの蚭定", - "system-settings": "システム蚭定", - "test-mail-sent": "テストメヌルが正垞に送信されたした", - "base-url": "ベヌスURL", - "base-url-required": "ベヌスURLは必須です。", - "mail-from": "メヌル", - "mail-from-required": "メヌルの送信元が必芁です。", - "smtp-protocol": "SMTPプロトコル", - "smtp-host": "SMTPホスト", - "smtp-host-required": "SMTPホストが必芁です。", - "smtp-port": "SMTPポヌト", - "smtp-port-required": "smtpポヌトを指定する必芁がありたす。", - "smtp-port-invalid": "それは有効なsmtpポヌトのようには芋えたせん。", - "timeout-msec": "タむムアりトミリ秒", - "timeout-required": "タむムアりトが必芁です。", - "timeout-invalid": "それは有効なタむムアりトのようには芋えたせん。", - "enable-tls": "TLSを有効にする", - "send-test-mail": "テストメヌルを送信する" - }, - "alarm": { - "alarm": "è­Šå ±", - "alarms": "アラヌム", - "select-alarm": "アラヌムを遞択", - "no-alarms-matching": "'{{entity}}'発芋されたした。", - "alarm-required": "アラヌムが必芁です", - "alarm-status": "アラヌム状態", - "search-status": { - "ANY": "どれか", - "ACTIVE": "アクティブ", - "CLEARED": "クリアされた", - "ACK": "承認された", - "UNACK": "未確認の" - }, - "display-status": { - "ACTIVE_UNACK": "アクティブ未確認", - "ACTIVE_ACK": "Active Acknowledged", - "CLEARED_UNACK": "クリアされた未確認のメッセヌゞ", - "CLEARED_ACK": "承認された承認枈み" - }, - "no-alarms-prompt": "アラヌムが芋぀かりたせん", - "created-time": "䜜成時刻", - "type": "タむプ", - "severity": "重倧床", - "originator": "創始者", - "originator-type": "発信者タむプ", - "details": "詳现", - "status": "状態", - "alarm-details": "アラヌムの詳现", - "start-time": "始たる時間", - "end-time": "終了時間", - "ack-time": "確認された時間", - "clear-time": "クリアされた時間", - "severity-critical": "クリティカル", - "severity-major": "メゞャヌ", - "severity-minor": "マむナヌ", - "severity-warning": "譊告", - "severity-indeterminate": "䞍確定", - "acknowledge": "認める", - "clear": "クリア", - "search": "アラヌムの怜玢", - "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} }遞択された", - "no-data": "衚瀺するデヌタがありたせん", - "polling-interval": "アラヌムポヌリング間隔秒", - "polling-interval-required": "アラヌムのポヌリング間隔が必芁です。", - "min-polling-interval-message": "少なくずも1秒間のポヌリング間隔が蚱可されたす。", - "aknowledge-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }", - "aknowledge-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?", - "clear-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }", - "clear-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?" - }, - "alias": { - "add": "゚むリアスを远加する", - "edit": "゚むリアスを線集する", - "name": "゚むリアス名", - "name-required": "゚むリアス名は必須です", - "duplicate-alias": "同じ名前の゚むリアスは既に存圚したす。", - "filter-type-single-entity": "単䞀の゚ンティティ", - "filter-type-entity-list": "゚ンティティリスト", - "filter-type-entity-name": "゚ンティティ名", - "filter-type-state-entity": "ダッシュボヌド状態からの゚ンティティ", - "filter-type-state-entity-description": "ダッシュボヌドの状態パラメヌタから取埗された゚ンティティ", - "filter-type-asset-type": "資産の皮類", - "filter-type-asset-type-description": "'{{assetType}}'", - "filter-type-asset-type-and-name-description": "'{{assetType}}''{{prefix}}'", - "filter-type-device-type": "デバむスタむプ", - "filter-type-device-type-description": "'{{deviceType}}'", - "filter-type-device-type-and-name-description": "'{{deviceType}}''{{prefix}}'", - "filter-type-relations-query": "関係ク゚リ", - "filter-type-relations-query-description": "{{entities}}{{relationType}}{{direction}}{{rootEntity}}", - "filter-type-asset-search-query": "資産怜玢ク゚リ", - "filter-type-asset-search-query-description": "{{assetTypes}}{{relationType}}{{direction}}{{rootEntity}}", - "filter-type-device-search-query": "デバむス怜玢ク゚リ", - "filter-type-device-search-query-description": "{{deviceTypes}}{{relationType}}{{direction}}{{rootEntity}}", - "entity-filter": "゚ンティティフィルタ", - "resolve-multiple": "耇数の゚ンティティずしお解決する", - "filter-type": "フィルタタむプ", - "filter-type-required": "フィルタタむプが必芁です。", - "entity-filter-no-entity-matched": "指定されたフィルタに䞀臎する゚ンティティは芋぀かりたせんでした。", - "no-entity-filter-specified": "゚ンティティフィルタが指定されおいない", - "root-state-entity": "ルヌトずしおダッシュボヌドの状態゚ンティティを䜿甚する", - "root-entity": "ルヌト゚ンティティ", - "state-entity-parameter-name": "状態゚ンティティのパラメヌタ名", - "default-state-entity": "デフォルト状態゚ンティティ", - "default-entity-parameter-name": "デフォルトでは", - "max-relation-level": "最倧関連レベル", - "unlimited-level": "無制限レベル", - "state-entity": "ダッシュボヌドの状態゚ンティティ", - "all-entities": "すべおの゚ンティティ", - "any-relation": "どれか" - }, - "asset": { - "asset": "資産", - "assets": "資産", - "management": "資産運甚管理", - "view-assets": "アセットの衚瀺", - "add": "アセットを远加", - "assign-to-customer": "顧客に割り圓おる", - "assign-asset-to-customer": "顧客に資産を割り圓おる", - "assign-asset-to-customer-text": "顧客に割り圓おる資産を遞択しおください", - "no-assets-text": "アセットが芋぀かりたせん", - "assign-to-customer-text": "資産を割り圓おる顧客を遞択しおください", - "public": "パブリック", - "assignedToCustomer": "顧客に割り圓おられた", - "make-public": "アセットを公開する", - "make-private": "アセットをプラむベヌトにする", - "unassign-from-customer": "顧客からの割り圓お解陀", - "delete": "アセットを削陀", - "asset-public": "資産は公開されおいたす", - "asset-type": "資産の皮類", - "asset-type-required": "資産の皮類が必芁です。", - "select-asset-type": "アセットタむプを遞択", - "enter-asset-type": "アセットタむプを入力", - "any-asset": "すべおのアセット", - "no-asset-types-matching": "'{{entitySubtype}}'発芋されたした。", - "asset-type-list-empty": "遞択されたアセットタむプはありたせん。", - "asset-types": "資産タむプ", - "name": "名", - "name-required": "名前は必須です。", - "description": "説明", - "type": "タむプ", - "type-required": "タむプが必芁です。", - "details": "詳现", - "events": "むベント", - "add-asset-text": "新しいアセットを远加する", - "asset-details": "資産の詳现", - "assign-assets": "アセットの割り圓お", - "assign-assets-text": "{ count, plural, 1 {1 asset} other {# assets} }顧客に", - "delete-assets": "アセットを削陀する", - "unassign-assets": "アセットの割り圓おを解陀する", - "unassign-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }顧客から", - "assign-new-asset": "新しいアセットを割り圓おる", - "delete-asset-title": "'{{assetName}}'?", - "delete-asset-text": "確認埌、資産ず関連するすべおのデヌタが回埩䞍胜になるこずに泚意しおください。", - "delete-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?", - "delete-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }", - "delete-assets-text": "確認埌、遞択したすべおの資産が削陀され、関連するすべおのデヌタは回埩䞍胜になりたすので泚意しおください。", - "make-public-asset-title": "'{{assetName}}'パブリック", - "make-public-asset-text": "確認埌、資産ずそのすべおのデヌタは公開され、他の人がアクセスできるようになりたす。", - "make-private-asset-title": "'{{assetName}}'プラむベヌト", - "make-private-asset-text": "確認埌、資産ずそのすべおのデヌタは非公開にされ、他の人がアクセスするこずはできたせん。", - "unassign-asset-title": "'{{assetName}}'?", - "unassign-asset-text": "確認埌、資産は割り圓お解陀され、顧客はアクセスできなくなりたす。", - "unassign-asset": "アセットの割り圓おを解陀する", - "unassign-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?", - "unassign-assets-text": "確認埌、遞択されたすべおの資産が割り圓お解陀され、顧客がアクセスできなくなりたす。", - "copyId": "アセットIDをコピヌする", - "idCopiedMessage": "アセットIDがクリップボヌドにコピヌされたした", - "select-asset": "アセットを遞択", - "no-assets-matching": "'{{entity}}'発芋されたした。", - "asset-required": "資産が必芁です", - "name-starts-with": "アセット名はで始たりたす", - "label": "ラベル" - }, - "attribute": { - "attributes": "属性", - "latest-telemetry": "最新テレメトリ", - "attributes-scope": "゚ンティティ属性のスコヌプ", - "scope-latest-telemetry": "最新テレメトリ", - "scope-client": "クラむアントの属性", - "scope-server": "サヌバヌの属性", - "scope-shared": "共有属性", - "add": "属性を远加する", - "key": "キヌ", - "last-update-time": "最終曎新時間", - "key-required": "属性キヌは必須です。", - "value": "倀", - "value-required": "属性倀は必須です。", - "delete-attributes-title": "{ count, plural, 1 {1 attribute} other {# attributes} }?", - "delete-attributes-text": "泚意しおください。確認埌、遞択したすべおの属性が削陀されたす。", - "delete-attributes": "属性を削陀する", - "enter-attribute-value": "属性倀を入力", - "show-on-widget": "りィゞェットで衚瀺", - "widget-mode": "りィゞェットモヌド", - "next-widget": "次のりィゞェット", - "prev-widget": "前のりィゞェット", - "add-to-dashboard": "ダッシュボヌドに远加", - "add-widget-to-dashboard": "りィゞェットをダッシュ​​ボヌドに远加する", - "selected-attributes": "{ count, plural, 1 {1 attribute} other {# attributes} }遞択された", - "selected-telemetry": "{ count, plural, 1 {1 telemetry unit} other {# telemetry units} }遞択された" - }, - "audit-log": { - "audit": "監査", - "audit-logs": "監査ログ", - "timestamp": "タむムスタンプ", - "entity-type": "゚ンティティタむプ", - "entity-name": "゚ンティティ名", - "user": "ナヌザヌ", - "type": "タむプ", - "status": "状態", - "details": "詳现", - "type-added": "远加された", - "type-deleted": "削陀枈み", - "type-updated": "曎新したした", - "type-attributes-updated": "属性が曎新されたした", - "type-attributes-deleted": "属性が削陀されたした", - "type-rpc-call": "RPC呌び出し", - "type-credentials-updated": "資栌が曎新されたした", - "type-assigned-to-customer": "顧客に割り圓おられた", - "type-unassigned-from-customer": "顧客から割り圓おられおいない", - "type-activated": "掻性化", - "type-suspended": "䞀時停止䞭", - "type-credentials-read": "信甚蚌明曞を読む", - "type-attributes-read": "読み取られた属性", - "type-relation-add-or-update": "関係が曎新されたした", - "type-relation-delete": "関係が削陀されたした", - "type-relations-delete": "すべおのリレヌションを削陀", - "type-alarm-ack": "承認された", - "type-alarm-clear": "クリアされた", - "status-success": "成功", - "status-failure": "倱敗", - "audit-log-details": "監査ログの詳现", - "no-audit-logs-prompt": "ログが芋぀かりたせん", - "action-data": "行動デヌタ", - "failure-details": "倱敗の詳现", - "search": "監査ログの怜玢", - "clear-search": "怜玢をクリアする" - }, - "confirm-on-exit": { - "message": "保存されおいない倉曎がありたす。あなたは本圓にこのペヌゞを出るのですか", - "html-message": "保存しおいない倉曎がありたす。
このペヌゞを終了しおもよろしいですか", - "title": "保存されおいない倉曎" - }, - "contact": { - "country": "囜", - "city": "シティ", - "state": "州/県", - "postal-code": "郵䟿番号", - "postal-code-invalid": "無効な郵䟿番号圢匏です。", - "address": "䜏所", - "address2": "アドレス2", - "phone": "電話", - "email": "Eメヌル", - "no-address": "䜏所がありたせん" - }, - "common": { - "username": "ナヌザヌ名", - "password": "パスワヌド", - "enter-username": "ナヌザヌネヌムを入力しおください", - "enter-password": "パスワヌドを入力する", - "enter-search": "怜玢を入力" - }, - "content-type": { - "json": "Json", - "text": "テキスト", - "binary": "バむナリBase64" - }, - "customer": { - "customer": "顧客", - "customers": "顧客", - "management": "顧客管理", - "dashboard": "カスタマヌダッシュボヌド", - "dashboards": "カスタマヌダッシュボヌド", - "devices": "顧客デバむス", - "assets": "顧客資産", - "public-dashboards": "パブリックダッシュボヌド", - "public-devices": "パブリックデバむス", - "public-assets": "公的資産", - "add": "顧客を远加", - "delete": "顧客を削陀する", - "manage-customer-users": "顧客ナヌザヌを管理する", - "manage-customer-devices": "顧客のデバむスを管理する", - "manage-customer-dashboards": "顧客ダッシュボヌドの管理", - "manage-public-devices": "パブリックデバむスを管理する", - "manage-public-dashboards": "公開ダッシュボヌドの管理", - "manage-customer-assets": "顧客資産の管理", - "manage-public-assets": "公的資産を管理する", - "add-customer-text": "新芏顧客を远加", - "no-customers-text": "顧客が芋぀かりたせん", - "customer-details": "お客様情報", - "delete-customer-title": "'{{customerTitle}}'?", - "delete-customer-text": "確認埌、お客様および関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "delete-customers-title": "{ count, plural, 1 {1 customer} other {# customers} }?", - "delete-customers-action-title": "{ count, plural, 1 {1 customer} other {# customers} }", - "delete-customers-text": "確認埌、遞択したすべおの顧客は削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "manage-users": "ナヌザヌを管理する", - "manage-assets": "アセットを管理する", - "manage-devices": "デバむスを管理する", - "manage-dashboards": "ダッシュボヌドの管理", - "title": "タむトル", - "title-required": "タむトルは必須です。", - "description": "説明", - "details": "詳现", - "events": "むベント", - "copyId": "顧客IDをコピヌ", - "idCopiedMessage": "顧客IDがクリップボヌドにコピヌされたした", - "select-customer": "顧客を遞択", - "no-customers-matching": "'{{entity}}'発芋されたした。", - "customer-required": "顧客は必須です", - "select-default-customer": "デフォルトの顧客を遞択", - "default-customer": "デフォルトの顧客", - "default-customer-required": "テナントレベルのダッシュボヌドをデバッグするには、デフォルトの顧客が必芁です" - }, - "datetime": { - "date-from": "デヌトから", - "time-from": "からの時間", - "date-to": "日付", - "time-to": "の時間" - }, - "dashboard": { - "dashboard": "ダッシュボヌド", - "dashboards": "ダッシュボヌド", - "management": "ダッシュボヌド管理", - "view-dashboards": "ダッシュボヌドを衚瀺する", - "add": "ダッシュボヌドを远加", - "assign-dashboard-to-customer": "顧客にダッシュボヌドを割り圓おる", - "assign-dashboard-to-customer-text": "顧客に割り圓おるダッシュボヌドを遞択しおください", - "assign-to-customer-text": "ダッシュボヌドを割り圓おる顧客を遞択しおください", - "assign-to-customer": "顧客に割り圓おる", - "unassign-from-customer": "顧客からの割り圓お解陀", - "make-public": "ダッシュボヌドを公開する", - "make-private": "ダッシュボヌドを非公開にする", - "manage-assigned-customers": "割り圓おられた顧客を管理する", - "assigned-customers": "割り圓おられた顧客", - "assign-to-customers": "顧客にダッシュボヌドを割り圓おる", - "assign-to-customers-text": "ダッシュボヌドを割り圓おる顧客を遞択しおください", - "unassign-from-customers": "顧客からのダッシュボヌドの割り圓お解陀", - "unassign-from-customers-text": "ダッシュボヌドから割り圓お解陀する顧客を遞択しおください", - "no-dashboards-text": "ダッシュボヌドが芋぀かりたせん", - "no-widgets": "りィゞェットは蚭定されおいたせん", - "add-widget": "新しいりィゞェットを远加", - "title": "タむトル", - "select-widget-title": "りィゞェットを遞択", - "select-widget-subtitle": "利甚可胜なりィゞェットタむプのリスト", - "delete": "ダッシュボヌドの削陀", - "title-required": "タむトルは必須です。", - "description": "説明", - "details": "詳现", - "dashboard-details": "ダッシュボヌドの詳现", - "add-dashboard-text": "新しいダッシュボヌドを远加する", - "assign-dashboards": "ダッシュボヌドの割り圓お", - "assign-new-dashboard": "新しいダッシュボヌドを割り圓おる", - "assign-dashboards-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客に", - "unassign-dashboards-action-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から", - "delete-dashboards": "ダッシュボヌドの削陀", - "unassign-dashboards": "ダッシュボヌドの割り圓おを解陀する", - "unassign-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から", - "delete-dashboard-title": "'{{dashboardTitle}}'?", - "delete-dashboard-text": "確認埌、ダッシュボヌドずすべおの関連デヌタが回埩䞍胜になるので泚意しおください。", - "delete-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?", - "delete-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }", - "delete-dashboards-text": "泚意しおください。確認埌、遞択したダッシュボヌドはすべお削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "unassign-dashboard-title": "'{{dashboardTitle}}'?", - "unassign-dashboard-text": "確認埌、ダッシュボヌドは割り圓おられなくなり、顧客はアクセスできなくなりたす。", - "unassign-dashboard": "ダッシュボヌドの割り圓おを解陀する", - "unassign-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?", - "unassign-dashboards-text": "確認の埌、遞択したすべおのダッシュボヌドは割り圓おられなくなり、顧客はアクセスできなくなりたす。", - "public-dashboard-title": "ダッシュボヌドは公開されたした", - "public-dashboard-text": "{{dashboardTitle}} is now public and accessible via next public link:", - "public-dashboard-notice": "泚デヌタにアクセスするために、関連するデバむスを公開するこずを忘れないでください。", - "make-private-dashboard-title": "'{{dashboardTitle}}'プラむベヌト", - "make-private-dashboard-text": "確認の埌、ダッシュボヌドはプラむベヌトにされ、他の人がアクセスするこずはできたせん。", - "make-private-dashboard": "ダッシュボヌドを非公開にする", - "socialshare-text": "'{{dashboardTitle}}'ThingsBoardを搭茉", - "socialshare-title": "'{{dashboardTitle}}'ThingsBoardを搭茉", - "select-dashboard": "ダッシュボヌドを遞択", - "no-dashboards-matching": "'{{entity}}'発芋されたした。", - "dashboard-required": "ダッシュボヌドが必芁です。", - "select-existing": "既存のダッシュボヌドを遞択", - "create-new": "新しいダッシュボヌドを䜜成する", - "new-dashboard-title": "新しいダッシュボヌドのタむトル", - "open-dashboard": "ダッシュボヌドを開く", - "set-background": "背景を蚭定する", - "background-color": "背景色", - "background-image": "背景画像", - "background-size-mode": "背景サむズモヌド", - "no-image": "遞択した画像がありたせん", - "drop-image": "画像をドロップするか、クリックしおアップロヌドするファむルを遞択したす。", - "settings": "蚭定", - "columns-count": "列数", - "columns-count-required": "列数が必芁です。", - "min-columns-count-message": "わずか10の最小列数が蚱可されたす。", - "max-columns-count-message": "最倧1000の列カりントのみが蚱可されたす。", - "widgets-margins": "りィゞェット間のマヌゞン", - "horizontal-margin": "氎平マヌゞン", - "horizontal-margin-required": "氎平䜙癜倀が必芁です。", - "min-horizontal-margin-message": "最小氎平マヌゞン倀ずしおは0だけが蚱容されたす。", - "max-horizontal-margin-message": "最倧氎平マヌゞン倀は50だけです。", - "vertical-margin": "垂盎マヌゞン", - "vertical-margin-required": "垂盎マヌゞン倀が必芁です。", - "min-vertical-margin-message": "最小の垂盎マヌゞン倀ずしお0のみが蚱可されたす。", - "max-vertical-margin-message": "最倧垂盎マヌゞン倀は50のみです。", - "autofill-height": "自動レむアりトの高さ", - "mobile-layout": "モバむルレむアりトの蚭定", - "mobile-row-height": "モバむル行の高さ、px", - "mobile-row-height-required": "モバむル行の高さ倀が必芁です。", - "min-mobile-row-height-message": "最小の行の高さの倀ずしお、5ピクセルしか蚱可されたせん。", - "max-mobile-row-height-message": "移動可胜な行の高さの最倧倀ずしお蚱可されるのは200ピクセルだけです。", - "display-title": "ダッシュボヌドのタむトルを衚瀺する", - "toolbar-always-open": "ツヌルバヌを開いたたたにする", - "title-color": "タむトルカラヌ", - "display-dashboards-selection": "ダッシュボヌドの遞択を衚瀺する", - "display-entities-selection": "゚ンティティの遞択を衚瀺する", - "display-dashboard-timewindow": "タむムりィンドりを衚瀺する", - "display-dashboard-export": "゚クスポヌトの衚瀺", - "import": "むンポヌトダッシュボヌド", - "export": "゚クスポヌトダッシュボヌド", - "export-failed-error": "{{error}}", - "create-new-dashboard": "新しいダッシュボヌドを䜜成する", - "dashboard-file": "ダッシュボヌドファむル", - "invalid-dashboard-file-error": "ダッシュボヌドをむンポヌトできたせんダッシュボヌドのデヌタ構造が無効です。", - "dashboard-import-missing-aliases-title": "むンポヌトされたダッシュボヌドで䜿甚される゚むリアスを蚭定する", - "create-new-widget": "新しいりィゞェットを䜜成する", - "import-widget": "むンポヌトりィゞェット", - "widget-file": "りィゞェットファむル", - "invalid-widget-file-error": "りィゞェットをむンポヌトできたせんりィゞェットのデヌタ構造が無効です。", - "widget-import-missing-aliases-title": "むンポヌトされたりィゞェットで䜿甚される゚むリアスを蚭定する", - "open-toolbar": "ダッシュボヌドツヌルバヌを開く", - "close-toolbar": "ツヌルバヌを閉じる", - "configuration-error": "蚭定゚ラヌ", - "alias-resolution-error-title": "ダッシュボヌド゚むリアス蚭定゚ラヌ", - "invalid-aliases-config": "゚むリアスフィルタの䞀郚に䞀臎するデバむスを芋぀けるこずができたせん。
この問題を解決するには、管理者に連絡しおください。", - "select-devices": "デバむスの遞択", - "assignedToCustomer": "顧客に割り圓おられた", - "assignedToCustomers": "顧客に割り圓おられた", - "public": "パブリック", - "public-link": "パブリックリンク", - "copy-public-link": "パブリックリンクをコピヌする", - "public-link-copied-message": "ダッシュボヌドのパブリックリンクがクリップボヌドにコピヌされたした", - "manage-states": "ダッシュボヌドの状態を管理する", - "states": "ダッシュボヌドの状態", - "search-states": "怜玢ダッシュボヌドの状態", - "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard states} }遞択された", - "edit-state": "ダッシュボヌドの状態を線集する", - "delete-state": "ダッシュボヌドの状態を削陀する", - "add-state": "ダッシュボヌドの状態を远加する", - "state": "ダッシュボヌドの状態", - "state-name": "名", - "state-name-required": "ダッシュボヌドの状態名は必須です。", - "state-id": "状態ID", - "state-id-required": "ダッシュボヌドの状態IDは必須です。", - "state-id-exists": "同じIDを持぀ダッシュボヌドの状態は既に存圚したす。", - "is-root-state": "ルヌト状態", - "delete-state-title": "ダッシュボヌドの状態を削陀する", - "delete-state-text": "'{{stateName}}'?", - "show-details": "詳现を衚瀺", - "hide-details": "詳现を隠す", - "select-state": "タヌゲット状態を遞択する", - "state-controller": "状態コントロヌラ" - }, - "datakey": { - "settings": "蚭定", - "advanced": "侊箚", - "label": "ラベル", - "color": "色", - "units": "倀の隣に衚瀺する特別なシンボル", - "decimals": "浮動小数点の埌の桁数", - "data-generation-func": "デヌタ生成関数", - "use-data-post-processing-func": "デヌタ埌凊理機胜を䜿甚する", - "configuration": "デヌタキヌ蚭定", - "timeseries": "タむムズ", - "attributes": "属性", - "alarm": "アラヌムフィヌルド", - "timeseries-required": "゚ンティティの時系列デヌタが必芁です。", - "timeseries-or-attributes-required": "゚ンティティのtimeseries /属性は必須です。", - "maximum-timeseries-or-attributes": "{ count, plural, 1 {1 timeseries/attribute is allowed.} other {# timeseries/attributes are allowed} }", - "alarm-fields-required": "アラヌムフィヌルドが必芁です。", - "function-types": "関数型", - "function-types-required": "関数型が必芁です。", - "maximum-function-types": "{ count, plural, 1 {1 function type is allowed.} other {# function types are allowed} }" - }, - "datasource": { - "type": "デヌタ゜ヌスタむプ", - "name": "名", - "add-datasource-prompt": "デヌタ゜ヌスを远加しおください" - }, - "details": { - "edit-mode": "線集モヌド", - "toggle-edit-mode": "線集モヌドを切り替える" - }, - "device": { - "device": "デバむス", - "device-required": "デバむスが必芁です。", - "devices": "デバむス", - "management": "端末管理", - "view-devices": "デバむスの衚瀺", - "device-alias": "デバむス゚むリアス", - "aliases": "デバむス゚むリアス", - "no-alias-matching": "'{{alias}}'芋぀かりたせん。", - "no-aliases-found": "別名は芋぀かりたせんでした。", - "no-key-matching": "'{{key}}'芋぀かりたせん。", - "no-keys-found": "キヌが芋぀かりたせん。", - "create-new-alias": "新しいものを䜜成しおください", - "create-new-key": "新しいものを䜜成しおください", - "duplicate-alias-error": "'{{alias}}'
デバむス゚むリアスは、ダッシュボヌド内で䞀意である必芁がありたす。", - "configure-alias": "'{{alias}}'゚むリアス", - "no-devices-matching": "'{{entity}}'発芋されたした。", - "alias": "゚むリアス", - "alias-required": "デバむス゚むリアスが必芁です。", - "remove-alias": "デバむス゚むリアスを削陀する", - "add-alias": "デバむス゚むリアスを远加する", - "name-starts-with": "デバむス名はで始たりたす", - "device-list": "デバむスリスト", - "use-device-name-filter": "フィルタを䜿甚する", - "device-list-empty": "デバむスが遞択されおいたせん。", - "device-name-filter-required": "デバむス名フィルタが必芁です。", - "device-name-filter-no-device-matched": "'{{device}}'発芋されたした。", - "add": "デバむスを远加", - "assign-to-customer": "顧客に割り圓おる", - "assign-device-to-customer": "顧客にデバむスを割り圓おる", - "assign-device-to-customer-text": "顧客に割り圓おるデバむスを遞択しおください", - "make-public": "端末を公開する", - "make-private": "デバむスを非公開にする", - "no-devices-text": "デバむスが芋぀かりたせん", - "assign-to-customer-text": "デバむスを割り圓おる顧客を遞択しおください", - "device-details": "デバむスの詳现", - "add-device-text": "新しいデバむスを远加する", - "credentials": "資栌情報", - "manage-credentials": "資栌情報を管理する", - "delete": "デバむスを削陀する", - "assign-devices": "デバむスを割り圓おる", - "assign-devices-text": "{ count, plural, 1 {1 device} other {# devices} }顧客に", - "delete-devices": "デバむスを削陀する", - "unassign-from-customer": "顧客からの割り圓お解陀", - "unassign-devices": "デバむスの割り圓おを解陀する", - "unassign-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }顧客から", - "assign-new-device": "新しいデバむスを割り圓おる", - "make-public-device-title": "'{{deviceName}}'パブリック", - "make-public-device-text": "確認埌、デバむスずそのすべおのデヌタは公開され、他のナヌザヌがアクセスできるようになりたす。", - "make-private-device-title": "'{{deviceName}}'プラむベヌト", - "make-private-device-text": "確認埌、デバむスずそのすべおのデヌタは非公開になり、他人がアクセスできなくなりたす。", - "view-credentials": "資栌情報を衚瀺する", - "delete-device-title": "'{{deviceName}}'?", - "delete-device-text": "確認埌、デバむスず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "delete-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?", - "delete-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }", - "delete-devices-text": "泚意しおください。確認埌、遞択したすべおのデバむスが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "unassign-device-title": "'{{deviceName}}'?", - "unassign-device-text": "確認の埌、デバむスは割り圓おが解陀され、顧客がアクセスできなくなりたす。", - "unassign-device": "デバむスの割り圓おを解陀する", - "unassign-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?", - "unassign-devices-text": "確認の埌、遞択されたすべおのデバむスが割り圓お解陀され、顧客がアクセスできなくなりたす。", - "device-credentials": "デバむス資栌情報", - "credentials-type": "資栌情報タむプ", - "access-token": "アクセストヌクン", - "access-token-required": "アクセストヌクンが必芁です。", - "access-token-invalid": "アクセストヌクンの長さは、1〜20文字でなければなりたせん。", - "rsa-key": "RSA公開鍵", - "rsa-key-required": "RSA公開鍵が必芁です。", - "secret": "秘密", - "secret-required": "秘密が必芁です。", - "device-type": "デバむスタむプ", - "device-type-required": "デバむスタむプが必芁です。", - "select-device-type": "デバむスタむプを遞択", - "enter-device-type": "デバむスタむプを入力", - "any-device": "すべおのデバむス", - "no-device-types-matching": "'{{entitySubtype}}'発芋されたした。", - "device-type-list-empty": "遞択されたデバむスタむプはありたせん。", - "device-types": "デバむスの皮類", - "name": "名", - "name-required": "名前は必須です。", - "description": "説明", - "events": "むベント", - "details": "詳现", - "copyId": "デバむスIDをコピヌする", - "copyAccessToken": "コピヌアクセストヌクン", - "idCopiedMessage": "デバむスIDがクリップボヌドにコピヌされたした", - "accessTokenCopiedMessage": "デバむスアクセストヌクンがクリップボヌドにコピヌされたした", - "assignedToCustomer": "顧客に割り圓おられた", - "unable-delete-device-alias-title": "デバむス゚むリアスを削陀できたせん", - "unable-delete-device-alias-text": "'{{deviceAlias}}'{{widgetsList}}", - "is-gateway": "ゲヌトりェむです", - "public": "パブリック", - "device-public": "デバむスは公開されおいたす", - "select-device": "デバむスの遞択" - }, - "dialog": { - "close": "ダむアログを閉じる" - }, - "error": { - "unable-to-connect": "サヌバヌに接続できたせんむンタヌネット接続を確認しおください。", - "unhandled-error-code": "{{errorCode}}", - "unknown-error": "䞍明な゚ラヌ" - }, - "entity": { - "entity": "゚ンティティ", - "entities": "゚ンティティ", - "aliases": "゚ンティティ゚むリアス", - "entity-alias": "゚ンティティ゚むリアス", - "unable-delete-entity-alias-title": "゚ンティティ゚むリアスを削陀できたせん", - "unable-delete-entity-alias-text": "'{{entityAlias}}'{{widgetsList}}", - "duplicate-alias-error": "'{{alias}}'
゚ンティティの゚むリアスは、ダッシュボヌド内で䞀意である必芁がありたす。", - "missing-entity-filter-error": "'{{alias}}'.", - "configure-alias": "'{{alias}}'゚むリアス", - "alias": "゚むリアス", - "alias-required": "゚ンティティ゚むリアスが必芁です。", - "remove-alias": "゚ンティティ゚むリアスを削陀する", - "add-alias": "゚ンティティ゚むリアスを远加する", - "entity-list": "゚ンティティリスト", - "entity-type": "゚ンティティタむプ", - "entity-types": "゚ンティティタむプ", - "entity-type-list": "゚ンティティタむプリスト", - "any-entity": "任意の゚ンティティ", - "enter-entity-type": "゚ンティティタむプを入力", - "no-entities-matching": "'{{entity}}'発芋されたした。", - "no-entity-types-matching": "'{{entityType}}'発芋されたした。", - "name-starts-with": "名前はで始たる", - "use-entity-name-filter": "フィルタを䜿甚する", - "entity-list-empty": "遞択された゚ンティティはありたせん", - "entity-type-list-empty": "゚ンティティタむプは遞択されおいたせん。", - "entity-name-filter-required": "゚ンティティ名フィルタが必芁です。", - "entity-name-filter-no-entity-matched": "'{{entity}}'発芋されたした。", - "all-subtypes": "すべお", - "select-entities": "゚ンティティの遞択", - "no-aliases-found": "別名は芋぀かりたせんでした。", - "no-alias-matching": "'{{alias}}'芋぀かりたせん。", - "create-new-alias": "新しいものを䜜成しおください", - "key": "キヌ", - "key-name": "キヌ名", - "no-keys-found": "キヌが芋぀かりたせん。", - "no-key-matching": "'{{key}}'芋぀かりたせん。", - "create-new-key": "新しいものを䜜成しおください", - "type": "タむプ", - "type-required": "゚ンティティタむプが必芁です。", - "type-device": "デバむス", - "type-devices": "デバむス", - "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", - "device-name-starts-with": "'{{prefix}}'", - "type-asset": "資産", - "type-assets": "資産", - "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", - "asset-name-starts-with": "'{{prefix}}'", - "type-rule": "ルヌル", - "type-rules": "ルヌル", - "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }", - "rule-name-starts-with": "'{{prefix}}'", - "type-plugin": "プラグむン", - "type-plugins": "プラグむン", - "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }", - "plugin-name-starts-with": "'{{prefix}}'", - "type-tenant": "テナント", - "type-tenants": "テナント", - "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", - "tenant-name-starts-with": "'{{prefix}}'", - "type-customer": "顧客", - "type-customers": "顧客", - "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", - "customer-name-starts-with": "'{{prefix}}'", - "type-user": "ナヌザヌ", - "type-users": "ナヌザヌ", - "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }", - "user-name-starts-with": "'{{prefix}}'", - "type-dashboard": "ダッシュボヌド", - "type-dashboards": "ダッシュボヌド", - "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }", - "dashboard-name-starts-with": "'{{prefix}}'", - "type-alarm": "è­Šå ±", - "type-alarms": "アラヌム", - "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", - "alarm-name-starts-with": "'{{prefix}}'", - "type-rulechain": "ルヌルチェヌン", - "type-rulechains": "ルヌルチェヌン", - "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", - "rulechain-name-starts-with": "'{{prefix}}'", - "type-rulenode": "ルヌルノヌド", - "type-rulenodes": "ルヌルノヌド", - "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }", - "rulenode-name-starts-with": "'{{prefix}}'", - "type-current-customer": "珟圚の顧客", - "search": "怜玢゚ンティティ", - "selected-entities": "{ count, plural, 1 {1 entity} other {# entities} }遞択された", - "entity-name": "゚ンティティ名", - "details": "゚ンティティの詳现", - "no-entities-prompt": "゚ンティティが芋぀かりたせん", - "no-data": "衚瀺するデヌタがありたせん" - }, - "event": { - "event-type": "むベントタむプ", - "type-error": "゚ラヌ", - "type-lc-event": "ラむフサむクルむベント", - "type-stats": "統蚈", - "type-debug-rule-node": "デバッグ", - "type-debug-rule-chain": "デバッグ", - "no-events-prompt": "むベントは芋぀かりたせんでした", - "error": "゚ラヌ", - "alarm": "è­Šå ±", - "event-time": "むベント時間", - "server": "サヌバ", - "body": "䜓", - "method": "方法", - "type": "タむプ", - "entity": "゚ンティティ", - "message-id": "メッセヌゞID", - "message-type": "メッセヌゞタむプ", - "data-type": "デヌタ・タむプ", - "relation-type": "関係タむプ", - "metadata": "メタデヌタ", - "data": "デヌタ", - "event": "むベント", - "status": "状態", - "success": "成功", - "failed": "倱敗", - "messages-processed": "凊理されたメッセヌゞ", - "errors-occurred": "゚ラヌが発生したした" - }, - "extension": { - "extensions": "拡匵機胜", - "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} }遞択された", - "type": "タむプ", - "key": "キヌ", - "value": "倀", - "id": "むド", - "extension-id": "内線番号", - "extension-type": "拡匵タむプ", - "transformer-json": "JSON *", - "unique-id-required": "珟圚の拡匵IDは既に存圚したす。", - "delete": "拡匵子を削陀", - "add": "内線番号を远加", - "edit": "拡匵機胜を線集する", - "delete-extension-title": "'{{extensionId}}'?", - "delete-extension-text": "確認埌、拡匵子ず関連するすべおのデヌタが回埩䞍胜になるこずに泚意しおください。", - "delete-extensions-title": "{ count, plural, 1 {1 extension} other {# extensions} }?", - "delete-extensions-text": "泚意しおください。確認埌、遞択したすべおの内線番号が削陀されたす。", - "converters": "コンバヌタヌ", - "converter-id": "コンバヌタヌID", - "configuration": "構成", - "converter-configurations": "コンバヌタ構成", - "token": "セキュリティトヌクン", - "add-converter": "コンバヌタを远加する", - "add-config": "コンバヌタ蚭定を远加する", - "device-name-expression": "デバむス名匏", - "device-type-expression": "デバむスタむプの匏", - "custom": "カスタム", - "to-double": "ダブル", - "transformer": "トランス", - "json-required": "トランスフォヌマヌjsonが必芁です。", - "json-parse": "倉圧噚jsonを解析できたせん。", - "attributes": "属性", - "add-attribute": "属性を远加する", - "add-map": "マッピング芁玠を远加する", - "timeseries": "タむムズ", - "add-timeseries": "時系列を远加する", - "field-required": "フィヌルドは必須項目です", - "brokers": "ブロヌカヌ", - "add-broker": "ブロヌカヌを远加", - "host": "ホスト", - "port": "ポヌト", - "port-range": "ポヌトは1〜65535の範囲内にある必芁がありたす。", - "ssl": "SSL", - "credentials": "資栌情報", - "username": "ナヌザヌ名", - "password": "パスワヌド", - "retry-interval": "ミリ秒単䜍の再詊行間隔", - "anonymous": "匿名", - "basic": "ベヌシック", - "pem": "PEM", - "ca-cert": "CA蚌明曞ファむル*", - "private-key": "秘密鍵ファむル*", - "cert": "蚌明曞ファむル*", - "no-file": "ファむルが遞択されおいたせん。", - "drop-file": "ファむルをドロップするか、クリックしおアップロヌドするファむルを遞択したす。", - "mapping": "マッピング", - "topic-filter": "トピックフィルタ", - "converter-type": "コンバヌタタむプ", - "converter-json": "Json", - "json-name-expression": "デバむス名json匏", - "topic-name-expression": "デバむス名トピック衚珟", - "json-type-expression": "デバむスタむプjson匏", - "topic-type-expression": "デバむスタむプトピック衚珟", - "attribute-key-expression": "属性キヌ匏", - "attr-json-key-expression": "属性キヌjson匏", - "attr-topic-key-expression": "属性キヌトピック匏", - "request-id-expression": "芁求ID匏", - "request-id-json-expression": "リク゚ストID json匏", - "request-id-topic-expression": "リク゚ストIDトピック衚珟", - "response-topic-expression": "応答トピック衚珟", - "value-expression": "倀匏", - "topic": "トピック", - "timeout": "タむムアりトミリ秒", - "converter-json-required": "コンバヌタjsonが必芁です。", - "converter-json-parse": "コンバヌタjsonを解析できたせん。", - "filter-expression": "フィルタ匏", - "connect-requests": "接続芁求", - "add-connect-request": "接続芁求を远加", - "disconnect-requests": "切断芁求", - "add-disconnect-request": "切断リク゚ストを远加する", - "attribute-requests": "属性芁求", - "add-attribute-request": "属性芁求を远加する", - "attribute-updates": "属性の曎新", - "add-attribute-update": "属性の曎新を远加する", - "server-side-rpc": "サヌバヌ偎RPC", - "add-server-side-rpc-request": "サヌバヌ偎RPC芁求を远加する", - "device-name-filter": "デバむス名フィルタ", - "attribute-filter": "属性フィルタ", - "method-filter": "方法フィルタヌ", - "request-topic-expression": "トピック衚珟を芁求する", - "response-timeout": "応答タむムアりトミリ秒", - "topic-expression": "トピック衚珟", - "client-scope": "クラむアントスコヌプ", - "add-device": "デバむスを远加", - "opc-server": "サヌバヌ", - "opc-add-server": "サヌバヌを远加", - "opc-add-server-prompt": "サヌバヌを远加しおください", - "opc-application-name": "アプリケヌション名", - "opc-application-uri": "アプリケヌションURI", - "opc-scan-period-in-seconds": "スキャン時間秒", - "opc-security": "セキュリティ", - "opc-identity": "身元", - "opc-keystore": "キヌストア", - "opc-type": "タむプ", - "opc-keystore-type": "タむプ", - "opc-keystore-location": "ロケヌション*", - "opc-keystore-password": "パスワヌド", - "opc-keystore-alias": "゚むリアス", - "opc-keystore-key-password": "キヌのパスワヌド", - "opc-device-node-pattern": "デバむスノヌドパタヌン", - "opc-device-name-pattern": "デバむス名パタヌン", - "modbus-server": "サヌバヌ/スレヌブ", - "modbus-add-server": "サヌバヌ/スレヌブを远加する", - "modbus-add-server-prompt": "サヌバヌ/スレヌブを远加しおください", - "modbus-transport": "茞送", - "modbus-port-name": "シリアルポヌト名", - "modbus-encoding": "゚ンコヌディング", - "modbus-parity": "パリティ", - "modbus-baudrate": "ボヌレヌト", - "modbus-databits": "デヌタビット", - "modbus-stopbits": "ストップビット", - "modbus-databits-range": "デヌタビットは7〜8の範囲内にある必芁がありたす。", - "modbus-stopbits-range": "ストップビットは1〜2の範囲内でなければなりたせん。", - "modbus-unit-id": "ナニットID", - "modbus-unit-id-range": "ナニットIDは1〜247の範囲で指定しおください。", - "modbus-device-name": "装眮名", - "modbus-poll-period": "投祚期間ミリ秒", - "modbus-attributes-poll-period": "属性のポヌリング期間ミリ秒", - "modbus-timeseries-poll-period": "時系列ポヌリング期間ミリ秒", - "modbus-poll-period-range": "投祚期間は正の倀でなければなりたせん。", - "modbus-tag": "タグ", - "modbus-function": "関数", - "modbus-register-address": "登録アドレス", - "modbus-register-address-range": "レゞスタのアドレスは0〜65535の範囲内である必芁がありたす。", - "modbus-register-bit-index": "ビットむンデックス", - "modbus-register-bit-index-range": "ビットむンデックスは0〜15の範囲内である必芁がありたす。", - "modbus-register-count": "レゞスタ数", - "modbus-register-count-range": "レゞスタ数は正の倀でなければなりたせん。", - "modbus-byte-order": "バむト順", - "sync": { - "status": "状態", - "sync": "同期", - "not-sync": "同期しない", - "last-sync-time": "前回の同期時間", - "not-available": "利甚䞍可" - }, - "export-extensions-configuration": "゚クステンション蚭定の゚クスポヌト", - "import-extensions-configuration": "゚クステンション蚭定のむンポヌト", - "import-extensions": "拡匵機胜のむンポヌト", - "import-extension": "むンポヌト拡匵", - "export-extension": "茞出延長", - "file": "拡匵機胜ファむル", - "invalid-file-error": "無効な拡匵ファむル" - }, - "fullscreen": { - "expand": "フルスクリヌンに拡倧", - "exit": "党画面衚瀺を終了", - "toggle": "フルスクリヌンモヌドを切り替える", - "fullscreen": "党画面衚瀺" - }, - "function": { - "function": "関数" - }, - "grid": { - "delete-item-title": "このアむテムを削陀しおもよろしいですか", - "delete-item-text": "泚意しおください。確認埌、この項目ず関連するすべおのデヌタは回埩䞍胜になりたす。", - "delete-items-title": "{ count, plural, 1 {1 item} other {# items} }?", - "delete-items-action-title": "{ count, plural, 1 {1 item} other {# items} }", - "delete-items-text": "泚意しおください。確認埌、遞択したすべおのアむテムが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "add-item-text": "新しいアむテムを远加", - "no-items-text": "項目は芋぀かりたせんでした", - "item-details": "商品詳现", - "delete-item": "アむテムを削陀", - "delete-items": "アむテムを削陀する", - "scroll-to-top": "トップにスクロヌルしたす" - }, - "help": { - "goto-help-page": "ヘルプペヌゞに行く" - }, - "home": { - "home": "ホヌム", - "profile": "プロフィヌル", - "logout": "ログアりト", - "menu": "メニュヌ", - "avatar": "アバタヌ", - "open-user-menu": "ナヌザヌメニュヌを開く" - }, - "import": { - "no-file": "ファむルが遞択されおいたせん", - "drop-file": "JSONファむルをドロップするか、アップロヌドするファむルをクリックしお遞択したす。" - }, - "item": { - "selected": "遞択された" - }, - "js-func": { - "no-return-error": "関数は倀を返す必芁がありたす", - "return-type-mismatch": "'{{type}}'タむプ", - "tidy": "きちんずした" - }, - "key-val": { - "key": "キヌ", - "value": "倀", - "remove-entry": "゚ントリを削陀", - "add-entry": "゚ントリを远加", - "no-data": "゚ントリなし" - }, - "layout": { - "layout": "レむアりト", - "manage": "レむアりトの管理", - "settings": "レむアりト蚭定", - "color": "色", - "main": "メむン", - "right": "右", - "select": "タヌゲットレむアりトを遞択" - }, - "legend": { - "position": "䌝説の䜍眮", - "show-max": "最倧倀を衚瀺", - "show-min": "最小倀を衚瀺する", - "show-avg": "平均倀を衚瀺", - "show-total": "合蚈倀を衚瀺", - "settings": "凡䟋の蚭定", - "min": "分", - "max": "最倧", - "avg": "平均", - "total": "合蚈" - }, - "login": { - "login": "ログむン", - "request-password-reset": "リク゚ストパスワヌドのリセット", - "reset-password": "パスワヌドを再蚭定する", - "create-password": "パスワヌドの䜜成", - "passwords-mismatch-error": "入力されたパスワヌドは同じでなければなりたせん", - "password-again": "パスワヌドをもう䞀床", - "sign-in": "サむンむンしおください", - "username": "ナヌザヌ名電子メヌル", - "remember-me": "私を芚えおたすか", - "forgot-password": "パスワヌドをお忘れですか", - "password-reset": "パスワヌドのリセット", - "new-password": "新しいパスワヌド", - "new-password-again": "新しいパスワヌドを再入力", - "password-link-sent-message": "パスワヌドリセットリンクが正垞に送信されたした", - "email": "Eメヌル" - }, - "position": { - "top": "侊", - "bottom": "ボトム", - "left": "å·Š", - "right": "右" - }, - "profile": { - "profile": "プロフィヌル", - "change-password": "パスワヌドを倉曎する", - "current-password": "珟圚のパスワヌド" - }, - "relation": { - "relations": "関係", - "direction": "方向", - "search-direction": { - "FROM": "から", - "TO": "に" - }, - "direction-type": { - "FROM": "から", - "TO": "に" - }, - "from-relations": "アりトバりンド関係", - "to-relations": "むンバりンド関係", - "selected-relations": "{ count, plural, 1 {1 relation} other {# relations} }遞択された", - "type": "タむプ", - "to-entity-type": "゚ンティティタむプぞ", - "to-entity-name": "゚ンティティ名に", - "from-entity-type": "゚ンティティタむプから", - "from-entity-name": "゚ンティティ名から", - "to-entity": "実䜓ぞ", - "from-entity": "゚ンティティから", - "delete": "関係を削陀する", - "relation-type": "関係タむプ", - "relation-type-required": "関係タむプが必芁です。", - "any-relation-type": "いかなるタむプ", - "add": "関係を远加する", - "edit": "関係を線集する", - "delete-to-relation-title": "'{{entityName}}'?", - "delete-to-relation-text": "'{{entityName}}'珟圚の゚ンティティずは無関係です。", - "delete-to-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?", - "delete-to-relations-text": "泚意しおください。確認埌、遞択されたリレヌションはすべお削陀され、察応する゚ンティティは珟圚の゚ンティティずは無関係になりたす。", - "delete-from-relation-title": "'{{entityName}}'?", - "delete-from-relation-text": "'{{entityName}}'.", - "delete-from-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?", - "delete-from-relations-text": "泚意しおください。確認埌、遞択されたリレヌションはすべお削陀され、珟圚の゚ンティティは察応する゚ンティティずは無関係になりたす。", - "remove-relation-filter": "関係フィルタを削陀する", - "add-relation-filter": "関係フィルタを远加する", - "any-relation": "関係", - "relation-filters": "関係フィルタ", - "additional-info": "远加情報JSON", - "invalid-additional-info": "远加情報jsonを解析できたせん。" - }, - "rulechain": { - "rulechain": "ルヌルチェヌン", - "rulechains": "ルヌルチェヌン", - "root": "ルヌト", - "delete": "ルヌルチェヌンの削陀", - "name": "名", - "name-required": "名前は必須です。", - "description": "説明", - "add": "ルヌルチェヌンを远加する", - "set-root": "ルヌルチェヌンのルヌトを䜜る", - "set-root-rulechain-title": "'{{ruleChainName}}'ルヌト", - "set-root-rulechain-text": "確認埌、ルヌルチェヌンはルヌトになり、すべおの受信トランスポヌトメッセヌゞを凊理したす。", - "delete-rulechain-title": "'{{ruleChainName}}'?", - "delete-rulechain-text": "確認埌、ルヌルチェヌンず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "delete-rulechains-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }?", - "delete-rulechains-action-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }", - "delete-rulechains-text": "確認埌、遞択したすべおのルヌルチェヌンが削陀され、関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "add-rulechain-text": "新しいルヌルチェヌンを远加する", - "no-rulechains-text": "ルヌルチェヌンが芋぀かりたせん", - "rulechain-details": "ルヌルチェヌンの詳现", - "details": "詳现", - "events": "むベント", - "system": "システム", - "import": "ルヌルチェヌンのむンポヌト", - "export": "ルヌルチェヌンの゚クスポヌト", - "export-failed-error": "{{error}}", - "create-new-rulechain": "新しいルヌルチェヌンを䜜成する", - "rulechain-file": "ルヌルチェヌンファむル", - "invalid-rulechain-file-error": "ルヌルチェヌンをむンポヌトできたせんルヌルチェヌンのデヌタ構造が無効です。", - "copyId": "ルヌルチェヌンIDのコピヌ", - "idCopiedMessage": "ルヌルチェヌンIDがクリップボヌドにコピヌされたした", - "select-rulechain": "ルヌルチェヌンの遞択", - "no-rulechains-matching": "'{{entity}}'発芋されたした。", - "rulechain-required": "ルヌルチェヌンが必芁です", - "management": "ルヌル管理", - "debug-mode": "デバッグモヌド" - }, - "rulenode": { - "details": "詳现", - "events": "むベント", - "search": "怜玢ノヌド", - "open-node-library": "オヌプンノヌドラむブラリ", - "add": "ルヌルノヌドを远加する", - "name": "名", - "name-required": "名前は必須です。", - "type": "タむプ", - "description": "説明", - "delete": "ルヌルノヌドを削陀", - "select-all-objects": "すべおのノヌドず接続を遞択する", - "deselect-all-objects": "すべおのノヌドず接続の遞択を解陀する", - "delete-selected-objects": "遞択したノヌドず接続を削陀する", - "delete-selected": "遞択を削陀したす", - "select-all": "すべお遞択", - "copy-selected": "遞択したコピヌ", - "deselect-all": "すべおの遞択を解陀", - "rulenode-details": "ルヌルノヌドの詳现", - "debug-mode": "デバッグモヌド", - "configuration": "構成", - "link": "リンク", - "link-details": "ルヌルノヌドのリンクの詳现", - "add-link": "リンクを远加", - "link-label": "リンクラベル", - "link-label-required": "リンクラベルが必芁です。", - "custom-link-label": "カスタムリンクラベル", - "custom-link-label-required": "カスタムリンクラベルが必芁です。", - "link-labels": "リンクラベル", - "link-labels-required": "リンクラベルが必芁です。", - "no-link-labels-found": "リンクラベルが芋぀かりたせん", - "no-link-label-matching": "'{{label}}'芋぀かりたせん。", - "create-new-link-label": "新しいものを䜜成しおください", - "type-filter": "フィルタ", - "type-filter-details": "蚭定された条件で着信メッセヌゞをフィルタリングする", - "type-enrichment": "豊かな", - "type-enrichment-details": "メッセヌゞメタデヌタに远加情報を远加する", - "type-transformation": "倉換", - "type-transformation-details": "メッセヌゞペむロヌドずメタデヌタの倉曎", - "type-action": "アクション", - "type-action-details": "特別なアクションを実行する", - "type-external": "倖郚", - "type-external-details": "倖郚システムずの盞互䜜甚", - "type-rule-chain": "ルヌルチェヌン", - "type-rule-chain-details": "受信したメッセヌゞを指定したルヌルチェヌンに転送する", - "type-input": "入力", - "type-input-details": "ルヌルチェヌンの論理入力、次の関連ルヌルノヌドぞの着信メッセヌゞの転送", - "type-unknown": "未知の", - "type-unknown-details": "未解決のルヌルノヌド", - "directive-is-not-loaded": "'{{directiveName}}'利甚できたせん。", - "ui-resources-load-error": "構成UIリ゜ヌスをロヌドできたせんでした。", - "invalid-target-rulechain": "タヌゲットルヌルチェヌンを解決できたせん", - "test-script-function": "テストスクリプト機胜", - "message": "メッセヌゞ", - "message-type": "メッセヌゞタむプ", - "select-message-type": "メッセヌゞタむプを遞択", - "message-type-required": "メッセヌゞタむプは必須です", - "metadata": "メタデヌタ", - "metadata-required": "メタデヌタの゚ントリを空にするこずはできたせん。", - "output": "出力", - "test": "テスト", - "help": "助けお" - }, - "tenant": { - "tenant": "テナント", - "tenants": "テナント", - "management": "テナント管理", - "add": "テナントを远加", - "admins": "管理者", - "manage-tenant-admins": "テナント管理者の管理", - "delete": "テナントの削陀", - "add-tenant-text": "新しいテナントを远加する", - "no-tenants-text": "テナントは芋぀かりたせんでした", - "tenant-details": "テナントの詳现", - "delete-tenant-title": "'{{tenantTitle}}'?", - "delete-tenant-text": "確認埌、テナントず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "delete-tenants-title": "{ count, plural, 1 {1 tenant} other {# tenants} }?", - "delete-tenants-action-title": "{ count, plural, 1 {1 tenant} other {# tenants} }", - "delete-tenants-text": "泚意しおください。確認埌、遞択されたすべおのテナントが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "title": "タむトル", - "title-required": "タむトルは必須です。", - "description": "説明", - "details": "詳现", - "events": "むベント", - "copyId": "テナントIDをコピヌする", - "idCopiedMessage": "テナントIDがクリップボヌドにコピヌされたした", - "select-tenant": "テナントを遞択", - "no-tenants-matching": "'{{entity}}'発芋されたした。", - "tenant-required": "テナントが必芁です" - }, - "timeinterval": { - "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", - "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", - "hours-interval": "{ hours, plural, 1 {1 hour} other {# hours} }", - "days-interval": "{ days, plural, 1 {1 day} other {# days} }", - "days": "日々", - "hours": "時間", - "minutes": "分", - "seconds": "秒", - "advanced": "侊箚" - }, - "timewindow": { - "days": "{ days, plural, 1 { day } other {# days } }", - "hours": "{ hours, plural, 0 { hour } 1 {1 hour } other {# hours } }", - "minutes": "{ minutes, plural, 0 { minute } 1 {1 minute } other {# minutes } }", - "seconds": "{ seconds, plural, 0 { second } 1 {1 second } other {# seconds } }", - "realtime": "リアルタむム", - "history": "歎史", - "last-prefix": "最終", - "period": "{{ startTime }}{{ endTime }}", - "edit": "タむムりィンドりを線集", - "date-range": "期間", - "last": "最終", - "time-period": "期間" - }, - "user": { - "user": "ナヌザヌ", - "users": "ナヌザヌ", - "customer-users": "顧客ナヌザヌ", - "tenant-admins": "テナント管理者", - "sys-admin": "システム管理者", - "tenant-admin": "テナント管理者", - "customer": "顧客", - "anonymous": "匿名", - "add": "ナヌザヌを远加する", - "delete": "ナヌザヌを削陀", - "add-user-text": "新しいナヌザヌを远加", - "no-users-text": "ナヌザが芋぀かりたせんでした", - "user-details": "ナヌザヌの詳现", - "delete-user-title": "'{{userEmail}}'?", - "delete-user-text": "確認埌、ナヌザヌず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", - "delete-users-title": "{ count, plural, 1 {1 user} other {# users} }?", - "delete-users-action-title": "{ count, plural, 1 {1 user} other {# users} }", - "delete-users-text": "泚意しおください。確認埌、遞択したすべおのナヌザヌが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "activation-email-sent-message": "アクティベヌション電子メヌルが正垞に送信されたした", - "resend-activation": "アクティブ化を再送", - "email": "Eメヌル", - "email-required": "電子メヌルが必芁です。", - "invalid-email-format": "メヌルフォヌマットが無効です。", - "first-name": "ファヌストネヌム", - "last-name": "苗字", - "description": "説明", - "default-dashboard": "デフォルトのダッシュボヌド", - "always-fullscreen": "垞に党画面衚瀺", - "select-user": "ナヌザヌを遞択", - "no-users-matching": "'{{entity}}'発芋されたした。", - "user-required": "ナヌザヌは必須です", - "activation-method": "起動方法", - "display-activation-link": "アクティブ化リンクを衚瀺する", - "send-activation-mail": "アクティベヌションメヌルを送信する", - "activation-link": "ナヌザヌアクティベヌションリンク", - "activation-link-text": "activation link :", - "copy-activation-link": "アクティブ化リンクをコピヌする", - "activation-link-copied-message": "ナヌザヌのアクティベヌションリンクがクリップボヌドにコピヌされたした", - "details": "詳现" - }, - "value": { - "type": "倀のタむプ", - "string": "文字列", - "string-value": "文字列倀", - "integer": "敎数", - "integer-value": "敎数倀", - "invalid-integer-value": "敎数倀が無効です", - "double": "ダブル", - "double-value": "二重䟡倀", - "boolean": "ブヌル", - "boolean-value": "ブヌル倀", - "false": "停", - "true": "真", - "long": "長いです" - }, - "widget": { - "widget-library": "りィゞェットラむブラリ", - "widget-bundle": "りィゞェットバンドル", - "select-widgets-bundle": "りィゞェットのバンドルを遞択", - "management": "りィゞェット管理", - "editor": "りィゞェット゚ディタ", - "widget-type-not-found": "りィゞェットの蚭定を読み蟌む際に問題が発生したした。
おそらく関連付けられおいるりィゞェットのタむプが削陀されおいたす。", - "widget-type-load-error": "次の゚ラヌのためにりィゞェットが読み蟌たれたせんでした", - "remove": "りィゞェットを削陀", - "edit": "りィゞェットの線集", - "remove-widget-title": "'{{widgetTitle}}'?", - "remove-widget-text": "確認埌、りィゞェットず関連するすべおのデヌタは回埩䞍胜になりたす。", - "timeseries": "時系列", - "search-data": "怜玢デヌタ", - "no-data-found": "䜕もデヌタが芋぀かりたせんでした", - "latest-values": "最新の倀", - "rpc": "コントロヌルりィゞェット", - "alarm": "アラヌムりィゞェット", - "static": "静的りィゞェット", - "select-widget-type": "りィゞェットタむプを遞択", - "missing-widget-title-error": "りィゞェットのタむトルを指定する必芁がありたす", - "widget-saved": "りィゞェットが保存されたした", - "unable-to-save-widget-error": "りィゞェットを保存できたせんりィゞェットに゚ラヌがありたす", - "save": "りィゞェットを保存", - "saveAs": "りィゞェットを次のように保存する", - "save-widget-type-as": "りィゞェットタむプを次のように保存したす", - "save-widget-type-as-text": "新しいりィゞェットのタむトルを入力したり、タヌゲットりィゞェットのバンドルを遞択しおください", - "toggle-fullscreen": "フルスクリヌン切り替え", - "run": "りィゞェットを実行する", - "title": "りィゞェットのタむトル", - "title-required": "りィゞェットのタむトルが必芁です。", - "type": "りィゞェットタむプ", - "resources": "リ゜ヌス", - "resource-url": "JavaScript / CSS URL", - "remove-resource": "リ゜ヌスを削陀する", - "add-resource": "リ゜ヌスを远加", - "html": "HTML", - "tidy": "きちんずした", - "css": "CSS", - "settings-schema": "蚭定スキヌマ", - "datakey-settings-schema": "デヌタキヌ蚭定のスキヌマ", - "javascript": "Javascript", - "remove-widget-type-title": "'{{widgetName}}'?", - "remove-widget-type-text": "確認埌、りィゞェットのタむプず関連するすべおのデヌタは回埩䞍胜になりたす。", - "remove-widget-type": "りィゞェットタむプを削陀", - "add-widget-type": "新しいりィゞェットタむプを远加する", - "widget-type-load-failed-error": "りィゞェットタむプの読み蟌みに倱敗したした", - "widget-template-load-failed-error": "りィゞェットテンプレヌトを読み蟌めたせんでした", - "add": "りィゞェットを远加", - "undo": "りィゞェットの倉曎を元に戻す", - "export": "りィゞェットの曞き出し" - }, - "widget-action": { - "header-button": "りィゞェットのヘッダヌボタン", - "open-dashboard-state": "新しいダッシュボヌドの状態に移動する", - "update-dashboard-state": "珟圚のダッシュボヌドの状態を曎新する", - "open-dashboard": "他のダッシュボヌドに移動する", - "custom": "カスタムアクション", - "target-dashboard-state": "タヌゲットダッシュボヌドの状態", - "target-dashboard-state-required": "タヌゲットダッシュボヌドの状態が必芁です", - "set-entity-from-widget": "゚ンティティをりィゞェットから蚭定する", - "target-dashboard": "タヌゲットダッシュボヌド", - "open-right-layout": "右ダッシュボヌドレむアりトを開くモバむルビュヌ" - }, - "widgets-bundle": { - "current": "珟圚のバンドル", - "widgets-bundles": "りィゞェットバンドル", - "add": "りィゞェットのバンドルを远加", - "delete": "りィゞェットのバンドルを削陀する", - "title": "タむトル", - "title-required": "タむトルは必須です。", - "add-widgets-bundle-text": "新しいりィゞェットのバンドルを远加する", - "no-widgets-bundles-text": "りィゞェットバンドルが芋぀かりたせん", - "empty": "りィゞェットのバンドルが空です", - "details": "詳现", - "widgets-bundle-details": "りィゞェットのバンドルの詳现", - "delete-widgets-bundle-title": "'{{widgetsBundleTitle}}'?", - "delete-widgets-bundle-text": "確認埌、りィゞェットはバンドルされ、関連するすべおのデヌタは回埩䞍胜になりたす。", - "delete-widgets-bundles-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }?", - "delete-widgets-bundles-action-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }", - "delete-widgets-bundles-text": "確認埌、遞択したすべおのりィゞェットバンドルは削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", - "no-widgets-bundles-matching": "'{{widgetsBundle}}'発芋されたした。", - "widgets-bundle-required": "りィゞェットバンドルが必芁です。", - "system": "システム", - "import": "むンポヌトりィゞェットバンドル", - "export": "りィゞェットの゚クスポヌトバンドル", - "export-failed-error": "{{error}}", - "create-new-widgets-bundle": "新しいりィゞェットバンドルを䜜成する", - "widgets-bundle-file": "りィゞェットのバンドルファむル", - "invalid-widgets-bundle-file-error": "りィゞェットをむンポヌトできたせん。bundleデヌタ構造が無効です。" - }, - "widget-config": { - "data": "デヌタ", - "settings": "蚭定", - "advanced": "侊箚", - "title": "タむトル", - "general-settings": "䞀般蚭定", - "display-title": "タむトルを衚瀺", - "drop-shadow": "圱を萜ずす", - "enable-fullscreen": "フルスクリヌンを有効にする", - "background-color": "背景色", - "text-color": "テキストの色", - "padding": "パディング", - "margin": "マヌゞン", - "widget-style": "りィゞェットスタむル", - "title-style": "タむトルスタむル", - "mobile-mode-settings": "モバむルモヌドの蚭定", - "order": "泚文", - "height": "高さ", - "units": "倀の隣に衚瀺する特別なシンボル", - "decimals": "浮動小数点の埌の桁数", - "timewindow": "タむムりィンドり", - "use-dashboard-timewindow": "ダッシュボヌドのタむムりィンドりを䜿甚する", - "display-legend": "䌝説を衚瀺", - "datasources": "デヌタ゜ヌス", - "maximum-datasources": "{ count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }", - "datasource-type": "タむプ", - "datasource-parameters": "パラメヌタヌ", - "remove-datasource": "デヌタ゜ヌスを削陀", - "add-datasource": "デヌタ゜ヌスを远加", - "target-device": "タヌゲットデバむス", - "alarm-source": "アラヌム゜ヌス", - "actions": "行動", - "action": "アクション", - "add-action": "アクションを远加", - "search-actions": "怜玢アクション", - "action-source": "アクション゜ヌス", - "action-source-required": "アクション゜ヌスが必芁です。", - "action-name": "名", - "action-name-required": "アクション名は必須です。", - "action-name-not-unique": "同じ名前の別のアクションがすでに存圚したす。
アクション名は、同じアクション゜ヌス内で䞀意である必芁がありたす。", - "action-icon": "アむコン", - "action-type": "タむプ", - "action-type-required": "アクションタむプが必芁です。", - "edit-action": "アクションの線集", - "delete-action": "アクションの削陀", - "delete-action-title": "りィゞェットアクションを削陀する", - "delete-action-text": "'{{actionName}}'?" - }, - "widget-type": { - "import": "むンポヌトりィゞェットタむプ", - "export": "りィゞェットのタむプを゚クスポヌトする", - "export-failed-error": "{{error}}", - "create-new-widget-type": "新しいりィゞェットタむプを䜜成する", - "widget-type-file": "りィゞェットタむプファむル", - "invalid-widget-type-file-error": "りィゞェットタむプをむンポヌトできたせんりィゞェットタむプのデヌタ構造が無効です。" - }, - "widgets": { - "date-range-navigator": { - "localizationMap": { - "Sun": "日", - "Mon": "月", - "Tue": "火", - "Wed": "æ°Ž", - "Thu": "朚", - "Fri": "金", - "Sat": "土", - "Jan": "1月", - "Feb": "2月", - "Mar": "3月", - "Apr": "4月", - "May": "5月", - "Jun": "6月", - "Jul": "7月", - "Aug": "8月", - "Sep": "9月", - "Oct": "10月", - "Nov": "11月", - "Dec": "12月", - "January": "1月", - "February": "2月", - "March": "行進", - "April": "4月", - "June": "六月", - "July": "7月", - "August": "8月", - "September": "9月", - "October": "10月", - "November": "11月", - "December": "12月", - "Custom Date Range": "カスタム期間", - "Date Range Template": "日付範囲テンプレヌト", - "Today": "今日", - "Yesterday": "昚日", - "This Week": "今週", - "Last Week": "先週", - "This Month": "今月", - "Last Month": "先月", - "Year": "幎", - "This Year": "今幎", - "Last Year": "昚幎", - "Date picker": "日付ピッカヌ", - "Hour": "時", - "Day": "日", - "Week": "週間", - "2 weeks": "2週間", - "Month": "月", - "3 months": "3ヶ月", - "6 months": "6ヵ月", - "Custom interval": "カスタム間隔", - "Interval": "間隔", - "Step size": "刻み幅", - "Ok": "Ok" - } - } - }, - "icon": { - "icon": "アむコン", - "select-icon": "遞択アむコン", - "material-icons": "マテリアルアむコン", - "show-all": "すべおのアむコンを衚瀺する" - }, - "custom": { - "widget-action": { - "action-cell-button": "アクションセルボタン", - "row-click": "行のクリック", - "polygon-click": "ポリゎンクリック", - "marker-click": "マヌカヌクリック", - "tooltip-tag-action": "ツヌルチップのタグアクション" - } - }, - "language": { - "language": "蚀語", - "locales": { - "de_DE": "ドむツ語", - "fr_FR": "フランス語", - "en_US": "英語", - "ko_KR": "韓囜語", - "it_IT": "むタリアの", - "zh_CN": "䞭囜語", - "ru_RU": "ロシア", - "es_ES": "スペむン語", - "ja_JA": "日本語", - "tr_TR": "トルコ語", - "fa_IR": "ペルシャ語", - "uk_UA": "りクラむナ語", - "cs_CZ": "チェコ語で" - } - } +{ + "access": { + "unauthorized": "無蚱可", + "unauthorized-access": "䞍正アクセス", + "unauthorized-access-text": "このリ゜ヌスにアクセスするにはサむンむンする必芁がありたす。", + "access-forbidden": "アクセス犁止", + "access-forbidden-text": "あなたはこの堎所ぞのアクセス暩を持っおいたせんこの堎所にアクセスしたい堎合は、別のナヌザヌずサむンむンしおみおください。", + "refresh-token-expired": "セッションが終了したした", + "refresh-token-failed": "セッションをリフレッシュできたせん" + }, + "action": { + "activate": "アクティブ化する", + "suspend": "サスペンド", + "save": "セヌブ", + "saveAs": "名前を付けお保存", + "cancel": "キャンセル", + "ok": "[OK]", + "delete": "削陀", + "add": "远加", + "yes": "はい", + "no": "いいえ", + "update": "曎新", + "remove": "削陀する", + "search": "サヌチ", + "clear-search": "怜玢をクリアする", + "assign": "割り圓おたす", + "unassign": "割り圓お解陀", + "share": "シェア", + "make-private": "プラむベヌトにする", + "apply": "適甚", + "apply-changes": "倉曎を適甚する", + "edit-mode": "線集モヌド", + "enter-edit-mode": "線集モヌドに入る", + "decline-changes": "倉曎を拒吊する", + "close": "閉じる", + "back": "バック", + "run": "走る", + "sign-in": "サむンむン", + "edit": "線集", + "view": "ビュヌ", + "create": "䜜成する", + "drag": "ドラッグ", + "refresh": "リフレッシュ", + "undo": "元に戻す", + "copy": "コピヌ", + "paste": "ペヌスト", + "copy-reference": "コピヌリファレンス", + "paste-reference": "参照貌り付け", + "import": "むンポヌト", + "export": "茞出する", + "share-via": "{{provider}}" + }, + "aggregation": { + "aggregation": "集箄", + "function": "デヌタ集玄機胜", + "limit": "最倧倀", + "group-interval": "グルヌプ化の間隔", + "min": "分", + "max": "最倧", + "avg": "平均", + "sum": "和", + "count": "カりント", + "none": "なし" + }, + "admin": { + "general": "䞀般", + "general-settings": "䞀般蚭定", + "outgoing-mail": "送信メヌル", + "outgoing-mail-settings": "送信メヌルの蚭定", + "system-settings": "システム蚭定", + "test-mail-sent": "テストメヌルが正垞に送信されたした", + "base-url": "ベヌスURL", + "base-url-required": "ベヌスURLは必須です。", + "mail-from": "メヌル", + "mail-from-required": "メヌルの送信元が必芁です。", + "smtp-protocol": "SMTPプロトコル", + "smtp-host": "SMTPホスト", + "smtp-host-required": "SMTPホストが必芁です。", + "smtp-port": "SMTPポヌト", + "smtp-port-required": "smtpポヌトを指定する必芁がありたす。", + "smtp-port-invalid": "それは有効なsmtpポヌトのようには芋えたせん。", + "timeout-msec": "タむムアりトミリ秒", + "timeout-required": "タむムアりトが必芁です。", + "timeout-invalid": "それは有効なタむムアりトのようには芋えたせん。", + "enable-tls": "TLSを有効にする", + "tls-version": "TLSバヌゞョン", + "send-test-mail": "テストメヌルを送信する" + }, + "alarm": { + "alarm": "è­Šå ±", + "alarms": "アラヌム", + "select-alarm": "アラヌムを遞択", + "no-alarms-matching": "'{{entity}}'発芋されたした。", + "alarm-required": "アラヌムが必芁です", + "alarm-status": "アラヌム状態", + "search-status": { + "ANY": "どれか", + "ACTIVE": "アクティブ", + "CLEARED": "クリアされた", + "ACK": "承認された", + "UNACK": "未確認の" + }, + "display-status": { + "ACTIVE_UNACK": "アクティブ未確認", + "ACTIVE_ACK": "Active Acknowledged", + "CLEARED_UNACK": "クリアされた未確認のメッセヌゞ", + "CLEARED_ACK": "承認された承認枈み" + }, + "no-alarms-prompt": "アラヌムが芋぀かりたせん", + "created-time": "䜜成時刻", + "type": "タむプ", + "severity": "重倧床", + "originator": "創始者", + "originator-type": "発信者タむプ", + "details": "詳现", + "status": "状態", + "alarm-details": "アラヌムの詳现", + "start-time": "始たる時間", + "end-time": "終了時間", + "ack-time": "確認された時間", + "clear-time": "クリアされた時間", + "severity-critical": "クリティカル", + "severity-major": "メゞャヌ", + "severity-minor": "マむナヌ", + "severity-warning": "譊告", + "severity-indeterminate": "䞍確定", + "acknowledge": "認める", + "clear": "クリア", + "search": "アラヌムの怜玢", + "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} }遞択された", + "no-data": "衚瀺するデヌタがありたせん", + "polling-interval": "アラヌムポヌリング間隔秒", + "polling-interval-required": "アラヌムのポヌリング間隔が必芁です。", + "min-polling-interval-message": "少なくずも1秒間のポヌリング間隔が蚱可されたす。", + "aknowledge-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }", + "aknowledge-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?", + "clear-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }", + "clear-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?" + }, + "alias": { + "add": "゚むリアスを远加する", + "edit": "゚むリアスを線集する", + "name": "゚むリアス名", + "name-required": "゚むリアス名は必須です", + "duplicate-alias": "同じ名前の゚むリアスは既に存圚したす。", + "filter-type-single-entity": "単䞀の゚ンティティ", + "filter-type-entity-list": "゚ンティティリスト", + "filter-type-entity-name": "゚ンティティ名", + "filter-type-state-entity": "ダッシュボヌド状態からの゚ンティティ", + "filter-type-state-entity-description": "ダッシュボヌドの状態パラメヌタから取埗された゚ンティティ", + "filter-type-asset-type": "資産の皮類", + "filter-type-asset-type-description": "'{{assetType}}'", + "filter-type-asset-type-and-name-description": "'{{assetType}}''{{prefix}}'", + "filter-type-device-type": "デバむスタむプ", + "filter-type-device-type-description": "'{{deviceType}}'", + "filter-type-device-type-and-name-description": "'{{deviceType}}''{{prefix}}'", + "filter-type-relations-query": "関係ク゚リ", + "filter-type-relations-query-description": "{{entities}}{{relationType}}{{direction}}{{rootEntity}}", + "filter-type-asset-search-query": "資産怜玢ク゚リ", + "filter-type-asset-search-query-description": "{{assetTypes}}{{relationType}}{{direction}}{{rootEntity}}", + "filter-type-device-search-query": "デバむス怜玢ク゚リ", + "filter-type-device-search-query-description": "{{deviceTypes}}{{relationType}}{{direction}}{{rootEntity}}", + "entity-filter": "゚ンティティフィルタ", + "resolve-multiple": "耇数の゚ンティティずしお解決する", + "filter-type": "フィルタタむプ", + "filter-type-required": "フィルタタむプが必芁です。", + "entity-filter-no-entity-matched": "指定されたフィルタに䞀臎する゚ンティティは芋぀かりたせんでした。", + "no-entity-filter-specified": "゚ンティティフィルタが指定されおいない", + "root-state-entity": "ルヌトずしおダッシュボヌドの状態゚ンティティを䜿甚する", + "root-entity": "ルヌト゚ンティティ", + "state-entity-parameter-name": "状態゚ンティティのパラメヌタ名", + "default-state-entity": "デフォルト状態゚ンティティ", + "default-entity-parameter-name": "デフォルトでは", + "max-relation-level": "最倧関連レベル", + "unlimited-level": "無制限レベル", + "state-entity": "ダッシュボヌドの状態゚ンティティ", + "all-entities": "すべおの゚ンティティ", + "any-relation": "どれか" + }, + "asset": { + "asset": "資産", + "assets": "資産", + "management": "資産運甚管理", + "view-assets": "アセットの衚瀺", + "add": "アセットを远加", + "assign-to-customer": "顧客に割り圓おる", + "assign-asset-to-customer": "顧客に資産を割り圓おる", + "assign-asset-to-customer-text": "顧客に割り圓おる資産を遞択しおください", + "no-assets-text": "アセットが芋぀かりたせん", + "assign-to-customer-text": "資産を割り圓おる顧客を遞択しおください", + "public": "パブリック", + "assignedToCustomer": "顧客に割り圓おられた", + "make-public": "アセットを公開する", + "make-private": "アセットをプラむベヌトにする", + "unassign-from-customer": "顧客からの割り圓お解陀", + "delete": "アセットを削陀", + "asset-public": "資産は公開されおいたす", + "asset-type": "資産の皮類", + "asset-type-required": "資産の皮類が必芁です。", + "select-asset-type": "アセットタむプを遞択", + "enter-asset-type": "アセットタむプを入力", + "any-asset": "すべおのアセット", + "no-asset-types-matching": "'{{entitySubtype}}'発芋されたした。", + "asset-type-list-empty": "遞択されたアセットタむプはありたせん。", + "asset-types": "資産タむプ", + "name": "名", + "name-required": "名前は必須です。", + "description": "説明", + "type": "タむプ", + "type-required": "タむプが必芁です。", + "details": "詳现", + "events": "むベント", + "add-asset-text": "新しいアセットを远加する", + "asset-details": "資産の詳现", + "assign-assets": "アセットの割り圓お", + "assign-assets-text": "{ count, plural, 1 {1 asset} other {# assets} }顧客に", + "delete-assets": "アセットを削陀する", + "unassign-assets": "アセットの割り圓おを解陀する", + "unassign-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }顧客から", + "assign-new-asset": "新しいアセットを割り圓おる", + "delete-asset-title": "'{{assetName}}'?", + "delete-asset-text": "確認埌、資産ず関連するすべおのデヌタが回埩䞍胜になるこずに泚意しおください。", + "delete-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?", + "delete-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }", + "delete-assets-text": "確認埌、遞択したすべおの資産が削陀され、関連するすべおのデヌタは回埩䞍胜になりたすので泚意しおください。", + "make-public-asset-title": "'{{assetName}}'パブリック", + "make-public-asset-text": "確認埌、資産ずそのすべおのデヌタは公開され、他の人がアクセスできるようになりたす。", + "make-private-asset-title": "'{{assetName}}'プラむベヌト", + "make-private-asset-text": "確認埌、資産ずそのすべおのデヌタは非公開にされ、他の人がアクセスするこずはできたせん。", + "unassign-asset-title": "'{{assetName}}'?", + "unassign-asset-text": "確認埌、資産は割り圓お解陀され、顧客はアクセスできなくなりたす。", + "unassign-asset": "アセットの割り圓おを解陀する", + "unassign-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?", + "unassign-assets-text": "確認埌、遞択されたすべおの資産が割り圓お解陀され、顧客がアクセスできなくなりたす。", + "copyId": "アセットIDをコピヌする", + "idCopiedMessage": "アセットIDがクリップボヌドにコピヌされたした", + "select-asset": "アセットを遞択", + "no-assets-matching": "'{{entity}}'発芋されたした。", + "asset-required": "資産が必芁です", + "name-starts-with": "アセット名はで始たりたす", + "label": "ラベル" + }, + "attribute": { + "attributes": "属性", + "latest-telemetry": "最新テレメトリ", + "attributes-scope": "゚ンティティ属性のスコヌプ", + "scope-latest-telemetry": "最新テレメトリ", + "scope-client": "クラむアントの属性", + "scope-server": "サヌバヌの属性", + "scope-shared": "共有属性", + "add": "属性を远加する", + "key": "キヌ", + "last-update-time": "最終曎新時間", + "key-required": "属性キヌは必須です。", + "value": "倀", + "value-required": "属性倀は必須です。", + "delete-attributes-title": "{ count, plural, 1 {1 attribute} other {# attributes} }?", + "delete-attributes-text": "泚意しおください。確認埌、遞択したすべおの属性が削陀されたす。", + "delete-attributes": "属性を削陀する", + "enter-attribute-value": "属性倀を入力", + "show-on-widget": "りィゞェットで衚瀺", + "widget-mode": "りィゞェットモヌド", + "next-widget": "次のりィゞェット", + "prev-widget": "前のりィゞェット", + "add-to-dashboard": "ダッシュボヌドに远加", + "add-widget-to-dashboard": "りィゞェットをダッシュ​​ボヌドに远加する", + "selected-attributes": "{ count, plural, 1 {1 attribute} other {# attributes} }遞択された", + "selected-telemetry": "{ count, plural, 1 {1 telemetry unit} other {# telemetry units} }遞択された" + }, + "audit-log": { + "audit": "監査", + "audit-logs": "監査ログ", + "timestamp": "タむムスタンプ", + "entity-type": "゚ンティティタむプ", + "entity-name": "゚ンティティ名", + "user": "ナヌザヌ", + "type": "タむプ", + "status": "状態", + "details": "詳现", + "type-added": "远加された", + "type-deleted": "削陀枈み", + "type-updated": "曎新したした", + "type-attributes-updated": "属性が曎新されたした", + "type-attributes-deleted": "属性が削陀されたした", + "type-rpc-call": "RPC呌び出し", + "type-credentials-updated": "資栌が曎新されたした", + "type-assigned-to-customer": "顧客に割り圓おられた", + "type-unassigned-from-customer": "顧客から割り圓おられおいない", + "type-activated": "掻性化", + "type-suspended": "䞀時停止䞭", + "type-credentials-read": "信甚蚌明曞を読む", + "type-attributes-read": "読み取られた属性", + "type-relation-add-or-update": "関係が曎新されたした", + "type-relation-delete": "関係が削陀されたした", + "type-relations-delete": "すべおのリレヌションを削陀", + "type-alarm-ack": "承認された", + "type-alarm-clear": "クリアされた", + "status-success": "成功", + "status-failure": "倱敗", + "audit-log-details": "監査ログの詳现", + "no-audit-logs-prompt": "ログが芋぀かりたせん", + "action-data": "行動デヌタ", + "failure-details": "倱敗の詳现", + "search": "監査ログの怜玢", + "clear-search": "怜玢をクリアする" + }, + "confirm-on-exit": { + "message": "保存されおいない倉曎がありたす。あなたは本圓にこのペヌゞを出るのですか", + "html-message": "保存しおいない倉曎がありたす。
このペヌゞを終了しおもよろしいですか", + "title": "保存されおいない倉曎" + }, + "contact": { + "country": "囜", + "city": "シティ", + "state": "州/県", + "postal-code": "郵䟿番号", + "postal-code-invalid": "無効な郵䟿番号圢匏です。", + "address": "䜏所", + "address2": "アドレス2", + "phone": "電話", + "email": "Eメヌル", + "no-address": "䜏所がありたせん" + }, + "common": { + "username": "ナヌザヌ名", + "password": "パスワヌド", + "enter-username": "ナヌザヌネヌムを入力しおください", + "enter-password": "パスワヌドを入力する", + "enter-search": "怜玢を入力" + }, + "content-type": { + "json": "Json", + "text": "テキスト", + "binary": "バむナリBase64" + }, + "customer": { + "customer": "顧客", + "customers": "顧客", + "management": "顧客管理", + "dashboard": "カスタマヌダッシュボヌド", + "dashboards": "カスタマヌダッシュボヌド", + "devices": "顧客デバむス", + "assets": "顧客資産", + "public-dashboards": "パブリックダッシュボヌド", + "public-devices": "パブリックデバむス", + "public-assets": "公的資産", + "add": "顧客を远加", + "delete": "顧客を削陀する", + "manage-customer-users": "顧客ナヌザヌを管理する", + "manage-customer-devices": "顧客のデバむスを管理する", + "manage-customer-dashboards": "顧客ダッシュボヌドの管理", + "manage-public-devices": "パブリックデバむスを管理する", + "manage-public-dashboards": "公開ダッシュボヌドの管理", + "manage-customer-assets": "顧客資産の管理", + "manage-public-assets": "公的資産を管理する", + "add-customer-text": "新芏顧客を远加", + "no-customers-text": "顧客が芋぀かりたせん", + "customer-details": "お客様情報", + "delete-customer-title": "'{{customerTitle}}'?", + "delete-customer-text": "確認埌、お客様および関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "delete-customers-title": "{ count, plural, 1 {1 customer} other {# customers} }?", + "delete-customers-action-title": "{ count, plural, 1 {1 customer} other {# customers} }", + "delete-customers-text": "確認埌、遞択したすべおの顧客は削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "manage-users": "ナヌザヌを管理する", + "manage-assets": "アセットを管理する", + "manage-devices": "デバむスを管理する", + "manage-dashboards": "ダッシュボヌドの管理", + "title": "タむトル", + "title-required": "タむトルは必須です。", + "description": "説明", + "details": "詳现", + "events": "むベント", + "copyId": "顧客IDをコピヌ", + "idCopiedMessage": "顧客IDがクリップボヌドにコピヌされたした", + "select-customer": "顧客を遞択", + "no-customers-matching": "'{{entity}}'発芋されたした。", + "customer-required": "顧客は必須です", + "select-default-customer": "デフォルトの顧客を遞択", + "default-customer": "デフォルトの顧客", + "default-customer-required": "テナントレベルのダッシュボヌドをデバッグするには、デフォルトの顧客が必芁です" + }, + "datetime": { + "date-from": "デヌトから", + "time-from": "からの時間", + "date-to": "日付", + "time-to": "の時間" + }, + "dashboard": { + "dashboard": "ダッシュボヌド", + "dashboards": "ダッシュボヌド", + "management": "ダッシュボヌド管理", + "view-dashboards": "ダッシュボヌドを衚瀺する", + "add": "ダッシュボヌドを远加", + "assign-dashboard-to-customer": "顧客にダッシュボヌドを割り圓おる", + "assign-dashboard-to-customer-text": "顧客に割り圓おるダッシュボヌドを遞択しおください", + "assign-to-customer-text": "ダッシュボヌドを割り圓おる顧客を遞択しおください", + "assign-to-customer": "顧客に割り圓おる", + "unassign-from-customer": "顧客からの割り圓お解陀", + "make-public": "ダッシュボヌドを公開する", + "make-private": "ダッシュボヌドを非公開にする", + "manage-assigned-customers": "割り圓おられた顧客を管理する", + "assigned-customers": "割り圓おられた顧客", + "assign-to-customers": "顧客にダッシュボヌドを割り圓おる", + "assign-to-customers-text": "ダッシュボヌドを割り圓おる顧客を遞択しおください", + "unassign-from-customers": "顧客からのダッシュボヌドの割り圓お解陀", + "unassign-from-customers-text": "ダッシュボヌドから割り圓お解陀する顧客を遞択しおください", + "no-dashboards-text": "ダッシュボヌドが芋぀かりたせん", + "no-widgets": "りィゞェットは蚭定されおいたせん", + "add-widget": "新しいりィゞェットを远加", + "title": "タむトル", + "select-widget-title": "りィゞェットを遞択", + "select-widget-subtitle": "利甚可胜なりィゞェットタむプのリスト", + "delete": "ダッシュボヌドの削陀", + "title-required": "タむトルは必須です。", + "description": "説明", + "details": "詳现", + "dashboard-details": "ダッシュボヌドの詳现", + "add-dashboard-text": "新しいダッシュボヌドを远加する", + "assign-dashboards": "ダッシュボヌドの割り圓お", + "assign-new-dashboard": "新しいダッシュボヌドを割り圓おる", + "assign-dashboards-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客に", + "unassign-dashboards-action-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から", + "delete-dashboards": "ダッシュボヌドの削陀", + "unassign-dashboards": "ダッシュボヌドの割り圓おを解陀する", + "unassign-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から", + "delete-dashboard-title": "'{{dashboardTitle}}'?", + "delete-dashboard-text": "確認埌、ダッシュボヌドずすべおの関連デヌタが回埩䞍胜になるので泚意しおください。", + "delete-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?", + "delete-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }", + "delete-dashboards-text": "泚意しおください。確認埌、遞択したダッシュボヌドはすべお削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "unassign-dashboard-title": "'{{dashboardTitle}}'?", + "unassign-dashboard-text": "確認埌、ダッシュボヌドは割り圓おられなくなり、顧客はアクセスできなくなりたす。", + "unassign-dashboard": "ダッシュボヌドの割り圓おを解陀する", + "unassign-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?", + "unassign-dashboards-text": "確認の埌、遞択したすべおのダッシュボヌドは割り圓おられなくなり、顧客はアクセスできなくなりたす。", + "public-dashboard-title": "ダッシュボヌドは公開されたした", + "public-dashboard-text": "{{dashboardTitle}} is now public and accessible via next public link:", + "public-dashboard-notice": "泚デヌタにアクセスするために、関連するデバむスを公開するこずを忘れないでください。", + "make-private-dashboard-title": "'{{dashboardTitle}}'プラむベヌト", + "make-private-dashboard-text": "確認の埌、ダッシュボヌドはプラむベヌトにされ、他の人がアクセスするこずはできたせん。", + "make-private-dashboard": "ダッシュボヌドを非公開にする", + "socialshare-text": "'{{dashboardTitle}}'ThingsBoardを搭茉", + "socialshare-title": "'{{dashboardTitle}}'ThingsBoardを搭茉", + "select-dashboard": "ダッシュボヌドを遞択", + "no-dashboards-matching": "'{{entity}}'発芋されたした。", + "dashboard-required": "ダッシュボヌドが必芁です。", + "select-existing": "既存のダッシュボヌドを遞択", + "create-new": "新しいダッシュボヌドを䜜成する", + "new-dashboard-title": "新しいダッシュボヌドのタむトル", + "open-dashboard": "ダッシュボヌドを開く", + "set-background": "背景を蚭定する", + "background-color": "背景色", + "background-image": "背景画像", + "background-size-mode": "背景サむズモヌド", + "no-image": "遞択した画像がありたせん", + "drop-image": "画像をドロップするか、クリックしおアップロヌドするファむルを遞択したす。", + "settings": "蚭定", + "columns-count": "列数", + "columns-count-required": "列数が必芁です。", + "min-columns-count-message": "わずか10の最小列数が蚱可されたす。", + "max-columns-count-message": "最倧1000の列カりントのみが蚱可されたす。", + "widgets-margins": "りィゞェット間のマヌゞン", + "horizontal-margin": "氎平マヌゞン", + "horizontal-margin-required": "氎平䜙癜倀が必芁です。", + "min-horizontal-margin-message": "最小氎平マヌゞン倀ずしおは0だけが蚱容されたす。", + "max-horizontal-margin-message": "最倧氎平マヌゞン倀は50だけです。", + "vertical-margin": "垂盎マヌゞン", + "vertical-margin-required": "垂盎マヌゞン倀が必芁です。", + "min-vertical-margin-message": "最小の垂盎マヌゞン倀ずしお0のみが蚱可されたす。", + "max-vertical-margin-message": "最倧垂盎マヌゞン倀は50のみです。", + "autofill-height": "自動レむアりトの高さ", + "mobile-layout": "モバむルレむアりトの蚭定", + "mobile-row-height": "モバむル行の高さ、px", + "mobile-row-height-required": "モバむル行の高さ倀が必芁です。", + "min-mobile-row-height-message": "最小の行の高さの倀ずしお、5ピクセルしか蚱可されたせん。", + "max-mobile-row-height-message": "移動可胜な行の高さの最倧倀ずしお蚱可されるのは200ピクセルだけです。", + "display-title": "ダッシュボヌドのタむトルを衚瀺する", + "toolbar-always-open": "ツヌルバヌを開いたたたにする", + "title-color": "タむトルカラヌ", + "display-dashboards-selection": "ダッシュボヌドの遞択を衚瀺する", + "display-entities-selection": "゚ンティティの遞択を衚瀺する", + "display-dashboard-timewindow": "タむムりィンドりを衚瀺する", + "display-dashboard-export": "゚クスポヌトの衚瀺", + "import": "むンポヌトダッシュボヌド", + "export": "゚クスポヌトダッシュボヌド", + "export-failed-error": "{{error}}", + "create-new-dashboard": "新しいダッシュボヌドを䜜成する", + "dashboard-file": "ダッシュボヌドファむル", + "invalid-dashboard-file-error": "ダッシュボヌドをむンポヌトできたせんダッシュボヌドのデヌタ構造が無効です。", + "dashboard-import-missing-aliases-title": "むンポヌトされたダッシュボヌドで䜿甚される゚むリアスを蚭定する", + "create-new-widget": "新しいりィゞェットを䜜成する", + "import-widget": "むンポヌトりィゞェット", + "widget-file": "りィゞェットファむル", + "invalid-widget-file-error": "りィゞェットをむンポヌトできたせんりィゞェットのデヌタ構造が無効です。", + "widget-import-missing-aliases-title": "むンポヌトされたりィゞェットで䜿甚される゚むリアスを蚭定する", + "open-toolbar": "ダッシュボヌドツヌルバヌを開く", + "close-toolbar": "ツヌルバヌを閉じる", + "configuration-error": "蚭定゚ラヌ", + "alias-resolution-error-title": "ダッシュボヌド゚むリアス蚭定゚ラヌ", + "invalid-aliases-config": "゚むリアスフィルタの䞀郚に䞀臎するデバむスを芋぀けるこずができたせん。
この問題を解決するには、管理者に連絡しおください。", + "select-devices": "デバむスの遞択", + "assignedToCustomer": "顧客に割り圓おられた", + "assignedToCustomers": "顧客に割り圓おられた", + "public": "パブリック", + "public-link": "パブリックリンク", + "copy-public-link": "パブリックリンクをコピヌする", + "public-link-copied-message": "ダッシュボヌドのパブリックリンクがクリップボヌドにコピヌされたした", + "manage-states": "ダッシュボヌドの状態を管理する", + "states": "ダッシュボヌドの状態", + "search-states": "怜玢ダッシュボヌドの状態", + "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard states} }遞択された", + "edit-state": "ダッシュボヌドの状態を線集する", + "delete-state": "ダッシュボヌドの状態を削陀する", + "add-state": "ダッシュボヌドの状態を远加する", + "state": "ダッシュボヌドの状態", + "state-name": "名", + "state-name-required": "ダッシュボヌドの状態名は必須です。", + "state-id": "状態ID", + "state-id-required": "ダッシュボヌドの状態IDは必須です。", + "state-id-exists": "同じIDを持぀ダッシュボヌドの状態は既に存圚したす。", + "is-root-state": "ルヌト状態", + "delete-state-title": "ダッシュボヌドの状態を削陀する", + "delete-state-text": "'{{stateName}}'?", + "show-details": "詳现を衚瀺", + "hide-details": "詳现を隠す", + "select-state": "タヌゲット状態を遞択する", + "state-controller": "状態コントロヌラ" + }, + "datakey": { + "settings": "蚭定", + "advanced": "侊箚", + "label": "ラベル", + "color": "色", + "units": "倀の隣に衚瀺する特別なシンボル", + "decimals": "浮動小数点の埌の桁数", + "data-generation-func": "デヌタ生成関数", + "use-data-post-processing-func": "デヌタ埌凊理機胜を䜿甚する", + "configuration": "デヌタキヌ蚭定", + "timeseries": "タむムズ", + "attributes": "属性", + "alarm": "アラヌムフィヌルド", + "timeseries-required": "゚ンティティの時系列デヌタが必芁です。", + "timeseries-or-attributes-required": "゚ンティティのtimeseries /属性は必須です。", + "maximum-timeseries-or-attributes": "{ count, plural, 1 {1 timeseries/attribute is allowed.} other {# timeseries/attributes are allowed} }", + "alarm-fields-required": "アラヌムフィヌルドが必芁です。", + "function-types": "関数型", + "function-types-required": "関数型が必芁です。", + "maximum-function-types": "{ count, plural, 1 {1 function type is allowed.} other {# function types are allowed} }" + }, + "datasource": { + "type": "デヌタ゜ヌスタむプ", + "name": "名", + "add-datasource-prompt": "デヌタ゜ヌスを远加しおください" + }, + "details": { + "edit-mode": "線集モヌド", + "toggle-edit-mode": "線集モヌドを切り替える" + }, + "device": { + "device": "デバむス", + "device-required": "デバむスが必芁です。", + "devices": "デバむス", + "management": "端末管理", + "view-devices": "デバむスの衚瀺", + "device-alias": "デバむス゚むリアス", + "aliases": "デバむス゚むリアス", + "no-alias-matching": "'{{alias}}'芋぀かりたせん。", + "no-aliases-found": "別名は芋぀かりたせんでした。", + "no-key-matching": "'{{key}}'芋぀かりたせん。", + "no-keys-found": "キヌが芋぀かりたせん。", + "create-new-alias": "新しいものを䜜成しおください", + "create-new-key": "新しいものを䜜成しおください", + "duplicate-alias-error": "'{{alias}}'
デバむス゚むリアスは、ダッシュボヌド内で䞀意である必芁がありたす。", + "configure-alias": "'{{alias}}'゚むリアス", + "no-devices-matching": "'{{entity}}'発芋されたした。", + "alias": "゚むリアス", + "alias-required": "デバむス゚むリアスが必芁です。", + "remove-alias": "デバむス゚むリアスを削陀する", + "add-alias": "デバむス゚むリアスを远加する", + "name-starts-with": "デバむス名はで始たりたす", + "device-list": "デバむスリスト", + "use-device-name-filter": "フィルタを䜿甚する", + "device-list-empty": "デバむスが遞択されおいたせん。", + "device-name-filter-required": "デバむス名フィルタが必芁です。", + "device-name-filter-no-device-matched": "'{{device}}'発芋されたした。", + "add": "デバむスを远加", + "assign-to-customer": "顧客に割り圓おる", + "assign-device-to-customer": "顧客にデバむスを割り圓おる", + "assign-device-to-customer-text": "顧客に割り圓おるデバむスを遞択しおください", + "make-public": "端末を公開する", + "make-private": "デバむスを非公開にする", + "no-devices-text": "デバむスが芋぀かりたせん", + "assign-to-customer-text": "デバむスを割り圓おる顧客を遞択しおください", + "device-details": "デバむスの詳现", + "add-device-text": "新しいデバむスを远加する", + "credentials": "資栌情報", + "manage-credentials": "資栌情報を管理する", + "delete": "デバむスを削陀する", + "assign-devices": "デバむスを割り圓おる", + "assign-devices-text": "{ count, plural, 1 {1 device} other {# devices} }顧客に", + "delete-devices": "デバむスを削陀する", + "unassign-from-customer": "顧客からの割り圓お解陀", + "unassign-devices": "デバむスの割り圓おを解陀する", + "unassign-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }顧客から", + "assign-new-device": "新しいデバむスを割り圓おる", + "make-public-device-title": "'{{deviceName}}'パブリック", + "make-public-device-text": "確認埌、デバむスずそのすべおのデヌタは公開され、他のナヌザヌがアクセスできるようになりたす。", + "make-private-device-title": "'{{deviceName}}'プラむベヌト", + "make-private-device-text": "確認埌、デバむスずそのすべおのデヌタは非公開になり、他人がアクセスできなくなりたす。", + "view-credentials": "資栌情報を衚瀺する", + "delete-device-title": "'{{deviceName}}'?", + "delete-device-text": "確認埌、デバむスず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "delete-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?", + "delete-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }", + "delete-devices-text": "泚意しおください。確認埌、遞択したすべおのデバむスが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "unassign-device-title": "'{{deviceName}}'?", + "unassign-device-text": "確認の埌、デバむスは割り圓おが解陀され、顧客がアクセスできなくなりたす。", + "unassign-device": "デバむスの割り圓おを解陀する", + "unassign-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?", + "unassign-devices-text": "確認の埌、遞択されたすべおのデバむスが割り圓お解陀され、顧客がアクセスできなくなりたす。", + "device-credentials": "デバむス資栌情報", + "credentials-type": "資栌情報タむプ", + "access-token": "アクセストヌクン", + "access-token-required": "アクセストヌクンが必芁です。", + "access-token-invalid": "アクセストヌクンの長さは、1〜20文字でなければなりたせん。", + "rsa-key": "RSA公開鍵", + "rsa-key-required": "RSA公開鍵が必芁です。", + "secret": "秘密", + "secret-required": "秘密が必芁です。", + "device-type": "デバむスタむプ", + "device-type-required": "デバむスタむプが必芁です。", + "select-device-type": "デバむスタむプを遞択", + "enter-device-type": "デバむスタむプを入力", + "any-device": "すべおのデバむス", + "no-device-types-matching": "'{{entitySubtype}}'発芋されたした。", + "device-type-list-empty": "遞択されたデバむスタむプはありたせん。", + "device-types": "デバむスの皮類", + "name": "名", + "name-required": "名前は必須です。", + "description": "説明", + "events": "むベント", + "details": "詳现", + "copyId": "デバむスIDをコピヌする", + "copyAccessToken": "コピヌアクセストヌクン", + "idCopiedMessage": "デバむスIDがクリップボヌドにコピヌされたした", + "accessTokenCopiedMessage": "デバむスアクセストヌクンがクリップボヌドにコピヌされたした", + "assignedToCustomer": "顧客に割り圓おられた", + "unable-delete-device-alias-title": "デバむス゚むリアスを削陀できたせん", + "unable-delete-device-alias-text": "'{{deviceAlias}}'{{widgetsList}}", + "is-gateway": "ゲヌトりェむです", + "public": "パブリック", + "device-public": "デバむスは公開されおいたす", + "select-device": "デバむスの遞択" + }, + "dialog": { + "close": "ダむアログを閉じる" + }, + "error": { + "unable-to-connect": "サヌバヌに接続できたせんむンタヌネット接続を確認しおください。", + "unhandled-error-code": "{{errorCode}}", + "unknown-error": "䞍明な゚ラヌ" + }, + "entity": { + "entity": "゚ンティティ", + "entities": "゚ンティティ", + "aliases": "゚ンティティ゚むリアス", + "entity-alias": "゚ンティティ゚むリアス", + "unable-delete-entity-alias-title": "゚ンティティ゚むリアスを削陀できたせん", + "unable-delete-entity-alias-text": "'{{entityAlias}}'{{widgetsList}}", + "duplicate-alias-error": "'{{alias}}'
゚ンティティの゚むリアスは、ダッシュボヌド内で䞀意である必芁がありたす。", + "missing-entity-filter-error": "'{{alias}}'.", + "configure-alias": "'{{alias}}'゚むリアス", + "alias": "゚むリアス", + "alias-required": "゚ンティティ゚むリアスが必芁です。", + "remove-alias": "゚ンティティ゚むリアスを削陀する", + "add-alias": "゚ンティティ゚むリアスを远加する", + "entity-list": "゚ンティティリスト", + "entity-type": "゚ンティティタむプ", + "entity-types": "゚ンティティタむプ", + "entity-type-list": "゚ンティティタむプリスト", + "any-entity": "任意の゚ンティティ", + "enter-entity-type": "゚ンティティタむプを入力", + "no-entities-matching": "'{{entity}}'発芋されたした。", + "no-entity-types-matching": "'{{entityType}}'発芋されたした。", + "name-starts-with": "名前はで始たる", + "use-entity-name-filter": "フィルタを䜿甚する", + "entity-list-empty": "遞択された゚ンティティはありたせん", + "entity-type-list-empty": "゚ンティティタむプは遞択されおいたせん。", + "entity-name-filter-required": "゚ンティティ名フィルタが必芁です。", + "entity-name-filter-no-entity-matched": "'{{entity}}'発芋されたした。", + "all-subtypes": "すべお", + "select-entities": "゚ンティティの遞択", + "no-aliases-found": "別名は芋぀かりたせんでした。", + "no-alias-matching": "'{{alias}}'芋぀かりたせん。", + "create-new-alias": "新しいものを䜜成しおください", + "key": "キヌ", + "key-name": "キヌ名", + "no-keys-found": "キヌが芋぀かりたせん。", + "no-key-matching": "'{{key}}'芋぀かりたせん。", + "create-new-key": "新しいものを䜜成しおください", + "type": "タむプ", + "type-required": "゚ンティティタむプが必芁です。", + "type-device": "デバむス", + "type-devices": "デバむス", + "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", + "device-name-starts-with": "'{{prefix}}'", + "type-asset": "資産", + "type-assets": "資産", + "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", + "asset-name-starts-with": "'{{prefix}}'", + "type-rule": "ルヌル", + "type-rules": "ルヌル", + "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }", + "rule-name-starts-with": "'{{prefix}}'", + "type-plugin": "プラグむン", + "type-plugins": "プラグむン", + "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }", + "plugin-name-starts-with": "'{{prefix}}'", + "type-tenant": "テナント", + "type-tenants": "テナント", + "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", + "tenant-name-starts-with": "'{{prefix}}'", + "type-customer": "顧客", + "type-customers": "顧客", + "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", + "customer-name-starts-with": "'{{prefix}}'", + "type-user": "ナヌザヌ", + "type-users": "ナヌザヌ", + "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }", + "user-name-starts-with": "'{{prefix}}'", + "type-dashboard": "ダッシュボヌド", + "type-dashboards": "ダッシュボヌド", + "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }", + "dashboard-name-starts-with": "'{{prefix}}'", + "type-alarm": "è­Šå ±", + "type-alarms": "アラヌム", + "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", + "alarm-name-starts-with": "'{{prefix}}'", + "type-rulechain": "ルヌルチェヌン", + "type-rulechains": "ルヌルチェヌン", + "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", + "rulechain-name-starts-with": "'{{prefix}}'", + "type-rulenode": "ルヌルノヌド", + "type-rulenodes": "ルヌルノヌド", + "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }", + "rulenode-name-starts-with": "'{{prefix}}'", + "type-current-customer": "珟圚の顧客", + "search": "怜玢゚ンティティ", + "selected-entities": "{ count, plural, 1 {1 entity} other {# entities} }遞択された", + "entity-name": "゚ンティティ名", + "details": "゚ンティティの詳现", + "no-entities-prompt": "゚ンティティが芋぀かりたせん", + "no-data": "衚瀺するデヌタがありたせん" + }, + "event": { + "event-type": "むベントタむプ", + "type-error": "゚ラヌ", + "type-lc-event": "ラむフサむクルむベント", + "type-stats": "統蚈", + "type-debug-rule-node": "デバッグ", + "type-debug-rule-chain": "デバッグ", + "no-events-prompt": "むベントは芋぀かりたせんでした", + "error": "゚ラヌ", + "alarm": "è­Šå ±", + "event-time": "むベント時間", + "server": "サヌバ", + "body": "䜓", + "method": "方法", + "type": "タむプ", + "entity": "゚ンティティ", + "message-id": "メッセヌゞID", + "message-type": "メッセヌゞタむプ", + "data-type": "デヌタ・タむプ", + "relation-type": "関係タむプ", + "metadata": "メタデヌタ", + "data": "デヌタ", + "event": "むベント", + "status": "状態", + "success": "成功", + "failed": "倱敗", + "messages-processed": "凊理されたメッセヌゞ", + "errors-occurred": "゚ラヌが発生したした" + }, + "extension": { + "extensions": "拡匵機胜", + "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} }遞択された", + "type": "タむプ", + "key": "キヌ", + "value": "倀", + "id": "むド", + "extension-id": "内線番号", + "extension-type": "拡匵タむプ", + "transformer-json": "JSON *", + "unique-id-required": "珟圚の拡匵IDは既に存圚したす。", + "delete": "拡匵子を削陀", + "add": "内線番号を远加", + "edit": "拡匵機胜を線集する", + "delete-extension-title": "'{{extensionId}}'?", + "delete-extension-text": "確認埌、拡匵子ず関連するすべおのデヌタが回埩䞍胜になるこずに泚意しおください。", + "delete-extensions-title": "{ count, plural, 1 {1 extension} other {# extensions} }?", + "delete-extensions-text": "泚意しおください。確認埌、遞択したすべおの内線番号が削陀されたす。", + "converters": "コンバヌタヌ", + "converter-id": "コンバヌタヌID", + "configuration": "構成", + "converter-configurations": "コンバヌタ構成", + "token": "セキュリティトヌクン", + "add-converter": "コンバヌタを远加する", + "add-config": "コンバヌタ蚭定を远加する", + "device-name-expression": "デバむス名匏", + "device-type-expression": "デバむスタむプの匏", + "custom": "カスタム", + "to-double": "ダブル", + "transformer": "トランス", + "json-required": "トランスフォヌマヌjsonが必芁です。", + "json-parse": "倉圧噚jsonを解析できたせん。", + "attributes": "属性", + "add-attribute": "属性を远加する", + "add-map": "マッピング芁玠を远加する", + "timeseries": "タむムズ", + "add-timeseries": "時系列を远加する", + "field-required": "フィヌルドは必須項目です", + "brokers": "ブロヌカヌ", + "add-broker": "ブロヌカヌを远加", + "host": "ホスト", + "port": "ポヌト", + "port-range": "ポヌトは1〜65535の範囲内にある必芁がありたす。", + "ssl": "SSL", + "credentials": "資栌情報", + "username": "ナヌザヌ名", + "password": "パスワヌド", + "retry-interval": "ミリ秒単䜍の再詊行間隔", + "anonymous": "匿名", + "basic": "ベヌシック", + "pem": "PEM", + "ca-cert": "CA蚌明曞ファむル*", + "private-key": "秘密鍵ファむル*", + "cert": "蚌明曞ファむル*", + "no-file": "ファむルが遞択されおいたせん。", + "drop-file": "ファむルをドロップするか、クリックしおアップロヌドするファむルを遞択したす。", + "mapping": "マッピング", + "topic-filter": "トピックフィルタ", + "converter-type": "コンバヌタタむプ", + "converter-json": "Json", + "json-name-expression": "デバむス名json匏", + "topic-name-expression": "デバむス名トピック衚珟", + "json-type-expression": "デバむスタむプjson匏", + "topic-type-expression": "デバむスタむプトピック衚珟", + "attribute-key-expression": "属性キヌ匏", + "attr-json-key-expression": "属性キヌjson匏", + "attr-topic-key-expression": "属性キヌトピック匏", + "request-id-expression": "芁求ID匏", + "request-id-json-expression": "リク゚ストID json匏", + "request-id-topic-expression": "リク゚ストIDトピック衚珟", + "response-topic-expression": "応答トピック衚珟", + "value-expression": "倀匏", + "topic": "トピック", + "timeout": "タむムアりトミリ秒", + "converter-json-required": "コンバヌタjsonが必芁です。", + "converter-json-parse": "コンバヌタjsonを解析できたせん。", + "filter-expression": "フィルタ匏", + "connect-requests": "接続芁求", + "add-connect-request": "接続芁求を远加", + "disconnect-requests": "切断芁求", + "add-disconnect-request": "切断リク゚ストを远加する", + "attribute-requests": "属性芁求", + "add-attribute-request": "属性芁求を远加する", + "attribute-updates": "属性の曎新", + "add-attribute-update": "属性の曎新を远加する", + "server-side-rpc": "サヌバヌ偎RPC", + "add-server-side-rpc-request": "サヌバヌ偎RPC芁求を远加する", + "device-name-filter": "デバむス名フィルタ", + "attribute-filter": "属性フィルタ", + "method-filter": "方法フィルタヌ", + "request-topic-expression": "トピック衚珟を芁求する", + "response-timeout": "応答タむムアりトミリ秒", + "topic-expression": "トピック衚珟", + "client-scope": "クラむアントスコヌプ", + "add-device": "デバむスを远加", + "opc-server": "サヌバヌ", + "opc-add-server": "サヌバヌを远加", + "opc-add-server-prompt": "サヌバヌを远加しおください", + "opc-application-name": "アプリケヌション名", + "opc-application-uri": "アプリケヌションURI", + "opc-scan-period-in-seconds": "スキャン時間秒", + "opc-security": "セキュリティ", + "opc-identity": "身元", + "opc-keystore": "キヌストア", + "opc-type": "タむプ", + "opc-keystore-type": "タむプ", + "opc-keystore-location": "ロケヌション*", + "opc-keystore-password": "パスワヌド", + "opc-keystore-alias": "゚むリアス", + "opc-keystore-key-password": "キヌのパスワヌド", + "opc-device-node-pattern": "デバむスノヌドパタヌン", + "opc-device-name-pattern": "デバむス名パタヌン", + "modbus-server": "サヌバヌ/スレヌブ", + "modbus-add-server": "サヌバヌ/スレヌブを远加する", + "modbus-add-server-prompt": "サヌバヌ/スレヌブを远加しおください", + "modbus-transport": "茞送", + "modbus-port-name": "シリアルポヌト名", + "modbus-encoding": "゚ンコヌディング", + "modbus-parity": "パリティ", + "modbus-baudrate": "ボヌレヌト", + "modbus-databits": "デヌタビット", + "modbus-stopbits": "ストップビット", + "modbus-databits-range": "デヌタビットは7〜8の範囲内にある必芁がありたす。", + "modbus-stopbits-range": "ストップビットは1〜2の範囲内でなければなりたせん。", + "modbus-unit-id": "ナニットID", + "modbus-unit-id-range": "ナニットIDは1〜247の範囲で指定しおください。", + "modbus-device-name": "装眮名", + "modbus-poll-period": "投祚期間ミリ秒", + "modbus-attributes-poll-period": "属性のポヌリング期間ミリ秒", + "modbus-timeseries-poll-period": "時系列ポヌリング期間ミリ秒", + "modbus-poll-period-range": "投祚期間は正の倀でなければなりたせん。", + "modbus-tag": "タグ", + "modbus-function": "関数", + "modbus-register-address": "登録アドレス", + "modbus-register-address-range": "レゞスタのアドレスは0〜65535の範囲内である必芁がありたす。", + "modbus-register-bit-index": "ビットむンデックス", + "modbus-register-bit-index-range": "ビットむンデックスは0〜15の範囲内である必芁がありたす。", + "modbus-register-count": "レゞスタ数", + "modbus-register-count-range": "レゞスタ数は正の倀でなければなりたせん。", + "modbus-byte-order": "バむト順", + "sync": { + "status": "状態", + "sync": "同期", + "not-sync": "同期しない", + "last-sync-time": "前回の同期時間", + "not-available": "利甚䞍可" + }, + "export-extensions-configuration": "゚クステンション蚭定の゚クスポヌト", + "import-extensions-configuration": "゚クステンション蚭定のむンポヌト", + "import-extensions": "拡匵機胜のむンポヌト", + "import-extension": "むンポヌト拡匵", + "export-extension": "茞出延長", + "file": "拡匵機胜ファむル", + "invalid-file-error": "無効な拡匵ファむル" + }, + "fullscreen": { + "expand": "フルスクリヌンに拡倧", + "exit": "党画面衚瀺を終了", + "toggle": "フルスクリヌンモヌドを切り替える", + "fullscreen": "党画面衚瀺" + }, + "function": { + "function": "関数" + }, + "grid": { + "delete-item-title": "このアむテムを削陀しおもよろしいですか", + "delete-item-text": "泚意しおください。確認埌、この項目ず関連するすべおのデヌタは回埩䞍胜になりたす。", + "delete-items-title": "{ count, plural, 1 {1 item} other {# items} }?", + "delete-items-action-title": "{ count, plural, 1 {1 item} other {# items} }", + "delete-items-text": "泚意しおください。確認埌、遞択したすべおのアむテムが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "add-item-text": "新しいアむテムを远加", + "no-items-text": "項目は芋぀かりたせんでした", + "item-details": "商品詳现", + "delete-item": "アむテムを削陀", + "delete-items": "アむテムを削陀する", + "scroll-to-top": "トップにスクロヌルしたす" + }, + "help": { + "goto-help-page": "ヘルプペヌゞに行く" + }, + "home": { + "home": "ホヌム", + "profile": "プロフィヌル", + "logout": "ログアりト", + "menu": "メニュヌ", + "avatar": "アバタヌ", + "open-user-menu": "ナヌザヌメニュヌを開く" + }, + "import": { + "no-file": "ファむルが遞択されおいたせん", + "drop-file": "JSONファむルをドロップするか、アップロヌドするファむルをクリックしお遞択したす。" + }, + "item": { + "selected": "遞択された" + }, + "js-func": { + "no-return-error": "関数は倀を返す必芁がありたす", + "return-type-mismatch": "'{{type}}'タむプ", + "tidy": "きちんずした" + }, + "key-val": { + "key": "キヌ", + "value": "倀", + "remove-entry": "゚ントリを削陀", + "add-entry": "゚ントリを远加", + "no-data": "゚ントリなし" + }, + "layout": { + "layout": "レむアりト", + "manage": "レむアりトの管理", + "settings": "レむアりト蚭定", + "color": "色", + "main": "メむン", + "right": "右", + "select": "タヌゲットレむアりトを遞択" + }, + "legend": { + "position": "䌝説の䜍眮", + "show-max": "最倧倀を衚瀺", + "show-min": "最小倀を衚瀺する", + "show-avg": "平均倀を衚瀺", + "show-total": "合蚈倀を衚瀺", + "settings": "凡䟋の蚭定", + "min": "分", + "max": "最倧", + "avg": "平均", + "total": "合蚈" + }, + "login": { + "login": "ログむン", + "request-password-reset": "リク゚ストパスワヌドのリセット", + "reset-password": "パスワヌドを再蚭定する", + "create-password": "パスワヌドの䜜成", + "passwords-mismatch-error": "入力されたパスワヌドは同じでなければなりたせん", + "password-again": "パスワヌドをもう䞀床", + "sign-in": "サむンむンしおください", + "username": "ナヌザヌ名電子メヌル", + "remember-me": "私を芚えおたすか", + "forgot-password": "パスワヌドをお忘れですか", + "password-reset": "パスワヌドのリセット", + "new-password": "新しいパスワヌド", + "new-password-again": "新しいパスワヌドを再入力", + "password-link-sent-message": "パスワヌドリセットリンクが正垞に送信されたした", + "email": "Eメヌル" + }, + "position": { + "top": "侊", + "bottom": "ボトム", + "left": "å·Š", + "right": "右" + }, + "profile": { + "profile": "プロフィヌル", + "change-password": "パスワヌドを倉曎する", + "current-password": "珟圚のパスワヌド" + }, + "relation": { + "relations": "関係", + "direction": "方向", + "search-direction": { + "FROM": "から", + "TO": "に" + }, + "direction-type": { + "FROM": "から", + "TO": "に" + }, + "from-relations": "アりトバりンド関係", + "to-relations": "むンバりンド関係", + "selected-relations": "{ count, plural, 1 {1 relation} other {# relations} }遞択された", + "type": "タむプ", + "to-entity-type": "゚ンティティタむプぞ", + "to-entity-name": "゚ンティティ名に", + "from-entity-type": "゚ンティティタむプから", + "from-entity-name": "゚ンティティ名から", + "to-entity": "実䜓ぞ", + "from-entity": "゚ンティティから", + "delete": "関係を削陀する", + "relation-type": "関係タむプ", + "relation-type-required": "関係タむプが必芁です。", + "any-relation-type": "いかなるタむプ", + "add": "関係を远加する", + "edit": "関係を線集する", + "delete-to-relation-title": "'{{entityName}}'?", + "delete-to-relation-text": "'{{entityName}}'珟圚の゚ンティティずは無関係です。", + "delete-to-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?", + "delete-to-relations-text": "泚意しおください。確認埌、遞択されたリレヌションはすべお削陀され、察応する゚ンティティは珟圚の゚ンティティずは無関係になりたす。", + "delete-from-relation-title": "'{{entityName}}'?", + "delete-from-relation-text": "'{{entityName}}'.", + "delete-from-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?", + "delete-from-relations-text": "泚意しおください。確認埌、遞択されたリレヌションはすべお削陀され、珟圚の゚ンティティは察応する゚ンティティずは無関係になりたす。", + "remove-relation-filter": "関係フィルタを削陀する", + "add-relation-filter": "関係フィルタを远加する", + "any-relation": "関係", + "relation-filters": "関係フィルタ", + "additional-info": "远加情報JSON", + "invalid-additional-info": "远加情報jsonを解析できたせん。" + }, + "rulechain": { + "rulechain": "ルヌルチェヌン", + "rulechains": "ルヌルチェヌン", + "root": "ルヌト", + "delete": "ルヌルチェヌンの削陀", + "name": "名", + "name-required": "名前は必須です。", + "description": "説明", + "add": "ルヌルチェヌンを远加する", + "set-root": "ルヌルチェヌンのルヌトを䜜る", + "set-root-rulechain-title": "'{{ruleChainName}}'ルヌト", + "set-root-rulechain-text": "確認埌、ルヌルチェヌンはルヌトになり、すべおの受信トランスポヌトメッセヌゞを凊理したす。", + "delete-rulechain-title": "'{{ruleChainName}}'?", + "delete-rulechain-text": "確認埌、ルヌルチェヌンず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "delete-rulechains-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }?", + "delete-rulechains-action-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }", + "delete-rulechains-text": "確認埌、遞択したすべおのルヌルチェヌンが削陀され、関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "add-rulechain-text": "新しいルヌルチェヌンを远加する", + "no-rulechains-text": "ルヌルチェヌンが芋぀かりたせん", + "rulechain-details": "ルヌルチェヌンの詳现", + "details": "詳现", + "events": "むベント", + "system": "システム", + "import": "ルヌルチェヌンのむンポヌト", + "export": "ルヌルチェヌンの゚クスポヌト", + "export-failed-error": "{{error}}", + "create-new-rulechain": "新しいルヌルチェヌンを䜜成する", + "rulechain-file": "ルヌルチェヌンファむル", + "invalid-rulechain-file-error": "ルヌルチェヌンをむンポヌトできたせんルヌルチェヌンのデヌタ構造が無効です。", + "copyId": "ルヌルチェヌンIDのコピヌ", + "idCopiedMessage": "ルヌルチェヌンIDがクリップボヌドにコピヌされたした", + "select-rulechain": "ルヌルチェヌンの遞択", + "no-rulechains-matching": "'{{entity}}'発芋されたした。", + "rulechain-required": "ルヌルチェヌンが必芁です", + "management": "ルヌル管理", + "debug-mode": "デバッグモヌド" + }, + "rulenode": { + "details": "詳现", + "events": "むベント", + "search": "怜玢ノヌド", + "open-node-library": "オヌプンノヌドラむブラリ", + "add": "ルヌルノヌドを远加する", + "name": "名", + "name-required": "名前は必須です。", + "type": "タむプ", + "description": "説明", + "delete": "ルヌルノヌドを削陀", + "select-all-objects": "すべおのノヌドず接続を遞択する", + "deselect-all-objects": "すべおのノヌドず接続の遞択を解陀する", + "delete-selected-objects": "遞択したノヌドず接続を削陀する", + "delete-selected": "遞択を削陀したす", + "select-all": "すべお遞択", + "copy-selected": "遞択したコピヌ", + "deselect-all": "すべおの遞択を解陀", + "rulenode-details": "ルヌルノヌドの詳现", + "debug-mode": "デバッグモヌド", + "configuration": "構成", + "link": "リンク", + "link-details": "ルヌルノヌドのリンクの詳现", + "add-link": "リンクを远加", + "link-label": "リンクラベル", + "link-label-required": "リンクラベルが必芁です。", + "custom-link-label": "カスタムリンクラベル", + "custom-link-label-required": "カスタムリンクラベルが必芁です。", + "link-labels": "リンクラベル", + "link-labels-required": "リンクラベルが必芁です。", + "no-link-labels-found": "リンクラベルが芋぀かりたせん", + "no-link-label-matching": "'{{label}}'芋぀かりたせん。", + "create-new-link-label": "新しいものを䜜成しおください", + "type-filter": "フィルタ", + "type-filter-details": "蚭定された条件で着信メッセヌゞをフィルタリングする", + "type-enrichment": "豊かな", + "type-enrichment-details": "メッセヌゞメタデヌタに远加情報を远加する", + "type-transformation": "倉換", + "type-transformation-details": "メッセヌゞペむロヌドずメタデヌタの倉曎", + "type-action": "アクション", + "type-action-details": "特別なアクションを実行する", + "type-external": "倖郚", + "type-external-details": "倖郚システムずの盞互䜜甚", + "type-rule-chain": "ルヌルチェヌン", + "type-rule-chain-details": "受信したメッセヌゞを指定したルヌルチェヌンに転送する", + "type-input": "入力", + "type-input-details": "ルヌルチェヌンの論理入力、次の関連ルヌルノヌドぞの着信メッセヌゞの転送", + "type-unknown": "未知の", + "type-unknown-details": "未解決のルヌルノヌド", + "directive-is-not-loaded": "'{{directiveName}}'利甚できたせん。", + "ui-resources-load-error": "構成UIリ゜ヌスをロヌドできたせんでした。", + "invalid-target-rulechain": "タヌゲットルヌルチェヌンを解決できたせん", + "test-script-function": "テストスクリプト機胜", + "message": "メッセヌゞ", + "message-type": "メッセヌゞタむプ", + "select-message-type": "メッセヌゞタむプを遞択", + "message-type-required": "メッセヌゞタむプは必須です", + "metadata": "メタデヌタ", + "metadata-required": "メタデヌタの゚ントリを空にするこずはできたせん。", + "output": "出力", + "test": "テスト", + "help": "助けお" + }, + "tenant": { + "tenant": "テナント", + "tenants": "テナント", + "management": "テナント管理", + "add": "テナントを远加", + "admins": "管理者", + "manage-tenant-admins": "テナント管理者の管理", + "delete": "テナントの削陀", + "add-tenant-text": "新しいテナントを远加する", + "no-tenants-text": "テナントは芋぀かりたせんでした", + "tenant-details": "テナントの詳现", + "delete-tenant-title": "'{{tenantTitle}}'?", + "delete-tenant-text": "確認埌、テナントず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "delete-tenants-title": "{ count, plural, 1 {1 tenant} other {# tenants} }?", + "delete-tenants-action-title": "{ count, plural, 1 {1 tenant} other {# tenants} }", + "delete-tenants-text": "泚意しおください。確認埌、遞択されたすべおのテナントが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "title": "タむトル", + "title-required": "タむトルは必須です。", + "description": "説明", + "details": "詳现", + "events": "むベント", + "copyId": "テナントIDをコピヌする", + "idCopiedMessage": "テナントIDがクリップボヌドにコピヌされたした", + "select-tenant": "テナントを遞択", + "no-tenants-matching": "'{{entity}}'発芋されたした。", + "tenant-required": "テナントが必芁です" + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, 1 {1 second} other {# seconds} }", + "minutes-interval": "{ minutes, plural, 1 {1 minute} other {# minutes} }", + "hours-interval": "{ hours, plural, 1 {1 hour} other {# hours} }", + "days-interval": "{ days, plural, 1 {1 day} other {# days} }", + "days": "日々", + "hours": "時間", + "minutes": "分", + "seconds": "秒", + "advanced": "侊箚" + }, + "timewindow": { + "days": "{ days, plural, 1 { day } other {# days } }", + "hours": "{ hours, plural, 0 { hour } 1 {1 hour } other {# hours } }", + "minutes": "{ minutes, plural, 0 { minute } 1 {1 minute } other {# minutes } }", + "seconds": "{ seconds, plural, 0 { second } 1 {1 second } other {# seconds } }", + "realtime": "リアルタむム", + "history": "歎史", + "last-prefix": "最終", + "period": "{{ startTime }}{{ endTime }}", + "edit": "タむムりィンドりを線集", + "date-range": "期間", + "last": "最終", + "time-period": "期間" + }, + "user": { + "user": "ナヌザヌ", + "users": "ナヌザヌ", + "customer-users": "顧客ナヌザヌ", + "tenant-admins": "テナント管理者", + "sys-admin": "システム管理者", + "tenant-admin": "テナント管理者", + "customer": "顧客", + "anonymous": "匿名", + "add": "ナヌザヌを远加する", + "delete": "ナヌザヌを削陀", + "add-user-text": "新しいナヌザヌを远加", + "no-users-text": "ナヌザが芋぀かりたせんでした", + "user-details": "ナヌザヌの詳现", + "delete-user-title": "'{{userEmail}}'?", + "delete-user-text": "確認埌、ナヌザヌず関連するすべおのデヌタが回埩䞍胜になるので泚意しおください。", + "delete-users-title": "{ count, plural, 1 {1 user} other {# users} }?", + "delete-users-action-title": "{ count, plural, 1 {1 user} other {# users} }", + "delete-users-text": "泚意しおください。確認埌、遞択したすべおのナヌザヌが削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "activation-email-sent-message": "アクティベヌション電子メヌルが正垞に送信されたした", + "resend-activation": "アクティブ化を再送", + "email": "Eメヌル", + "email-required": "電子メヌルが必芁です。", + "invalid-email-format": "メヌルフォヌマットが無効です。", + "first-name": "ファヌストネヌム", + "last-name": "苗字", + "description": "説明", + "default-dashboard": "デフォルトのダッシュボヌド", + "always-fullscreen": "垞に党画面衚瀺", + "select-user": "ナヌザヌを遞択", + "no-users-matching": "'{{entity}}'発芋されたした。", + "user-required": "ナヌザヌは必須です", + "activation-method": "起動方法", + "display-activation-link": "アクティブ化リンクを衚瀺する", + "send-activation-mail": "アクティベヌションメヌルを送信する", + "activation-link": "ナヌザヌアクティベヌションリンク", + "activation-link-text": "activation link :", + "copy-activation-link": "アクティブ化リンクをコピヌする", + "activation-link-copied-message": "ナヌザヌのアクティベヌションリンクがクリップボヌドにコピヌされたした", + "details": "詳现" + }, + "value": { + "type": "倀のタむプ", + "string": "文字列", + "string-value": "文字列倀", + "integer": "敎数", + "integer-value": "敎数倀", + "invalid-integer-value": "敎数倀が無効です", + "double": "ダブル", + "double-value": "二重䟡倀", + "boolean": "ブヌル", + "boolean-value": "ブヌル倀", + "false": "停", + "true": "真", + "long": "長いです" + }, + "widget": { + "widget-library": "りィゞェットラむブラリ", + "widget-bundle": "りィゞェットバンドル", + "select-widgets-bundle": "りィゞェットのバンドルを遞択", + "management": "りィゞェット管理", + "editor": "りィゞェット゚ディタ", + "widget-type-not-found": "りィゞェットの蚭定を読み蟌む際に問題が発生したした。
おそらく関連付けられおいるりィゞェットのタむプが削陀されおいたす。", + "widget-type-load-error": "次の゚ラヌのためにりィゞェットが読み蟌たれたせんでした", + "remove": "りィゞェットを削陀", + "edit": "りィゞェットの線集", + "remove-widget-title": "'{{widgetTitle}}'?", + "remove-widget-text": "確認埌、りィゞェットず関連するすべおのデヌタは回埩䞍胜になりたす。", + "timeseries": "時系列", + "search-data": "怜玢デヌタ", + "no-data-found": "䜕もデヌタが芋぀かりたせんでした", + "latest-values": "最新の倀", + "rpc": "コントロヌルりィゞェット", + "alarm": "アラヌムりィゞェット", + "static": "静的りィゞェット", + "select-widget-type": "りィゞェットタむプを遞択", + "missing-widget-title-error": "りィゞェットのタむトルを指定する必芁がありたす", + "widget-saved": "りィゞェットが保存されたした", + "unable-to-save-widget-error": "りィゞェットを保存できたせんりィゞェットに゚ラヌがありたす", + "save": "りィゞェットを保存", + "saveAs": "りィゞェットを次のように保存する", + "save-widget-type-as": "りィゞェットタむプを次のように保存したす", + "save-widget-type-as-text": "新しいりィゞェットのタむトルを入力したり、タヌゲットりィゞェットのバンドルを遞択しおください", + "toggle-fullscreen": "フルスクリヌン切り替え", + "run": "りィゞェットを実行する", + "title": "りィゞェットのタむトル", + "title-required": "りィゞェットのタむトルが必芁です。", + "type": "りィゞェットタむプ", + "resources": "リ゜ヌス", + "resource-url": "JavaScript / CSS URL", + "remove-resource": "リ゜ヌスを削陀する", + "add-resource": "リ゜ヌスを远加", + "html": "HTML", + "tidy": "きちんずした", + "css": "CSS", + "settings-schema": "蚭定スキヌマ", + "datakey-settings-schema": "デヌタキヌ蚭定のスキヌマ", + "javascript": "Javascript", + "remove-widget-type-title": "'{{widgetName}}'?", + "remove-widget-type-text": "確認埌、りィゞェットのタむプず関連するすべおのデヌタは回埩䞍胜になりたす。", + "remove-widget-type": "りィゞェットタむプを削陀", + "add-widget-type": "新しいりィゞェットタむプを远加する", + "widget-type-load-failed-error": "りィゞェットタむプの読み蟌みに倱敗したした", + "widget-template-load-failed-error": "りィゞェットテンプレヌトを読み蟌めたせんでした", + "add": "りィゞェットを远加", + "undo": "りィゞェットの倉曎を元に戻す", + "export": "りィゞェットの曞き出し" + }, + "widget-action": { + "header-button": "りィゞェットのヘッダヌボタン", + "open-dashboard-state": "新しいダッシュボヌドの状態に移動する", + "update-dashboard-state": "珟圚のダッシュボヌドの状態を曎新する", + "open-dashboard": "他のダッシュボヌドに移動する", + "custom": "カスタムアクション", + "target-dashboard-state": "タヌゲットダッシュボヌドの状態", + "target-dashboard-state-required": "タヌゲットダッシュボヌドの状態が必芁です", + "set-entity-from-widget": "゚ンティティをりィゞェットから蚭定する", + "target-dashboard": "タヌゲットダッシュボヌド", + "open-right-layout": "右ダッシュボヌドレむアりトを開くモバむルビュヌ" + }, + "widgets-bundle": { + "current": "珟圚のバンドル", + "widgets-bundles": "りィゞェットバンドル", + "add": "りィゞェットのバンドルを远加", + "delete": "りィゞェットのバンドルを削陀する", + "title": "タむトル", + "title-required": "タむトルは必須です。", + "add-widgets-bundle-text": "新しいりィゞェットのバンドルを远加する", + "no-widgets-bundles-text": "りィゞェットバンドルが芋぀かりたせん", + "empty": "りィゞェットのバンドルが空です", + "details": "詳现", + "widgets-bundle-details": "りィゞェットのバンドルの詳现", + "delete-widgets-bundle-title": "'{{widgetsBundleTitle}}'?", + "delete-widgets-bundle-text": "確認埌、りィゞェットはバンドルされ、関連するすべおのデヌタは回埩䞍胜になりたす。", + "delete-widgets-bundles-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }?", + "delete-widgets-bundles-action-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }", + "delete-widgets-bundles-text": "確認埌、遞択したすべおのりィゞェットバンドルは削陀され、関連するすべおのデヌタは回埩䞍胜になりたす。", + "no-widgets-bundles-matching": "'{{widgetsBundle}}'発芋されたした。", + "widgets-bundle-required": "りィゞェットバンドルが必芁です。", + "system": "システム", + "import": "むンポヌトりィゞェットバンドル", + "export": "りィゞェットの゚クスポヌトバンドル", + "export-failed-error": "{{error}}", + "create-new-widgets-bundle": "新しいりィゞェットバンドルを䜜成する", + "widgets-bundle-file": "りィゞェットのバンドルファむル", + "invalid-widgets-bundle-file-error": "りィゞェットをむンポヌトできたせん。bundleデヌタ構造が無効です。" + }, + "widget-config": { + "data": "デヌタ", + "settings": "蚭定", + "advanced": "侊箚", + "title": "タむトル", + "general-settings": "䞀般蚭定", + "display-title": "タむトルを衚瀺", + "drop-shadow": "圱を萜ずす", + "enable-fullscreen": "フルスクリヌンを有効にする", + "background-color": "背景色", + "text-color": "テキストの色", + "padding": "パディング", + "margin": "マヌゞン", + "widget-style": "りィゞェットスタむル", + "title-style": "タむトルスタむル", + "mobile-mode-settings": "モバむルモヌドの蚭定", + "order": "泚文", + "height": "高さ", + "units": "倀の隣に衚瀺する特別なシンボル", + "decimals": "浮動小数点の埌の桁数", + "timewindow": "タむムりィンドり", + "use-dashboard-timewindow": "ダッシュボヌドのタむムりィンドりを䜿甚する", + "display-legend": "䌝説を衚瀺", + "datasources": "デヌタ゜ヌス", + "maximum-datasources": "{ count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }", + "datasource-type": "タむプ", + "datasource-parameters": "パラメヌタヌ", + "remove-datasource": "デヌタ゜ヌスを削陀", + "add-datasource": "デヌタ゜ヌスを远加", + "target-device": "タヌゲットデバむス", + "alarm-source": "アラヌム゜ヌス", + "actions": "行動", + "action": "アクション", + "add-action": "アクションを远加", + "search-actions": "怜玢アクション", + "action-source": "アクション゜ヌス", + "action-source-required": "アクション゜ヌスが必芁です。", + "action-name": "名", + "action-name-required": "アクション名は必須です。", + "action-name-not-unique": "同じ名前の別のアクションがすでに存圚したす。
アクション名は、同じアクション゜ヌス内で䞀意である必芁がありたす。", + "action-icon": "アむコン", + "action-type": "タむプ", + "action-type-required": "アクションタむプが必芁です。", + "edit-action": "アクションの線集", + "delete-action": "アクションの削陀", + "delete-action-title": "りィゞェットアクションを削陀する", + "delete-action-text": "'{{actionName}}'?" + }, + "widget-type": { + "import": "むンポヌトりィゞェットタむプ", + "export": "りィゞェットのタむプを゚クスポヌトする", + "export-failed-error": "{{error}}", + "create-new-widget-type": "新しいりィゞェットタむプを䜜成する", + "widget-type-file": "りィゞェットタむプファむル", + "invalid-widget-type-file-error": "りィゞェットタむプをむンポヌトできたせんりィゞェットタむプのデヌタ構造が無効です。" + }, + "widgets": { + "date-range-navigator": { + "localizationMap": { + "Sun": "日", + "Mon": "月", + "Tue": "火", + "Wed": "æ°Ž", + "Thu": "朚", + "Fri": "金", + "Sat": "土", + "Jan": "1月", + "Feb": "2月", + "Mar": "3月", + "Apr": "4月", + "May": "5月", + "Jun": "6月", + "Jul": "7月", + "Aug": "8月", + "Sep": "9月", + "Oct": "10月", + "Nov": "11月", + "Dec": "12月", + "January": "1月", + "February": "2月", + "March": "行進", + "April": "4月", + "June": "六月", + "July": "7月", + "August": "8月", + "September": "9月", + "October": "10月", + "November": "11月", + "December": "12月", + "Custom Date Range": "カスタム期間", + "Date Range Template": "日付範囲テンプレヌト", + "Today": "今日", + "Yesterday": "昚日", + "This Week": "今週", + "Last Week": "先週", + "This Month": "今月", + "Last Month": "先月", + "Year": "幎", + "This Year": "今幎", + "Last Year": "昚幎", + "Date picker": "日付ピッカヌ", + "Hour": "時", + "Day": "日", + "Week": "週間", + "2 weeks": "2週間", + "Month": "月", + "3 months": "3ヶ月", + "6 months": "6ヵ月", + "Custom interval": "カスタム間隔", + "Interval": "間隔", + "Step size": "刻み幅", + "Ok": "Ok" + } + } + }, + "icon": { + "icon": "アむコン", + "select-icon": "遞択アむコン", + "material-icons": "マテリアルアむコン", + "show-all": "すべおのアむコンを衚瀺する" + }, + "custom": { + "widget-action": { + "action-cell-button": "アクションセルボタン", + "row-click": "行のクリック", + "polygon-click": "ポリゎンクリック", + "marker-click": "マヌカヌクリック", + "tooltip-tag-action": "ツヌルチップのタグアクション" + } + }, + "language": { + "language": "蚀語", + "locales": { + "de_DE": "ドむツ語", + "fr_FR": "フランス語", + "en_US": "英語", + "ko_KR": "韓囜語", + "it_IT": "むタリアの", + "zh_CN": "䞭囜語", + "ru_RU": "ロシア", + "es_ES": "スペむン語", + "ja_JA": "日本語", + "tr_TR": "トルコ語", + "fa_IR": "ペルシャ語", + "uk_UA": "りクラむナ語", + "cs_CZ": "チェコ語で" + } + } } \ No newline at end of file diff --git a/ui/src/app/locale/locale.constant-ko_KR.json b/ui/src/app/locale/locale.constant-ko_KR.json index fde60c77bb..f9395b1dd6 100644 --- a/ui/src/app/locale/locale.constant-ko_KR.json +++ b/ui/src/app/locale/locale.constant-ko_KR.json @@ -83,6 +83,7 @@ "timeout-required": "제한시간을 입력핎알 합니닀.", "timeout-invalid": "올바륞 제한시간읎 아닙니닀.", "enable-tls": "TLS 사용", + "tls-version" : "TLS 버전", "send-test-mail": "테슀튞 메음 볎낎Ʞ" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-lv_LV.json b/ui/src/app/locale/locale.constant-lv_LV.json index 4ddbb1856f..08e7d34b7f 100644 --- a/ui/src/app/locale/locale.constant-lv_LV.json +++ b/ui/src/app/locale/locale.constant-lv_LV.json @@ -84,6 +84,7 @@ "timeout-required": "Timeout is required.", "timeout-invalid": "That doesn't look like a valid timeout.", "enable-tls": "Enable TLS", + "tls-version": "TLS version", "send-test-mail": "Send test mail" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index 87075014ba..f4ed6d5c93 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -85,6 +85,7 @@ "timeout-required": "ТайЌаут ПбязателеМ.", "timeout-invalid": "НеЎействОтельМый тайЌаут.", "enable-tls": "ВключОть TLS", + "tls-version" : "ВерсОя TLS", "send-test-mail": "ОтправОть прПбМПе пОсьЌП", "security-settings": "НастрПйкО безПпасМПстО", "password-policy": "ППлОтОка парПлей", diff --git a/ui/src/app/locale/locale.constant-tr_TR.json b/ui/src/app/locale/locale.constant-tr_TR.json index c9c5964c52..a9dd8e7697 100644 --- a/ui/src/app/locale/locale.constant-tr_TR.json +++ b/ui/src/app/locale/locale.constant-tr_TR.json @@ -83,6 +83,7 @@ "timeout-required": "Zaman aşımı değeri gerekli.", "timeout-invalid": "Bu geçerli bir zaman aşımı gibi görÃŒnmÃŒyor.", "enable-tls": "TLS'i etkinleştir.", + "tls-version" : "TLS sÃŒrÃŒmÃŒ", "send-test-mail": "Test e-postası gönder" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-uk_UA.json b/ui/src/app/locale/locale.constant-uk_UA.json index 6aa1e06e89..53d16bea5e 100644 --- a/ui/src/app/locale/locale.constant-uk_UA.json +++ b/ui/src/app/locale/locale.constant-uk_UA.json @@ -87,6 +87,7 @@ "timeout-required": "НеПбхіЎМП заЎатО час ПчікуваММя.", "timeout-invalid": "Ње Ме схПже Ма правОльМОй час ПчікуваММя.", "enable-tls": "УвіЌкМутО TLS", + "tls-version" : "Версія TLS", "send-test-mail": "НаЎіслатО тестПве пПвіЎПЌлеММя", "use-system-mail-settings": "ВОкПрОстПвуватО параЌетрО сОстеЌМПгП пПштПвПгП сервера", "mail-templates": "КаблПМО електрПММПї пПштО", diff --git a/ui/src/app/locale/locale.constant-zh_CN.json b/ui/src/app/locale/locale.constant-zh_CN.json index 0c1f5f743b..634aae3f1f 100644 --- a/ui/src/app/locale/locale.constant-zh_CN.json +++ b/ui/src/app/locale/locale.constant-zh_CN.json @@ -83,6 +83,7 @@ "timeout-required": "超时必填。", "timeout-invalid": "这看起来䞍像有效的超时倌。", "enable-tls": "启甚TLS", + "tls-version" : "TLS版本", "send-test-mail": "发送测试邮件" }, "alarm": { diff --git a/ui/src/app/locale/locale.constant-zh_TW.json b/ui/src/app/locale/locale.constant-zh_TW.json index acaa9ac53c..52637b7c82 100644 --- a/ui/src/app/locale/locale.constant-zh_TW.json +++ b/ui/src/app/locale/locale.constant-zh_TW.json @@ -83,6 +83,7 @@         "timeout-required": "超時必填。",         "timeout-invalid": "這看起䟆䞍像有效的超時倌。",         "enable-tls": "啟甚TLS", + "tls-version": "TLS版本",         "send-test-mail": "癌送枬詊郵件"     },     "alarm": {