Commit 753ff4e31ae9378aae1f2819194fd9d9b12707d4

Authored by Dima Landiak
2 parents f94c61f2 291634c1

merged with master

Showing 39 changed files with 3499 additions and 216 deletions
... ... @@ -116,6 +116,7 @@ public class AppActor extends RuleChainManagerActor {
116 116 break;
117 117 case ACTOR_SYSTEM_TO_DEVICE_SESSION_ACTOR_MSG:
118 118 onToDeviceSessionMsg((BasicActorSystemToDeviceSessionActorMsg) msg);
  119 + break;
119 120 default:
120 121 return false;
121 122 }
... ...
... ... @@ -114,7 +114,7 @@ public class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcesso
114 114 private String deviceType;
115 115 private TbMsgMetaData defaultMetaData;
116 116
117   - public DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) {
  117 + DeviceActorMessageProcessor(ActorSystemContext systemContext, LoggingAdapter logger, TenantId tenantId, DeviceId deviceId) {
118 118 super(systemContext, logger);
119 119 this.tenantId = tenantId;
120 120 this.deviceId = deviceId;
... ...
... ... @@ -28,7 +28,7 @@ import java.io.Serializable;
28 28 * Created by ashvayka on 19.03.18.
29 29 */
30 30 @Data
31   -final class RemoteToRuleChainTellNextMsg extends RuleNodeToRuleChainTellNextMsg implements TenantAwareMsg, RuleChainAwareMsg, Serializable {
  31 +final class RemoteToRuleChainTellNextMsg extends RuleNodeToRuleChainTellNextMsg implements TenantAwareMsg, RuleChainAwareMsg {
32 32
33 33 private static final long serialVersionUID = 2459605482321657447L;
34 34 private final TenantId tenantId;
... ...
... ... @@ -21,14 +21,16 @@ import org.thingsboard.server.common.msg.MsgType;
21 21 import org.thingsboard.server.common.msg.TbActorMsg;
22 22 import org.thingsboard.server.common.msg.TbMsg;
23 23
  24 +import java.io.Serializable;
24 25 import java.util.Set;
25 26
26 27 /**
27 28 * Created by ashvayka on 19.03.18.
28 29 */
29 30 @Data
30   -class RuleNodeToRuleChainTellNextMsg implements TbActorMsg {
  31 +class RuleNodeToRuleChainTellNextMsg implements TbActorMsg, Serializable {
31 32
  33 + private static final long serialVersionUID = 4577026446412871820L;
32 34 private final RuleNodeId originator;
33 35 private final Set<String> relationTypes;
34 36 private final TbMsg msg;
... ...
... ... @@ -15,13 +15,17 @@
15 15 */
16 16 package org.thingsboard.server.actors.session;
17 17
  18 +import akka.actor.ActorInitializationException;
18 19 import akka.actor.ActorRef;
19 20 import akka.actor.InvalidActorNameException;
20 21 import akka.actor.LocalActorRef;
  22 +import akka.actor.OneForOneStrategy;
21 23 import akka.actor.Props;
  24 +import akka.actor.SupervisorStrategy;
22 25 import akka.actor.Terminated;
23 26 import akka.event.Logging;
24 27 import akka.event.LoggingAdapter;
  28 +import akka.japi.Function;
25 29 import org.thingsboard.server.actors.ActorSystemContext;
26 30 import org.thingsboard.server.actors.service.ContextAwareActor;
27 31 import org.thingsboard.server.actors.service.ContextBasedCreator;
... ... @@ -34,6 +38,7 @@ import org.thingsboard.server.common.msg.cluster.ClusterEventMsg;
34 38 import org.thingsboard.server.common.msg.core.ActorSystemToDeviceSessionActorMsg;
35 39 import org.thingsboard.server.common.msg.core.SessionCloseMsg;
36 40 import org.thingsboard.server.common.msg.session.SessionCtrlMsg;
  41 +import scala.concurrent.duration.Duration;
37 42
38 43 import java.util.HashMap;
39 44 import java.util.Map;
... ... @@ -46,12 +51,17 @@ public class SessionManagerActor extends ContextAwareActor {
46 51
47 52 private final Map<String, ActorRef> sessionActors;
48 53
49   - public SessionManagerActor(ActorSystemContext systemContext) {
  54 + SessionManagerActor(ActorSystemContext systemContext) {
50 55 super(systemContext);
51 56 this.sessionActors = new HashMap<>(INITIAL_SESSION_MAP_SIZE);
52 57 }
53 58
54 59 @Override
  60 + public SupervisorStrategy supervisorStrategy() {
  61 + return strategy;
  62 + }
  63 +
  64 + @Override
55 65 protected boolean process(TbActorMsg msg) {
56 66 //TODO Move everything here, to work with TbActorMsg
57 67 return false;
... ... @@ -160,4 +170,11 @@ public class SessionManagerActor extends ContextAwareActor {
160 170 }
161 171 }
162 172
  173 + private final SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.create("1 minute"), new Function<Throwable, SupervisorStrategy.Directive>() {
  174 + @Override
  175 + public SupervisorStrategy.Directive apply(Throwable t) {
  176 + logger.error(t, "Unknown failure");
  177 + return SupervisorStrategy.stop();
  178 + }
  179 + });
163 180 }
... ...
... ... @@ -15,6 +15,7 @@
15 15 */
16 16 package org.thingsboard.server.actors.tenant;
17 17
  18 +import akka.actor.ActorInitializationException;
18 19 import akka.actor.ActorRef;
19 20 import akka.actor.OneForOneStrategy;
20 21 import akka.actor.Props;
... ... @@ -170,7 +171,11 @@ public class TenantActor extends RuleChainManagerActor {
170 171 @Override
171 172 public SupervisorStrategy.Directive apply(Throwable t) {
172 173 logger.error(t, "Unknown failure");
173   - return SupervisorStrategy.resume();
  174 + if(t instanceof ActorInitializationException){
  175 + return SupervisorStrategy.stop();
  176 + } else {
  177 + return SupervisorStrategy.resume();
  178 + }
174 179 }
175 180 });
176 181
... ...
... ... @@ -86,7 +86,7 @@ public class AlarmController extends BaseController {
86 86 savedAlarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
87 87 return savedAlarm;
88 88 } catch (Exception e) {
89   - logEntityAction(emptyId(EntityType.ASSET), alarm,
  89 + logEntityAction(emptyId(EntityType.ALARM), alarm,
90 90 null, alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
91 91 throw handleException(e);
92 92 }
... ...
... ... @@ -15,7 +15,12 @@
15 15 */
16 16 package org.thingsboard.server.controller;
17 17
  18 +import com.fasterxml.jackson.databind.JsonNode;
  19 +import com.fasterxml.jackson.databind.ObjectMapper;
  20 +import com.fasterxml.jackson.databind.node.ObjectNode;
  21 +import lombok.Getter;
18 22 import org.springframework.beans.factory.annotation.Autowired;
  23 +import org.springframework.beans.factory.annotation.Value;
19 24 import org.springframework.http.HttpStatus;
20 25 import org.springframework.security.access.prepost.PreAuthorize;
21 26 import org.springframework.web.bind.annotation.PathVariable;
... ... @@ -39,7 +44,11 @@ import org.thingsboard.server.common.data.page.TextPageData;
39 44 import org.thingsboard.server.common.data.page.TextPageLink;
40 45 import org.thingsboard.server.common.data.security.Authority;
41 46 import org.thingsboard.server.common.data.security.UserCredentials;
  47 +import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository;
42 48 import org.thingsboard.server.service.security.model.SecurityUser;
  49 +import org.thingsboard.server.service.security.model.UserPrincipal;
  50 +import org.thingsboard.server.service.security.model.token.JwtToken;
  51 +import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
43 52
44 53 import javax.servlet.http.HttpServletRequest;
45 54
... ... @@ -50,9 +59,21 @@ public class UserController extends BaseController {
50 59 public static final String USER_ID = "userId";
51 60 public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!";
52 61 public static final String ACTIVATE_URL_PATTERN = "%s/api/noauth/activate?activateToken=%s";
  62 +
  63 + @Value("${security.user_token_access_enabled}")
  64 + @Getter
  65 + private boolean userTokenAccessEnabled;
  66 +
53 67 @Autowired
54 68 private MailService mailService;
55 69
  70 + @Autowired
  71 + private JwtTokenFactory tokenFactory;
  72 +
  73 + @Autowired
  74 + private RefreshTokenRepository refreshTokenRepository;
  75 +
  76 +
56 77 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
57 78 @RequestMapping(value = "/user/{userId}", method = RequestMethod.GET)
58 79 @ResponseBody
... ... @@ -71,6 +92,42 @@ public class UserController extends BaseController {
71 92 }
72 93 }
73 94
  95 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  96 + @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET)
  97 + @ResponseBody
  98 + public boolean isUserTokenAccessEnabled() {
  99 + return userTokenAccessEnabled;
  100 + }
  101 +
  102 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  103 + @RequestMapping(value = "/user/{userId}/token", method = RequestMethod.GET)
  104 + @ResponseBody
  105 + public JsonNode getUserToken(@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
  106 + checkParameter(USER_ID, strUserId);
  107 + try {
  108 + UserId userId = new UserId(toUUID(strUserId));
  109 + SecurityUser authUser = getCurrentUser();
  110 + User user = userService.findUserById(userId);
  111 + if (!userTokenAccessEnabled || (authUser.getAuthority() == Authority.SYS_ADMIN && user.getAuthority() != Authority.TENANT_ADMIN)
  112 + || (authUser.getAuthority() == Authority.TENANT_ADMIN && !authUser.getTenantId().equals(user.getTenantId()))) {
  113 + throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
  114 + ThingsboardErrorCode.PERMISSION_DENIED);
  115 + }
  116 + UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
  117 + UserCredentials credentials = userService.findUserCredentialsByUserId(userId);
  118 + SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
  119 + JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser);
  120 + JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser);
  121 + ObjectMapper objectMapper = new ObjectMapper();
  122 + ObjectNode tokenObject = objectMapper.createObjectNode();
  123 + tokenObject.put("token", accessToken.getToken());
  124 + tokenObject.put("refreshToken", refreshToken.getToken());
  125 + return tokenObject;
  126 + } catch (Exception e) {
  127 + throw handleException(e);
  128 + }
  129 + }
  130 +
74 131 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
75 132 @RequestMapping(value = "/user", method = RequestMethod.POST)
76 133 @ResponseBody
... ...
... ... @@ -22,6 +22,7 @@ import delight.nashornsandbox.NashornSandbox;
22 22 import delight.nashornsandbox.NashornSandboxes;
23 23 import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
24 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.apache.commons.lang3.tuple.Pair;
25 26
26 27 import javax.annotation.PostConstruct;
27 28 import javax.annotation.PreDestroy;
... ... @@ -42,9 +43,10 @@ public abstract class AbstractNashornJsSandboxService implements JsSandboxServic
42 43 private ScriptEngine engine;
43 44 private ExecutorService monitorExecutorService;
44 45
45   - private Map<UUID, String> functionsMap = new ConcurrentHashMap<>();
46   -
47   - private Map<UUID,AtomicInteger> blackListedFunctions = new ConcurrentHashMap<>();
  46 + private final Map<UUID, String> functionsMap = new ConcurrentHashMap<>();
  47 + private final Map<UUID,AtomicInteger> blackListedFunctions = new ConcurrentHashMap<>();
  48 + private final Map<String, Pair<UUID, AtomicInteger>> scriptToId = new ConcurrentHashMap<>();
  49 + private final Map<UUID, AtomicInteger> scriptIdToCount = new ConcurrentHashMap<>();
48 50
49 51 @PostConstruct
50 52 public void init() {
... ... @@ -78,19 +80,27 @@ public abstract class AbstractNashornJsSandboxService implements JsSandboxServic
78 80
79 81 @Override
80 82 public ListenableFuture<UUID> eval(JsScriptType scriptType, String scriptBody, String... argNames) {
81   - UUID scriptId = UUID.randomUUID();
82   - String functionName = "invokeInternal_" + scriptId.toString().replace('-','_');
83   - String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames);
84   - try {
85   - if (useJsSandbox()) {
86   - sandbox.eval(jsScript);
87   - } else {
88   - engine.eval(jsScript);
  83 + Pair<UUID, AtomicInteger> deduplicated = deduplicate(scriptType, scriptBody);
  84 + UUID scriptId = deduplicated.getLeft();
  85 + AtomicInteger duplicateCount = deduplicated.getRight();
  86 +
  87 + if(duplicateCount.compareAndSet(0, 1)) {
  88 + String functionName = "invokeInternal_" + scriptId.toString().replace('-', '_');
  89 + String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames);
  90 + try {
  91 + if (useJsSandbox()) {
  92 + sandbox.eval(jsScript);
  93 + } else {
  94 + engine.eval(jsScript);
  95 + }
  96 + functionsMap.put(scriptId, functionName);
  97 + } catch (Exception e) {
  98 + duplicateCount.decrementAndGet();
  99 + log.warn("Failed to compile JS script: {}", e.getMessage(), e);
  100 + return Futures.immediateFailedFuture(e);
89 101 }
90   - functionsMap.put(scriptId, functionName);
91   - } catch (Exception e) {
92   - log.warn("Failed to compile JS script: {}", e.getMessage(), e);
93   - return Futures.immediateFailedFuture(e);
  102 + } else {
  103 + duplicateCount.incrementAndGet();
94 104 }
95 105 return Futures.immediateFuture(scriptId);
96 106 }
... ... @@ -122,6 +132,13 @@ public abstract class AbstractNashornJsSandboxService implements JsSandboxServic
122 132
123 133 @Override
124 134 public ListenableFuture<Void> release(UUID scriptId) {
  135 + AtomicInteger count = scriptIdToCount.get(scriptId);
  136 + if(count != null) {
  137 + if(count.decrementAndGet() > 0) {
  138 + return Futures.immediateFuture(null);
  139 + }
  140 + }
  141 +
125 142 String functionName = functionsMap.get(scriptId);
126 143 if (functionName != null) {
127 144 try {
... ... @@ -156,4 +173,16 @@ public abstract class AbstractNashornJsSandboxService implements JsSandboxServic
156 173 throw new RuntimeException("No script factory implemented for scriptType: " + scriptType);
157 174 }
158 175 }
  176 +
  177 + private Pair<UUID, AtomicInteger> deduplicate(JsScriptType scriptType, String scriptBody) {
  178 + Pair<UUID, AtomicInteger> precomputed = Pair.of(UUID.randomUUID(), new AtomicInteger());
  179 +
  180 + Pair<UUID, AtomicInteger> pair = scriptToId.computeIfAbsent(deduplicateKey(scriptType, scriptBody), i -> precomputed);
  181 + AtomicInteger duplicateCount = scriptIdToCount.computeIfAbsent(pair.getLeft(), i -> pair.getRight());
  182 + return Pair.of(pair.getLeft(), duplicateCount);
  183 + }
  184 +
  185 + private String deduplicateKey(JsScriptType scriptType, String scriptBody) {
  186 + return scriptType + "_" + scriptBody;
  187 + }
159 188 }
... ...
... ... @@ -45,7 +45,7 @@ public class RuleNodeJsScriptEngine implements org.thingsboard.rule.engine.api.S
45 45 try {
46 46 this.scriptId = this.sandboxService.eval(JsScriptType.RULE_NODE_SCRIPT, script, argNames).get();
47 47 } catch (Exception e) {
48   - throw new IllegalArgumentException("Can't compile script: " + e.getMessage());
  48 + throw new IllegalArgumentException("Can't compile script: " + e.getMessage(), e);
49 49 }
50 50 }
51 51
... ...
... ... @@ -24,12 +24,15 @@ import org.springframework.beans.factory.annotation.Autowired;
24 24 import org.springframework.context.annotation.Lazy;
25 25 import org.springframework.stereotype.Service;
26 26 import org.springframework.util.StringUtils;
  27 +import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg;
27 28 import org.thingsboard.rule.engine.api.util.DonAsynchron;
  29 +import org.thingsboard.server.actors.service.ActorService;
28 30 import org.thingsboard.server.common.data.DataConstants;
29 31 import org.thingsboard.server.common.data.EntityType;
30 32 import org.thingsboard.server.common.data.id.DeviceId;
31 33 import org.thingsboard.server.common.data.id.EntityId;
32 34 import org.thingsboard.server.common.data.id.EntityIdFactory;
  35 +import org.thingsboard.server.common.data.id.TenantId;
33 36 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
34 37 import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry;
35 38 import org.thingsboard.server.common.data.kv.BaseTsKvQuery;
... ... @@ -42,6 +45,7 @@ import org.thingsboard.server.common.data.kv.LongDataEntry;
42 45 import org.thingsboard.server.common.data.kv.StringDataEntry;
43 46 import org.thingsboard.server.common.data.kv.TsKvEntry;
44 47 import org.thingsboard.server.common.data.kv.TsKvQuery;
  48 +import org.thingsboard.server.common.msg.cluster.SendToClusterMsg;
45 49 import org.thingsboard.server.common.msg.cluster.ServerAddress;
46 50 import org.thingsboard.server.dao.attributes.AttributesService;
47 51 import org.thingsboard.server.dao.timeseries.TimeseriesService;
... ... @@ -101,6 +105,10 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
101 105 @Lazy
102 106 private DeviceStateService stateService;
103 107
  108 + @Autowired
  109 + @Lazy
  110 + private ActorService actorService;
  111 +
104 112 private ExecutorService tsCallBackExecutor;
105 113 private ExecutorService wsCallBackExecutor;
106 114
... ... @@ -204,6 +212,13 @@ public class DefaultTelemetrySubscriptionService implements TelemetrySubscriptio
204 212 }
205 213
206 214 @Override
  215 + public void onSharedAttributesUpdate(TenantId tenantId, DeviceId deviceId, Set<AttributeKvEntry> attributes) {
  216 + DeviceAttributesEventNotificationMsg notificationMsg = DeviceAttributesEventNotificationMsg.onUpdate(tenantId,
  217 + deviceId, DataConstants.SHARED_SCOPE, new ArrayList<>(attributes));
  218 + actorService.onMsg(new SendToClusterMsg(deviceId, notificationMsg));
  219 + }
  220 +
  221 + @Override
207 222 public void onNewRemoteSubscription(ServerAddress serverAddress, byte[] data) {
208 223 ClusterAPIProtos.SubscriptionProto proto;
209 224 try {
... ...
... ... @@ -66,12 +66,16 @@ plugins:
66 66 # Comma seperated package list used during classpath scanning for plugins
67 67 scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine}"
68 68
69   -# JWT Token parameters
70   -security.jwt:
71   - tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:900}" # Number of seconds (15 mins)
72   - refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:3600}" # Seconds (1 hour)
73   - tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}"
74   - tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}"
  69 +# Security parameters
  70 +security:
  71 + # JWT Token parameters
  72 + jwt:
  73 + tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:900}" # Number of seconds (15 mins)
  74 + refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:3600}" # Seconds (1 hour)
  75 + tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}"
  76 + tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}"
  77 + # Enable/disable access to Tenant Administrators JWT token by System Administrator or Customer Users JWT token by Tenant Administrator
  78 + user_token_access_enabled: "${SECURITY_USER_TOKEN_ACCESS_ENABLED:true}"
75 79
76 80 # Device communication protocol parameters
77 81 http:
... ... @@ -201,7 +205,7 @@ cassandra:
201 205 read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}"
202 206 write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}"
203 207 default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}"
204   - # Specify partitioning size for timestamp key-value storage. Example MINUTES, HOURS, DAYS, MONTHS
  208 + # Specify partitioning size for timestamp key-value storage. Example MINUTES, HOURS, DAYS, MONTHS,INDEFINITE
205 209 ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}"
206 210 ts_key_value_ttl: "${TS_KV_TTL:0}"
207 211 buffer_size: "${CASSANDRA_QUERY_BUFFER_SIZE:200000}"
... ... @@ -291,6 +295,9 @@ caffeine:
291 295 devices:
292 296 timeToLiveInMinutes: 1440
293 297 maxSize: 100000
  298 + assets:
  299 + timeToLiveInMinutes: 1440
  300 + maxSize: 100000
294 301
295 302 redis:
296 303 # standalone or cluster
... ...
... ... @@ -19,4 +19,5 @@ public class CacheConstants {
19 19 public static final String DEVICE_CREDENTIALS_CACHE = "deviceCredentials";
20 20 public static final String RELATIONS_CACHE = "relations";
21 21 public static final String DEVICE_CACHE = "devices";
  22 + public static final String ASSET_CACHE = "assets";
22 23 }
... ...
... ... @@ -34,7 +34,7 @@ public interface AssetService {
34 34
35 35 ListenableFuture<Asset> findAssetByIdAsync(AssetId assetId);
36 36
37   - Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name);
  37 + Asset findAssetByTenantIdAndName(TenantId tenantId, String name);
38 38
39 39 Asset saveAsset(Asset asset);
40 40
... ...
... ... @@ -21,6 +21,10 @@ import com.google.common.util.concurrent.Futures;
21 21 import com.google.common.util.concurrent.ListenableFuture;
22 22 import lombok.extern.slf4j.Slf4j;
23 23 import org.springframework.beans.factory.annotation.Autowired;
  24 +import org.springframework.cache.Cache;
  25 +import org.springframework.cache.CacheManager;
  26 +import org.springframework.cache.annotation.CacheEvict;
  27 +import org.springframework.cache.annotation.Cacheable;
24 28 import org.springframework.stereotype.Service;
25 29 import org.springframework.util.StringUtils;
26 30 import org.thingsboard.server.common.data.Customer;
... ... @@ -48,15 +52,12 @@ import java.util.ArrayList;
48 52 import java.util.Collections;
49 53 import java.util.Comparator;
50 54 import java.util.List;
51   -import java.util.Optional;
52 55 import java.util.stream.Collectors;
53 56
  57 +import static org.thingsboard.server.common.data.CacheConstants.ASSET_CACHE;
54 58 import static org.thingsboard.server.dao.DaoUtil.toUUIDs;
55 59 import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
56   -import static org.thingsboard.server.dao.service.Validator.validateId;
57   -import static org.thingsboard.server.dao.service.Validator.validateIds;
58   -import static org.thingsboard.server.dao.service.Validator.validatePageLink;
59   -import static org.thingsboard.server.dao.service.Validator.validateString;
  60 +import static org.thingsboard.server.dao.service.Validator.*;
60 61
61 62 @Service
62 63 @Slf4j
... ... @@ -75,6 +76,9 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
75 76 @Autowired
76 77 private CustomerDao customerDao;
77 78
  79 + @Autowired
  80 + private CacheManager cacheManager;
  81 +
78 82 @Override
79 83 public Asset findAssetById(AssetId assetId) {
80 84 log.trace("Executing findAssetById [{}]", assetId);
... ... @@ -89,13 +93,16 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
89 93 return assetDao.findByIdAsync(assetId.getId());
90 94 }
91 95
  96 + @Cacheable(cacheNames = ASSET_CACHE, key = "{#tenantId, #name}")
92 97 @Override
93   - public Optional<Asset> findAssetByTenantIdAndName(TenantId tenantId, String name) {
  98 + public Asset findAssetByTenantIdAndName(TenantId tenantId, String name) {
94 99 log.trace("Executing findAssetByTenantIdAndName [{}][{}]", tenantId, name);
95 100 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
96   - return assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name);
  101 + return assetDao.findAssetsByTenantIdAndName(tenantId.getId(), name)
  102 + .orElse(null);
97 103 }
98 104
  105 + @CacheEvict(cacheNames = ASSET_CACHE, key = "{#asset.tenantId, #asset.name}")
99 106 @Override
100 107 public Asset saveAsset(Asset asset) {
101 108 log.trace("Executing saveAsset [{}]", asset);
... ... @@ -122,6 +129,14 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ
122 129 log.trace("Executing deleteAsset [{}]", assetId);
123 130 validateId(assetId, INCORRECT_ASSET_ID + assetId);
124 131 deleteEntityRelations(assetId);
  132 +
  133 + Cache cache = cacheManager.getCache(ASSET_CACHE);
  134 + Asset asset = assetDao.findById(assetId.getId());
  135 + List<Object> list = new ArrayList<>();
  136 + list.add(asset.getTenantId());
  137 + list.add(asset.getName());
  138 + cache.evict(list);
  139 +
125 140 assetDao.removeById(assetId.getId());
126 141 }
127 142
... ...
... ... @@ -16,9 +16,7 @@
16 16 package org.thingsboard.server.dao.relation;
17 17
18 18 import com.google.common.base.Function;
19   -import com.google.common.util.concurrent.AsyncFunction;
20   -import com.google.common.util.concurrent.Futures;
21   -import com.google.common.util.concurrent.ListenableFuture;
  19 +import com.google.common.util.concurrent.*;
22 20 import lombok.extern.slf4j.Slf4j;
23 21 import org.springframework.beans.factory.annotation.Autowired;
24 22 import org.springframework.cache.Cache;
... ... @@ -41,7 +39,6 @@ import org.thingsboard.server.dao.exception.DataValidationException;
41 39
42 40 import javax.annotation.Nullable;
43 41 import java.util.ArrayList;
44   -import java.util.Arrays;
45 42 import java.util.Collections;
46 43 import java.util.HashSet;
47 44 import java.util.List;
... ... @@ -94,10 +91,10 @@ public class BaseRelationService implements RelationService {
94 91
95 92 @Caching(evict = {
96 93 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type, #relation.typeGroup}"),
97   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup}"),
98   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup}"),
99   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup}"),
100   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup}")
  94 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup, 'FROM'}"),
  95 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup, 'FROM'}"),
  96 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup, 'TO'}"),
  97 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
101 98 })
102 99 @Override
103 100 public boolean saveRelation(EntityRelation relation) {
... ... @@ -108,10 +105,10 @@ public class BaseRelationService implements RelationService {
108 105
109 106 @Caching(evict = {
110 107 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type, #relation.typeGroup}"),
111   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup}"),
112   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup}"),
113   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup}"),
114   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup}")
  108 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup, 'FROM'}"),
  109 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup, 'FROM'}"),
  110 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup, 'TO'}"),
  111 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
115 112 })
116 113 @Override
117 114 public ListenableFuture<Boolean> saveRelationAsync(EntityRelation relation) {
... ... @@ -122,10 +119,10 @@ public class BaseRelationService implements RelationService {
122 119
123 120 @Caching(evict = {
124 121 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type, #relation.typeGroup}"),
125   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup}"),
126   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup}"),
127   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup}"),
128   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup}")
  122 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup, 'FROM'}"),
  123 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup, 'FROM'}"),
  124 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup, 'TO'}"),
  125 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
129 126 })
130 127 @Override
131 128 public boolean deleteRelation(EntityRelation relation) {
... ... @@ -136,10 +133,10 @@ public class BaseRelationService implements RelationService {
136 133
137 134 @Caching(evict = {
138 135 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.to, #relation.type, #relation.typeGroup}"),
139   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup}"),
140   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup}"),
141   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup}"),
142   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup}")
  136 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.type, #relation.typeGroup, 'FROM'}"),
  137 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.from, #relation.typeGroup, 'FROM'}"),
  138 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.typeGroup, 'TO'}"),
  139 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#relation.to, #relation.type, #relation.typeGroup, 'TO'}")
143 140 })
144 141 @Override
145 142 public ListenableFuture<Boolean> deleteRelationAsync(EntityRelation relation) {
... ... @@ -150,10 +147,10 @@ public class BaseRelationService implements RelationService {
150 147
151 148 @Caching(evict = {
152 149 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType, #typeGroup}"),
153   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup}"),
154   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup}"),
155   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup}"),
156   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup}")
  150 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}"),
  151 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup, 'FROM'}"),
  152 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup, 'TO'}"),
  153 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
157 154 })
158 155 @Override
159 156 public boolean deleteRelation(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
... ... @@ -164,10 +161,10 @@ public class BaseRelationService implements RelationService {
164 161
165 162 @Caching(evict = {
166 163 @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #to, #relationType, #typeGroup}"),
167   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup}"),
168   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup}"),
169   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup}"),
170   - @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup}")
  164 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}"),
  165 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup, 'FROM'}"),
  166 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup, 'TO'}"),
  167 + @CacheEvict(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
171 168 })
172 169 @Override
173 170 public ListenableFuture<Boolean> deleteRelationAsync(EntityId from, EntityId to, String relationType, RelationTypeGroup typeGroup) {
... ... @@ -250,30 +247,36 @@ public class BaseRelationService implements RelationService {
250 247 fromTypeAndTypeGroup.add(relation.getFrom());
251 248 fromTypeAndTypeGroup.add(relation.getType());
252 249 fromTypeAndTypeGroup.add(relation.getTypeGroup());
  250 + fromTypeAndTypeGroup.add(EntitySearchDirection.FROM.name());
253 251 cache.evict(fromTypeAndTypeGroup);
254 252
255 253 List<Object> fromAndTypeGroup = new ArrayList<>();
256 254 fromAndTypeGroup.add(relation.getFrom());
257 255 fromAndTypeGroup.add(relation.getTypeGroup());
  256 + fromAndTypeGroup.add(EntitySearchDirection.FROM.name());
258 257 cache.evict(fromAndTypeGroup);
259 258
260 259 List<Object> toAndTypeGroup = new ArrayList<>();
261 260 toAndTypeGroup.add(relation.getTo());
262 261 toAndTypeGroup.add(relation.getTypeGroup());
  262 + toAndTypeGroup.add(EntitySearchDirection.TO.name());
263 263 cache.evict(toAndTypeGroup);
264 264
265 265 List<Object> toTypeAndTypeGroup = new ArrayList<>();
266   - fromTypeAndTypeGroup.add(relation.getTo());
267   - fromTypeAndTypeGroup.add(relation.getType());
268   - fromTypeAndTypeGroup.add(relation.getTypeGroup());
  266 + toTypeAndTypeGroup.add(relation.getTo());
  267 + toTypeAndTypeGroup.add(relation.getType());
  268 + toTypeAndTypeGroup.add(relation.getTypeGroup());
  269 + toTypeAndTypeGroup.add(EntitySearchDirection.TO.name());
269 270 cache.evict(toTypeAndTypeGroup);
270 271 }
271 272
272   - @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup}")
  273 + @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #typeGroup, 'FROM'}")
273 274 @Override
274 275 public List<EntityRelation> findByFrom(EntityId from, RelationTypeGroup typeGroup) {
  276 + validate(from);
  277 + validateTypeGroup(typeGroup);
275 278 try {
276   - return findByFromAsync(from, typeGroup).get();
  279 + return relationDao.findAllByFrom(from, typeGroup).get();
277 280 } catch (InterruptedException | ExecutionException e) {
278 281 throw new RuntimeException(e);
279 282 }
... ... @@ -284,7 +287,29 @@ public class BaseRelationService implements RelationService {
284 287 log.trace("Executing findByFrom [{}][{}]", from, typeGroup);
285 288 validate(from);
286 289 validateTypeGroup(typeGroup);
287   - return relationDao.findAllByFrom(from, typeGroup);
  290 +
  291 + List<Object> fromAndTypeGroup = new ArrayList<>();
  292 + fromAndTypeGroup.add(from);
  293 + fromAndTypeGroup.add(typeGroup);
  294 + fromAndTypeGroup.add(EntitySearchDirection.FROM.name());
  295 +
  296 + Cache cache = cacheManager.getCache(RELATIONS_CACHE);
  297 + List<EntityRelation> fromCache = cache.get(fromAndTypeGroup, List.class);
  298 + if (fromCache != null) {
  299 + return Futures.immediateFuture(fromCache);
  300 + } else {
  301 + ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByFrom(from, typeGroup);
  302 + Futures.addCallback(relationsFuture,
  303 + new FutureCallback<List<EntityRelation>>() {
  304 + @Override
  305 + public void onSuccess(@Nullable List<EntityRelation> result) {
  306 + cache.putIfAbsent(fromAndTypeGroup, result);
  307 + }
  308 + @Override
  309 + public void onFailure(Throwable t) {}
  310 + });
  311 + return relationsFuture;
  312 + }
288 313 }
289 314
290 315 @Override
... ... @@ -305,7 +330,7 @@ public class BaseRelationService implements RelationService {
305 330 });
306 331 }
307 332
308   - @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup}")
  333 + @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#from, #relationType, #typeGroup, 'FROM'}")
309 334 @Override
310 335 public List<EntityRelation> findByFromAndType(EntityId from, String relationType, RelationTypeGroup typeGroup) {
311 336 try {
... ... @@ -324,11 +349,13 @@ public class BaseRelationService implements RelationService {
324 349 return relationDao.findAllByFromAndType(from, relationType, typeGroup);
325 350 }
326 351
327   - @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup}")
  352 + @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #typeGroup, 'TO'}")
328 353 @Override
329 354 public List<EntityRelation> findByTo(EntityId to, RelationTypeGroup typeGroup) {
  355 + validate(to);
  356 + validateTypeGroup(typeGroup);
330 357 try {
331   - return findByToAsync(to, typeGroup).get();
  358 + return relationDao.findAllByTo(to, typeGroup).get();
332 359 } catch (InterruptedException | ExecutionException e) {
333 360 throw new RuntimeException(e);
334 361 }
... ... @@ -339,7 +366,29 @@ public class BaseRelationService implements RelationService {
339 366 log.trace("Executing findByTo [{}][{}]", to, typeGroup);
340 367 validate(to);
341 368 validateTypeGroup(typeGroup);
342   - return relationDao.findAllByTo(to, typeGroup);
  369 +
  370 + List<Object> toAndTypeGroup = new ArrayList<>();
  371 + toAndTypeGroup.add(to);
  372 + toAndTypeGroup.add(typeGroup);
  373 + toAndTypeGroup.add(EntitySearchDirection.TO.name());
  374 +
  375 + Cache cache = cacheManager.getCache(RELATIONS_CACHE);
  376 + List<EntityRelation> fromCache = cache.get(toAndTypeGroup, List.class);
  377 + if (fromCache != null) {
  378 + return Futures.immediateFuture(fromCache);
  379 + } else {
  380 + ListenableFuture<List<EntityRelation>> relationsFuture = relationDao.findAllByTo(to, typeGroup);
  381 + Futures.addCallback(relationsFuture,
  382 + new FutureCallback<List<EntityRelation>>() {
  383 + @Override
  384 + public void onSuccess(@Nullable List<EntityRelation> result) {
  385 + cache.putIfAbsent(toAndTypeGroup, result);
  386 + }
  387 + @Override
  388 + public void onFailure(Throwable t) {}
  389 + });
  390 + return relationsFuture;
  391 + }
343 392 }
344 393
345 394 @Override
... ... @@ -371,7 +420,7 @@ public class BaseRelationService implements RelationService {
371 420 });
372 421 }
373 422
374   - @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup}")
  423 + @Cacheable(cacheNames = RELATIONS_CACHE, key = "{#to, #relationType, #typeGroup, 'TO'}")
375 424 @Override
376 425 public List<EntityRelation> findByToAndType(EntityId to, String relationType, RelationTypeGroup typeGroup) {
377 426 try {
... ...
... ... @@ -29,17 +29,8 @@ import org.springframework.beans.factory.annotation.Value;
29 29 import org.springframework.core.env.Environment;
30 30 import org.springframework.stereotype.Component;
31 31 import org.thingsboard.server.common.data.id.EntityId;
32   -import org.thingsboard.server.common.data.kv.Aggregation;
33   -import org.thingsboard.server.common.data.kv.BaseTsKvQuery;
34   -import org.thingsboard.server.common.data.kv.BasicTsKvEntry;
35   -import org.thingsboard.server.common.data.kv.BooleanDataEntry;
  32 +import org.thingsboard.server.common.data.kv.*;
36 33 import org.thingsboard.server.common.data.kv.DataType;
37   -import org.thingsboard.server.common.data.kv.DoubleDataEntry;
38   -import org.thingsboard.server.common.data.kv.KvEntry;
39   -import org.thingsboard.server.common.data.kv.LongDataEntry;
40   -import org.thingsboard.server.common.data.kv.StringDataEntry;
41   -import org.thingsboard.server.common.data.kv.TsKvEntry;
42   -import org.thingsboard.server.common.data.kv.TsKvQuery;
43 34 import org.thingsboard.server.dao.model.ModelConstants;
44 35 import org.thingsboard.server.dao.nosql.CassandraAbstractAsyncDao;
45 36 import org.thingsboard.server.dao.util.NoSqlDao;
... ... @@ -70,6 +61,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
70 61 public static final String EQUALS_PARAM = " = ? ";
71 62 public static final String ASC_ORDER = "ASC";
72 63 public static final String DESC_ORDER = "DESC";
  64 + private static List<Long> FIXED_PARTITION = Arrays.asList(new Long[]{0L});
73 65
74 66 @Autowired
75 67 private Environment environment;
... ... @@ -161,14 +153,23 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
161 153 }
162 154 }
163 155
164   - private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, TsKvQuery query) {
165   - long minPartition = toPartitionTs(query.getStartTs());
166   - long maxPartition = toPartitionTs(query.getEndTs());
  156 + public boolean isFixedPartitioning() {
  157 + return tsFormat.getTruncateUnit().equals(TsPartitionDate.EPOCH_START);
  158 + }
167 159
  160 + private ListenableFuture<List<Long>> getPartitionsFuture(TsKvQuery query, EntityId entityId, long minPartition, long maxPartition) {
  161 + if (isFixedPartitioning()) { //no need to fetch partitions from DB
  162 + return Futures.immediateFuture(FIXED_PARTITION);
  163 + }
168 164 ResultSetFuture partitionsFuture = fetchPartitions(entityId, query.getKey(), minPartition, maxPartition);
  165 + return Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
  166 + }
169 167
  168 + private ListenableFuture<List<TsKvEntry>> findAllAsyncWithLimit(EntityId entityId, TsKvQuery query) {
  169 + long minPartition = toPartitionTs(query.getStartTs());
  170 + long maxPartition = toPartitionTs(query.getEndTs());
  171 + final ListenableFuture<List<Long>> partitionsListFuture = getPartitionsFuture(query, entityId, minPartition, maxPartition);
170 172 final SimpleListenableFuture<List<TsKvEntry>> resultFuture = new SimpleListenableFuture<>();
171   - final ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
172 173
173 174 Futures.addCallback(partitionsListFuture, new FutureCallback<List<Long>>() {
174 175 @Override
... ... @@ -179,7 +180,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
179 180
180 181 @Override
181 182 public void onFailure(Throwable t) {
182   - log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), minPartition, maxPartition, t);
  183 + log.error("[{}][{}] Failed to fetch partitions for interval {}-{}", entityId.getEntityType().name(), entityId.getId(), toPartitionTs(query.getStartTs()), toPartitionTs(query.getEndTs()), t);
183 184 }
184 185 }, readResultsProcessingExecutor);
185 186
... ... @@ -226,11 +227,7 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
226 227 final long startTs = query.getStartTs();
227 228 final long endTs = query.getEndTs();
228 229 final long ts = startTs + (endTs - startTs) / 2;
229   -
230   - ResultSetFuture partitionsFuture = fetchPartitions(entityId, key, minPartition, maxPartition);
231   -
232   - ListenableFuture<List<Long>> partitionsListFuture = Futures.transform(partitionsFuture, getPartitionsArrayFunction(), readResultsProcessingExecutor);
233   -
  230 + ListenableFuture<List<Long>> partitionsListFuture = getPartitionsFuture(query, entityId, minPartition, maxPartition);
234 231 ListenableFuture<List<ResultSet>> aggregationChunks = Futures.transformAsync(partitionsListFuture,
235 232 getFetchChunksAsyncFunction(entityId, key, aggregation, startTs, endTs), readResultsProcessingExecutor);
236 233
... ... @@ -306,6 +303,9 @@ public class CassandraBaseTimeseriesDao extends CassandraAbstractAsyncDao implem
306 303
307 304 @Override
308 305 public ListenableFuture<Void> savePartition(EntityId entityId, long tsKvEntryTs, String key, long ttl) {
  306 + if (isFixedPartitioning()) {
  307 + return Futures.immediateFuture(null);
  308 + }
309 309 ttl = computeTtl(ttl);
310 310 long partition = toPartitionTs(tsKvEntryTs);
311 311 log.debug("Saving partition {} for the entity [{}-{}] and key {}", partition, entityId.getEntityType(), entityId.getId(), key);
... ...
... ... @@ -16,22 +16,25 @@
16 16 package org.thingsboard.server.dao.timeseries;
17 17
18 18 import java.time.LocalDateTime;
  19 +import java.time.ZoneOffset;
19 20 import java.time.temporal.ChronoUnit;
20 21 import java.time.temporal.TemporalUnit;
21 22 import java.util.Optional;
22 23
23 24 public enum TsPartitionDate {
24 25
25   - MINUTES("yyyy-MM-dd-HH-mm", ChronoUnit.MINUTES), HOURS("yyyy-MM-dd-HH", ChronoUnit.HOURS), DAYS("yyyy-MM-dd", ChronoUnit.DAYS), MONTHS("yyyy-MM", ChronoUnit.MONTHS), YEARS("yyyy", ChronoUnit.YEARS);
  26 + MINUTES("yyyy-MM-dd-HH-mm", ChronoUnit.MINUTES), HOURS("yyyy-MM-dd-HH", ChronoUnit.HOURS), DAYS("yyyy-MM-dd", ChronoUnit.DAYS), MONTHS("yyyy-MM", ChronoUnit.MONTHS), YEARS("yyyy", ChronoUnit.YEARS),INDEFINITE("",ChronoUnit.FOREVER);
26 27
27 28 private final String pattern;
28 29 private final transient TemporalUnit truncateUnit;
  30 + public final static LocalDateTime EPOCH_START = LocalDateTime.ofEpochSecond(0,0, ZoneOffset.UTC);
29 31
30 32 TsPartitionDate(String pattern, TemporalUnit truncateUnit) {
31 33 this.pattern = pattern;
32 34 this.truncateUnit = truncateUnit;
33 35 }
34 36
  37 +
35 38 public String getPattern() {
36 39 return pattern;
37 40 }
... ... @@ -46,6 +49,8 @@ public enum TsPartitionDate {
46 49 return time.truncatedTo(ChronoUnit.DAYS).withDayOfMonth(1);
47 50 case YEARS:
48 51 return time.truncatedTo(ChronoUnit.DAYS).withDayOfYear(1);
  52 + case INDEFINITE:
  53 + return EPOCH_START;
49 54 default:
50 55 return time.truncatedTo(truncateUnit);
51 56 }
... ...
... ... @@ -227,6 +227,13 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest {
227 227 Assert.assertTrue(relations.contains(relationA));
228 228 Assert.assertTrue(relations.contains(relationB));
229 229 Assert.assertTrue(relations.contains(relationC));
  230 +
  231 + //Test from cache
  232 + relations = relationService.findByQuery(query).get();
  233 + Assert.assertEquals(3, relations.size());
  234 + Assert.assertTrue(relations.contains(relationA));
  235 + Assert.assertTrue(relations.contains(relationB));
  236 + Assert.assertTrue(relations.contains(relationC));
230 237 }
231 238
232 239 @Test
... ... @@ -253,6 +260,12 @@ public abstract class BaseRelationServiceTest extends AbstractServiceTest {
253 260 Assert.assertEquals(2, relations.size());
254 261 Assert.assertTrue(relations.contains(relationAB));
255 262 Assert.assertTrue(relations.contains(relationBC));
  263 +
  264 + //Test from cache
  265 + relations = relationService.findByQuery(query).get();
  266 + Assert.assertEquals(2, relations.size());
  267 + Assert.assertTrue(relations.contains(relationAB));
  268 + Assert.assertTrue(relations.contains(relationBC));
256 269 }
257 270
258 271
... ...
... ... @@ -21,6 +21,9 @@ caffeine.specs.deviceCredentials.maxSize=100000
21 21 caffeine.specs.devices.timeToLiveInMinutes=1440
22 22 caffeine.specs.devices.maxSize=100000
23 23
  24 +caffeine.specs.assets.timeToLiveInMinutes=1440
  25 +caffeine.specs.assets.maxSize=100000
  26 +
24 27 caching.specs.devices.timeToLiveInMinutes=1440
25 28 caching.specs.devices.maxSize=100000
26 29
... ...
... ... @@ -20,5 +20,7 @@ ADD run-application.sh /run-application.sh
20 20 ADD thingsboard.deb /thingsboard.deb
21 21
22 22 RUN apt-get update \
23   - && apt-get install -y nmap \
  23 + && apt-get install --no-install-recommends -y nmap \
  24 + && apt-get clean \
  25 + && rm -r /var/lib/apt/lists/* \
24 26 && chmod +x /run-application.sh
... ...
... ... @@ -40,6 +40,8 @@ public final class MqttClientConfig {
40 40 private Class<? extends Channel> channelClass = NioSocketChannel.class;
41 41
42 42 private boolean reconnect = true;
  43 + private long reconnectDelay = 1L;
  44 + private int maxBytesInMessage = 8092;
43 45
44 46 public MqttClientConfig() {
45 47 this(null);
... ... @@ -146,4 +148,38 @@ public final class MqttClientConfig {
146 148 public void setReconnect(boolean reconnect) {
147 149 this.reconnect = reconnect;
148 150 }
  151 +
  152 + public long getReconnectDelay() {
  153 + return reconnectDelay;
  154 + }
  155 +
  156 + /**
  157 + * Sets the reconnect delay in seconds. Defaults to 1 second.
  158 + * @param reconnectDelay
  159 + * @throws IllegalArgumentException if reconnectDelay is smaller than 1.
  160 + */
  161 + public void setReconnectDelay(long reconnectDelay) {
  162 + if (reconnectDelay <= 0) {
  163 + throw new IllegalArgumentException("reconnectDelay must be > 0");
  164 + }
  165 + this.reconnectDelay = reconnectDelay;
  166 + }
  167 +
  168 + public int getMaxBytesInMessage() {
  169 + return maxBytesInMessage;
  170 + }
  171 +
  172 + /**
  173 + * Sets the maximum number of bytes in the message for the {@link io.netty.handler.codec.mqtt.MqttDecoder}.
  174 + * Default value is 8092 as specified by Netty. The absolute maximum size is 256MB as set by the MQTT spec.
  175 + *
  176 + * @param maxBytesInMessage
  177 + * @throws IllegalArgumentException if maxBytesInMessage is smaller than 1 or greater than 256_000_000.
  178 + */
  179 + public void setMaxBytesInMessage(int maxBytesInMessage) {
  180 + if (maxBytesInMessage <= 0 || maxBytesInMessage > 256_000_000) {
  181 + throw new IllegalArgumentException("maxBytesInMessage must be > 0 or < 256_000_000");
  182 + }
  183 + this.maxBytesInMessage = maxBytesInMessage;
  184 + }
149 185 }
... ...
... ... @@ -155,7 +155,7 @@ final class MqttClientImpl implements MqttClient {
155 155 if (reconnect) {
156 156 this.reconnect = true;
157 157 }
158   - eventLoop.schedule((Runnable) () -> connect(host, port, reconnect), 1L, TimeUnit.SECONDS);
  158 + eventLoop.schedule((Runnable) () -> connect(host, port, reconnect), clientConfig.getReconnectDelay(), TimeUnit.SECONDS);
159 159 }
160 160 }
161 161
... ... @@ -512,7 +512,7 @@ final class MqttClientImpl implements MqttClient {
512 512 ch.pipeline().addLast(sslContext.newHandler(ch.alloc(), host, port));
513 513 }
514 514
515   - ch.pipeline().addLast("mqttDecoder", new MqttDecoder());
  515 + ch.pipeline().addLast("mqttDecoder", new MqttDecoder(clientConfig.getMaxBytesInMessage()));
516 516 ch.pipeline().addLast("mqttEncoder", MqttEncoder.INSTANCE);
517 517 ch.pipeline().addLast("idleStateHandler", new IdleStateHandler(MqttClientImpl.this.clientConfig.getTimeoutSeconds(), MqttClientImpl.this.clientConfig.getTimeoutSeconds(), 0));
518 518 ch.pipeline().addLast("mqttPingHandler", new MqttPingHandler(MqttClientImpl.this.clientConfig.getTimeoutSeconds()));
... ...
... ... @@ -16,11 +16,14 @@
16 16 package org.thingsboard.rule.engine.api;
17 17
18 18 import com.google.common.util.concurrent.FutureCallback;
  19 +import org.thingsboard.server.common.data.id.DeviceId;
19 20 import org.thingsboard.server.common.data.id.EntityId;
  21 +import org.thingsboard.server.common.data.id.TenantId;
20 22 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
21 23 import org.thingsboard.server.common.data.kv.TsKvEntry;
22 24
23 25 import java.util.List;
  26 +import java.util.Set;
24 27
25 28 /**
26 29 * Created by ashvayka on 02.04.18.
... ... @@ -41,4 +44,6 @@ public interface RuleEngineTelemetryService {
41 44
42 45 void saveAttrAndNotify(EntityId entityId, String scope, String key, boolean value, FutureCallback<Void> callback);
43 46
  47 + void onSharedAttributesUpdate(TenantId tenantId, DeviceId deviceId, Set<AttributeKvEntry> attributes);
  48 +
44 49 }
... ...
... ... @@ -17,12 +17,15 @@ package org.thingsboard.rule.engine.telemetry;
17 17
18 18 import com.google.gson.JsonParser;
19 19 import lombok.extern.slf4j.Slf4j;
20   -import org.thingsboard.rule.engine.api.util.TbNodeUtils;
21 20 import org.thingsboard.rule.engine.api.RuleNode;
22 21 import org.thingsboard.rule.engine.api.TbContext;
23 22 import org.thingsboard.rule.engine.api.TbNode;
24 23 import org.thingsboard.rule.engine.api.TbNodeConfiguration;
25 24 import org.thingsboard.rule.engine.api.TbNodeException;
  25 +import org.thingsboard.rule.engine.api.util.TbNodeUtils;
  26 +import org.thingsboard.server.common.data.DataConstants;
  27 +import org.thingsboard.server.common.data.EntityType;
  28 +import org.thingsboard.server.common.data.id.DeviceId;
26 29 import org.thingsboard.server.common.data.kv.AttributeKvEntry;
27 30 import org.thingsboard.server.common.data.plugin.ComponentType;
28 31 import org.thingsboard.server.common.msg.TbMsg;
... ... @@ -62,6 +65,9 @@ public class TbMsgAttributesNode implements TbNode {
62 65 String src = msg.getData();
63 66 Set<AttributeKvEntry> attributes = JsonConverter.convertToAttributes(new JsonParser().parse(src)).getAttributes();
64 67 ctx.getTelemetryService().saveAndNotify(msg.getOriginator(), config.getScope(), new ArrayList<>(attributes), new TelemetryNodeCallback(ctx, msg));
  68 + if (msg.getOriginator().getEntityType() == EntityType.DEVICE && DataConstants.SHARED_SCOPE.equals(config.getScope())) {
  69 + ctx.getTelemetryService().onSharedAttributesUpdate(ctx.getTenantId(), new DeviceId(msg.getOriginator().getId()), attributes);
  70 + }
65 71 }
66 72
67 73 @Override
... ...
1 1 {
2 2 "name": "thingsboard",
3 3 "private": true,
4   - "version": "2.1.0",
  4 + "version": "2.1.1",
5 5 "description": "Thingsboard UI",
6 6 "licenses": [
7 7 {
... ...
... ... @@ -27,6 +27,7 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
27 27 currentUserDetails = null,
28 28 lastPublicDashboardId = null,
29 29 allowedDashboardIds = [],
  30 + userTokenAccessEnabled = false,
30 31 userLoaded = false;
31 32
32 33 var refreshTokenQueue = [];
... ... @@ -59,7 +60,9 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
59 60 forceDefaultPlace: forceDefaultPlace,
60 61 updateLastPublicDashboardId: updateLastPublicDashboardId,
61 62 logout: logout,
62   - reloadUser: reloadUser
  63 + reloadUser: reloadUser,
  64 + isUserTokenAccessEnabled: isUserTokenAccessEnabled,
  65 + loginAsUser: loginAsUser
63 66 }
64 67
65 68 reloadUser();
... ... @@ -105,6 +108,7 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
105 108 currentUser = null;
106 109 currentUserDetails = null;
107 110 lastPublicDashboardId = null;
  111 + userTokenAccessEnabled = false;
108 112 allowedDashboardIds = [];
109 113 if (!jwtToken) {
110 114 clearTokenData();
... ... @@ -299,24 +303,36 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
299 303 } else if (currentUser) {
300 304 currentUser.authority = "ANONYMOUS";
301 305 }
  306 + var sysParamsPromise = loadSystemParams();
302 307 if (currentUser.isPublic) {
303 308 $rootScope.forceFullscreen = true;
304   - fetchAllowedDashboardIds();
  309 + sysParamsPromise.then(
  310 + () => { fetchAllowedDashboardIds(); },
  311 + () => { deferred.reject(); }
  312 + );
305 313 } else if (currentUser.userId) {
306 314 getUser(currentUser.userId, true).then(
307 315 function success(user) {
308   - currentUserDetails = user;
309   - updateUserLang();
310   - $rootScope.forceFullscreen = false;
311   - if (userForceFullscreen()) {
312   - $rootScope.forceFullscreen = true;
313   - }
314   - if ($rootScope.forceFullscreen && (currentUser.authority === 'TENANT_ADMIN' ||
315   - currentUser.authority === 'CUSTOMER_USER')) {
316   - fetchAllowedDashboardIds();
317   - } else {
318   - deferred.resolve();
319   - }
  316 + sysParamsPromise.then(
  317 + () => {
  318 + currentUserDetails = user;
  319 + updateUserLang();
  320 + $rootScope.forceFullscreen = false;
  321 + if (userForceFullscreen()) {
  322 + $rootScope.forceFullscreen = true;
  323 + }
  324 + if ($rootScope.forceFullscreen && (currentUser.authority === 'TENANT_ADMIN' ||
  325 + currentUser.authority === 'CUSTOMER_USER')) {
  326 + fetchAllowedDashboardIds();
  327 + } else {
  328 + deferred.resolve();
  329 + }
  330 + },
  331 + () => {
  332 + deferred.reject();
  333 + logout();
  334 + }
  335 + );
320 336 },
321 337 function fail() {
322 338 deferred.reject();
... ... @@ -353,6 +369,30 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
353 369 return deferred.promise;
354 370 }
355 371
  372 + function loadIsUserTokenAccessEnabled() {
  373 + var deferred = $q.defer();
  374 + if (currentUser.authority === 'SYS_ADMIN' || currentUser.authority === 'TENANT_ADMIN') {
  375 + var url = '/api/user/tokenAccessEnabled';
  376 + $http.get(url).then(function success(response) {
  377 + userTokenAccessEnabled = response.data;
  378 + deferred.resolve(response.data);
  379 + }, function fail() {
  380 + userTokenAccessEnabled = false;
  381 + deferred.reject();
  382 + });
  383 + } else {
  384 + userTokenAccessEnabled = false;
  385 + deferred.resolve(false);
  386 + }
  387 + return deferred.promise;
  388 + }
  389 +
  390 + function loadSystemParams() {
  391 + var promises = [];
  392 + promises.push(loadIsUserTokenAccessEnabled());
  393 + return $q.all(promises);
  394 + }
  395 +
356 396 function notifyUserLoaded() {
357 397 if (!userLoaded) {
358 398 userLoaded = true;
... ... @@ -520,7 +560,7 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
520 560 }
521 561 );
522 562 }
523   - $state.go(place, params);
  563 + $state.go(place, params, {reload: true});
524 564 } else {
525 565 $state.go('login', params);
526 566 }
... ... @@ -549,4 +589,18 @@ function UserService($http, $q, $rootScope, adminService, dashboardService, logi
549 589 }
550 590 }
551 591
  592 + function isUserTokenAccessEnabled() {
  593 + return userTokenAccessEnabled;
  594 + }
  595 +
  596 + function loginAsUser(userId) {
  597 + var url = '/api/user/' + userId + '/token';
  598 + $http.get(url).then(function success(response) {
  599 + var token = response.data.token;
  600 + var refreshToken = response.data.refreshToken;
  601 + setUserFromJwtToken(token, refreshToken, true);
  602 + }, function fail() {
  603 + });
  604 + }
  605 +
552 606 }
... ...
... ... @@ -1270,7 +1270,9 @@
1270 1270 "activation-link-text": "In order to activate user use the following <a href='{{activationLink}}' target='_blank'>activation link</a> :",
1271 1271 "copy-activation-link": "Copy activation link",
1272 1272 "activation-link-copied-message": "User activation link has been copied to clipboard",
1273   - "details": "Details"
  1273 + "details": "Details",
  1274 + "login-as-tenant-admin": "Login as Tenant Admin",
  1275 + "login-as-customer-user": "Login as Customer User"
1274 1276 },
1275 1277 "value": {
1276 1278 "type": "Value type",
... ... @@ -1451,12 +1453,14 @@
1451 1453 "language": {
1452 1454 "language": "Language",
1453 1455 "locales": {
  1456 + "fr_FR": "French",
1454 1457 "zh_CN": "Chinese",
1455 1458 "en_US": "English",
1456 1459 "it_IT": "Italian",
1457 1460 "ko_KR": "Korean",
1458 1461 "ru_RU": "Russian",
1459   - "es_ES": "Spanish"
  1462 + "es_ES": "Spanish",
  1463 + "ja_JA": "Japanese"
1460 1464 }
1461 1465 }
1462 1466 }
... ...
... ... @@ -1307,11 +1307,13 @@
1307 1307 "language": "Lenguaje",
1308 1308 "locales": {
1309 1309 "en_US": "Inglés",
  1310 + "fr_FR": "Francés",
1310 1311 "ko_KR": "Coreano",
1311 1312 "zh_CN": "Chino",
1312 1313 "ru_RU": "Ruso",
1313 1314 "es_ES": "Español",
1314   - "it_IT": "Italiano"
  1315 + "it_IT": "Italiano",
  1316 + "ja_JA": "Japonés"
1315 1317 }
1316 1318 }
1317   -}
\ No newline at end of file
  1319 +}
... ...
  1 +{
  2 +"access":{
  3 + "access-forbidden": "Accès interdit",
  4 + "access-forbidden-text": "Vous n'avez pas accès à cet emplacement! <br/> Essayez de vous connecter avec un autre utilisateur si vous souhaitez toujours accéder à cet emplacement.",
  5 + "refresh-token-expired": "La session a expiré",
  6 + "refresh-token-failed": "Impossible de rafraîchir la session",
  7 + "unauthorized": "non autorisé",
  8 + "unauthorized-access": "accès non autorisé",
  9 + "unauthorized-access-text": "Vous devez vous connecter pour avoir accès à cette ressource!"
  10 + },
  11 +"action":{
  12 + "activate": "Activer",
  13 + "add": "Ajouter",
  14 + "apply": "Appliquer",
  15 + "apply-changes": "Appliquer les modifications",
  16 + "assign": "Attribuer",
  17 + "back": "retour",
  18 + "cancel": "Annuler",
  19 + "clear-search": "Effacer la recherche",
  20 + "close": "Fermer",
  21 + "copy": "Copier",
  22 + "copy-reference": "Copier la référence",
  23 + "create": "Créer",
  24 + "decline-changes": "Refuser les modifications",
  25 + "delete": "Supprimer",
  26 + "drag": "Drag",
  27 + "edit": "Modifier",
  28 + "edit-mode": "Mode édition",
  29 + "enter-edit-mode": "Entrer en mode édition",
  30 + "export": "Exporter",
  31 + "import": "Importer",
  32 + "make-private": "Rendre privé",
  33 + "no": "Non",
  34 + "ok": "OK",
  35 + "paste": "coller",
  36 + "paste-reference": "Coller référence",
  37 + "refresh": "Rafraîchir",
  38 + "remove": "Supprimer",
  39 + "run": "Exécuter",
  40 + "save": "Enregistrer",
  41 + "saveAs": "Enregistrer sous",
  42 + "search": "Rechercher",
  43 + "share": "Partager",
  44 + "share-via": "Partager via {{provider}}",
  45 + "sign-in": "Connectez-vous!",
  46 + "suspend": "Suspendre",
  47 + "unassign": "Retirer",
  48 + "undo": "Annuler",
  49 + "update": "mise à jour",
  50 + "view": "Afficher",
  51 + "yes": "Oui"
  52 + },
  53 +"admin":{
  54 + "base-url": "URL de base",
  55 + "base-url-required": "L'URL de base est requise.",
  56 + "enable-tls": "Activer TLS",
  57 + "general": "Général",
  58 + "general-settings": "Paramètres généraux",
  59 + "mail-from": "Mail de",
  60 + "mail-from-required": "Mail de est requis.",
  61 + "outgoing-mail": "courrier sortant",
  62 + "outgoing-mail-settings": "Paramètres de courrier sortant",
  63 + "send-test-mail": "Envoyer un mail de test",
  64 + "smtp-host": "Hôte SMTP",
  65 + "smtp-host-required": "L'hôte SMTP est requis.",
  66 + "smtp-port": "Port SMTP",
  67 + "smtp-port-invalid": "Cela ne ressemble pas à un port smtp valide.",
  68 + "smtp-port-required": "Vous devez fournir un port smtp.",
  69 + "smtp-protocol": "Protocole SMTP",
  70 + "system-settings": "Paramètres système",
  71 + "test-mail-sent": "Le courrier de test a été envoyé avec succès!",
  72 + "timeout-invalid": "Cela ne ressemble pas à un délai d'expiration valide.",
  73 + "timeout-msec": "Délai (msec)",
  74 + "timeout-required": "Le délai est requis."
  75 + },
  76 +"aggregation":{
  77 + "aggregation": "agrégation",
  78 + "avg": "Moyenne",
  79 + "count": "Compte",
  80 + "function": "Fonction d'agrégation de données",
  81 + "group-interval": "Intervalle de regroupement",
  82 + "limit": "Valeurs maximales",
  83 + "max": "Max",
  84 + "min": "Min",
  85 + "none": "Aucune",
  86 + "sum": "Somme"
  87 + },
  88 +"alarm":{
  89 + "ack-time": "Heure d'acquittement",
  90 + "acknowledge": "Acquitter",
  91 + "aknowledge-alarms-text": "Etes-vous sûr de vouloir acquitter {count, plural, 1 {1 alarme} other {# alarmes}}?",
  92 + "aknowledge-alarms-title": "Acquitter {count, plural, 1 {1 alarme} other {# alarmes}}",
  93 + "alarm": "Alarme",
  94 + "alarm-details": "Détails de l'alarme",
  95 + "alarm-required": "Une alarme est requise",
  96 + "alarm-status": "Etat d'alarme",
  97 + "alarms": "Alarmes",
  98 + "clear": "Effacer",
  99 + "clear-alarms-text": "Êtes-vous sûr de vouloir effacer {count, plural, 1 {1 alarme} other {# alarmes}}?",
  100 + "clear-alarms-title": "Effacer {count, plural, 1 {1 alarme} other {# alarmes}}",
  101 + "clear-time": "Heure d'éffacement",
  102 + "created-time": "Heure de création",
  103 + "details": "Détails",
  104 + "display-status":{
  105 + "ACTIVE_ACK": "Active acquittée",
  106 + "ACTIVE_UNACK": "Active non acquittée",
  107 + "CLEARED_ACK": "effacée acquittée",
  108 + "CLEARED_UNACK": "effacée non acquittée"
  109 + },
  110 + "end-time": "Heure de fin",
  111 + "min-polling-interval-message": "Un intervalle d'interrogation d'au moins 1 seconde est autorisé.",
  112 + "no-alarms-matching": "Aucune alarme correspondant à {{entity}} n'a été trouvée. ",
  113 + "no-alarms-prompt": "Aucune alarme trouvée",
  114 + "no-data": "Aucune donnée à afficher",
  115 + "originator": "Source",
  116 + "originator-type": "Type de Source",
  117 + "polling-interval": "Intervalle d'interrogation des alarmes (sec)",
  118 + "polling-interval-required": "L'intervalle d'interrogation des alarmes est requis.",
  119 + "search": "Rechercher des alarmes",
  120 + "search-status":{
  121 + "ACK": "acquitté",
  122 + "ACTIVE": "active",
  123 + "ANY": "Toutes",
  124 + "CLEARED": "effacée",
  125 + "UNACK": "non acquittée"
  126 + },
  127 + "select-alarm": "Sélectionnez une alarme",
  128 + "selected-alarms": "{count, plural, 1 {1 alarme} other {# alarmes}} sélectionnées",
  129 + "severity": "Gravitée",
  130 + "severity-critical": "Critique",
  131 + "severity-indeterminate": "indéterminée",
  132 + "severity-major": "Majeure",
  133 + "severity-minor": "mineure",
  134 + "severity-warning": "Avertissement",
  135 + "start-time": "Heure de début",
  136 + "status": "Etat",
  137 + "type": "Type"
  138 + },
  139 +"alias":{
  140 + "add": "Ajouter un alias",
  141 + "all-entities": "Toutes les entités",
  142 + "any-relation": "toutes",
  143 + "default-entity-parameter-name": "Par défaut",
  144 + "default-state-entity": "Entité d'état par défaut",
  145 + "duplicate-alias": "Un alias portant le même nom existe déjà.",
  146 + "edit": "Modifier l'alias",
  147 + "entity-filter": "Filtre d'entité",
  148 + "entity-filter-no-entity-matched": "Aucune entité correspondant au filtre spécifié n'a été trouvée.",
  149 + "filter-type": "Type de filtre",
  150 + "filter-type-asset-search-query": "requête de recherche d'Assets",
  151 + "filter-type-asset-search-query-description": "Assets de types {{assetTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
  152 + "filter-type-asset-type": "type d'Asset",
  153 + "filter-type-asset-type-and-name-description": "Assets de type '{{assetType}}' et dont le nom commence par '{{prefix}}'",
  154 + "filter-type-asset-type-description": "Assets de type '{{assetType}}'",
  155 + "filter-type-device-search-query": "Requête de recherche de dispositif",
  156 + "filter-type-device-search-query-description": "Dispositifs de types {{deviceTypes}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
  157 + "filter-type-device-type": "Type de dispositif",
  158 + "filter-type-device-type-and-name-description": "Dispositifs de type '{{deviceType}}' et dont le nom commence par '{{prefix}}'",
  159 + "filter-type-device-type-description": "Dispositifs de type '{{deviceType}}'",
  160 + "filter-type-entity-list": "Liste d'entités",
  161 + "filter-type-entity-name": "Nom d'entité",
  162 + "filter-type-relations-query": "Interrogation des relations",
  163 + "filter-type-relations-query-description": "{{entities}} ayant {{relationType}} relation {{direction}} {{rootEntity}}",
  164 + "filter-type-required": "Le type de filtre est requis.",
  165 + "filter-type-single-entity": "Entité unique",
  166 + "filter-type-state-entity": "Entité de l'état du tableau de bord",
  167 + "filter-type-state-entity-description": "Entité extraite des paramètres d'état du tableau de bord",
  168 + "max-relation-level": "Niveau de relation maximum",
  169 + "name": "Nom de l'alias",
  170 + "name-required": "Le nom d'alias est requis",
  171 + "no-entity-filter-specified": "Aucun filtre d'entité spécifié",
  172 + "resolve-multiple": "Résoudre en plusieurs entités",
  173 + "root-entity": "Entité racine",
  174 + "root-state-entity": "Utiliser l'entité d'état du tableau de bord en tant que racine",
  175 + "state-entity": "Entité d'état du tableau de bord",
  176 + "state-entity-parameter-name": "Nom du paramètre d'entité d'état",
  177 + "unlimited-level": "niveau illimité"
  178 + },
  179 +"asset":{
  180 + "add": "Ajouter un Asset",
  181 + "add-asset-text": "Ajouter un nouvel Asset",
  182 + "any-asset": "Tout Asset",
  183 + "asset": "Asset",
  184 + "asset-details": "Détails de l'Asset",
  185 + "asset-public": "L'Asset est public",
  186 + "asset-required": "Asset requis",
  187 + "asset-type": "Type d'Asset",
  188 + "asset-type-list-empty": "Aucun type d'Asset sélectionné.",
  189 + "asset-type-required": "Le type d'Asset est requis.",
  190 + "asset-types": "Types d'Asset",
  191 + "assets": "Assets",
  192 + "assign-asset-to-customer": "Attribuer des Assets au client",
  193 + "assign-asset-to-customer-text": "Veuillez sélectionner les Assets à attribuer au client",
  194 + "assign-assets": "Attribuer des Assets",
  195 + "assign-assets-text": "Attribuer {count, plural, 1 {1 asset} other {# assets}} au client",
  196 + "assign-new-asset": "Attribuer un nouvel Asset",
  197 + "assign-to-customer": "Attribuer au client",
  198 + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les Assets",
  199 + "assignedToCustomer": "attribué au client",
  200 + "copyId": "Copier l'Id de l'Asset",
  201 + "delete": "Supprimer un Asset",
  202 + "delete-asset-text": "Faites attention, après la confirmation, l'Asset et toutes les données associées deviendront irrécupérables.",
  203 + "delete-asset-title": "Êtes-vous sûr de vouloir supprimer l'Asset '{{assetName}}'?",
  204 + "delete-assets": "Supprimer des Assets",
  205 + "delete-assets-action-title": "Supprimer {count, plural, 1 {1 asset} other {# assets}}",
  206 + "delete-assets-text": "Attention, après la confirmation, tous les Assets sélectionnés seront supprimés et toutes les données associées deviendront irrécupérables.",
  207 + "delete-assets-title": "Etes-vous sûr de vouloir supprimer {count, plural, 1 {1 asset} other {# assets}}?",
  208 + "description": "Description",
  209 + "details": "Détails",
  210 + "enter-asset-type": "Entrez le type d'Asset",
  211 + "events": "Evènements",
  212 + "idCopiedMessage": "L'Id d'asset a été copié dans le presse-papier",
  213 + "make-private": "Rendre l'Asset privé",
  214 + "make-private-asset-text": "Après la confirmation, l'Asset et toutes ses données seront rendus privés et ne seront pas accessibles par d'autres.",
  215 + "make-private-asset-title": "Etes-vous sûr de vouloir rendre l'Asset '{{assetName}}' privé '?",
  216 + "make-public": "Rendre l'Asset public",
  217 + "make-public-asset-text": "Après la confirmation, l'asset et toutes ses données seront rendus publics et accessibles aux autres.",
  218 + "make-public-asset-title": "Êtes-vous sûr de vouloir rendre l'Asset '{{assetName}}' public '?",
  219 + "management": "Gestion d'Assets",
  220 + "name": "Nom",
  221 + "name-required": "Nom est requis.",
  222 + "name-starts-with": "Le nom de l'Asset commence par",
  223 + "no-asset-types-matching": "Aucun type d'Asset correspondant à {{entitySubtype}} n'a été trouvé. ",
  224 + "no-assets-matching": "Aucun Asset correspondant à {{entity}} n'a été trouvé. ",
  225 + "no-assets-text": "Aucun Asset trouvé",
  226 + "public": "Public",
  227 + "select-asset": "Sélectionner un Asset",
  228 + "select-asset-type": "Sélectionner le type d'Asset",
  229 + "type": "Type",
  230 + "type-required": "Le type est requis.",
  231 + "unassign-asset": "Retirer l'Asset",
  232 + "unassign-asset-text": "Après la confirmation, l'Asset sera non attribué et ne sera pas accessible au client.",
  233 + "unassign-asset-title": "Êtes-vous sûr de vouloir retirer l'attribution de l'Asset '{{assetName}}'?",
  234 + "unassign-assets": "Retirer les Assets",
  235 + "unassign-assets-action-title": "Retirer {count, plural, 1 {1 asset} other {# assets}} du client",
  236 + "unassign-assets-text": "Après la confirmation, tous les Assets sélectionnés ne seront pas attribués et ne seront pas accessibles au client.",
  237 + "unassign-assets-title": "Êtes-vous sûr de vouloir retirer l'attribution de {count, plural, 1 {1 asset} other {# assets}}?",
  238 + "unassign-from-customer": "Retirer du client",
  239 + "view-assets": "Afficher les Assets"
  240 + },
  241 +"attribute":{
  242 + "add": "Ajouter un attribut",
  243 + "add-to-dashboard": "Ajouter au tableau de bord",
  244 + "add-widget-to-dashboard": "Ajouter un widget au tableau de bord",
  245 + "attributes": "Attributs",
  246 + "attributes-scope": "Etendue des attributs d'entité",
  247 + "delete-attributes": "Supprimer les attributs",
  248 + "delete-attributes-text": "Attention, après la confirmation, tous les attributs sélectionnés seront supprimés.",
  249 + "delete-attributes-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 attribut} other {# attributs}}?",
  250 + "enter-attribute-value": "Entrez la valeur de l'attribut",
  251 + "key": "Clé",
  252 + "key-required": "La Clé d'attribut est requise.",
  253 + "last-update-time": "Dernière mise à jour",
  254 + "latest-telemetry": "Dernière télémétrie",
  255 + "next-widget": "Widget suivant",
  256 + "prev-widget": "Widget précédent",
  257 + "scope-client": "Attributs du client",
  258 + "scope-latest-telemetry": "Dernière télémétrie",
  259 + "scope-server": "Attributs du serveur",
  260 + "scope-shared": "Attributs partagés",
  261 + "selected-attributes": "{count, plural, 1 {1 attribut} other {# attributs}} sélectionnés",
  262 + "selected-telemetry": "{count, plural, 1 {1 unité de télémétrie} other {# unités de télémétrie}} sélectionnées",
  263 + "show-on-widget": "Afficher sur le widget",
  264 + "value": "Valeur",
  265 + "value-required": "La valeur d'attribut est obligatoire.",
  266 + "widget-mode": "Mode du widget"
  267 + },
  268 +"audit-log":{
  269 + "action-data": "Action data",
  270 + "audit": "Audit",
  271 + "audit-log-details": "Détails du journal d'audit",
  272 + "audit-logs": "Journaux d'audit",
  273 + "clear-search": "Effacer la recherche",
  274 + "details": "Détails",
  275 + "entity-name": "Nom de l'entité",
  276 + "entity-type": "Type d'entité",
  277 + "failure-details": "Détails de l'échec",
  278 + "no-audit-logs-prompt": "Aucun journal trouvé",
  279 + "search": "Rechercher les journaux d'audit",
  280 + "status": "Etat",
  281 + "status-failure": "Échec",
  282 + "status-success": "Succès",
  283 + "timestamp": "Horodatage",
  284 + "type": "Type",
  285 + "type-activated": "Activé",
  286 + "type-added": "Ajouté",
  287 + "type-alarm-ack": "Acquitté",
  288 + "type-alarm-clear": "Effacé",
  289 + "type-assigned-to-customer": "Attribué au client",
  290 + "type-attributes-deleted": "Attributs supprimés",
  291 + "type-attributes-read": "Attributs lus",
  292 + "type-attributes-updated": "Attributs mis à jour",
  293 + "type-credentials-read": "Lecture des informations d'identification",
  294 + "type-credentials-updated": "Informations d'identification actualisées",
  295 + "type-deleted": "Supprimé",
  296 + "type-relation-add-or-update": "Relation mise à jour",
  297 + "type-relation-delete": "Relation supprimée",
  298 + "type-relations-delete": "Toutes les relations ont été supprimées",
  299 + "type-rpc-call": "Appel RPC",
  300 + "type-suspended": "Suspendu",
  301 + "type-unassigned-from-customer": "Non attribué du client",
  302 + "type-updated": "Mise à jour",
  303 + "user": "Utilisateur"
  304 + },
  305 +"common":{
  306 + "enter-password": "Entrez le mot de passe",
  307 + "enter-search": "Entrez la recherche",
  308 + "enter-username": "Entrez le nom d'utilisateur",
  309 + "password": "Mot de passe",
  310 + "username": "Nom d'utilisateur"
  311 + },
  312 +"confirm-on-exit":{
  313 + "html-message": "Vous avez des modifications non enregistrées. <br/> Êtes-vous sûr de vouloir quitter cette page?",
  314 + "message": "Vous avez des modifications non enregistrées. Êtes-vous sûr de vouloir quitter cette page?",
  315 + "title": "Modifications non enregistrées"
  316 + },
  317 +"contact":{
  318 + "address": "Adresse",
  319 + "address2": "adresse 2",
  320 + "city": "Ville",
  321 + "country": "Pays",
  322 + "email": "Email",
  323 + "no-address": "Pas d'adresse",
  324 + "phone": "Téléphone",
  325 + "postal-code": "Code postal",
  326 + "postal-code-invalid": "Format de code postal / code postal invalide",
  327 + "state": "Etat / Province"
  328 + },
  329 +"content-type":{
  330 + "binary": "Binaire (Base64)",
  331 + "json": "Json",
  332 + "text": "Texte"
  333 + },
  334 +"custom":{
  335 + "widget-action":{
  336 + "action-cell-button": "Action cell button",
  337 + "marker-click": "On marker click",
  338 + "row-click": "On row click",
  339 + "tooltip-tag-action": "Tooltip tag action"
  340 + }
  341 + },
  342 +"customer":{
  343 + "add": "Ajouter un client",
  344 + "add-customer-text": "Ajouter un nouveau client",
  345 + "assets": "Assets du client",
  346 + "copyId": "Copier l'id du client",
  347 + "customer": "Client",
  348 + "customer-details": "Détails du client",
  349 + "customer-required": "Le client est requis",
  350 + "customers": "Clients",
  351 + "dashboard": "Tableau de bord du client",
  352 + "dashboards": "tableaux de bord du client",
  353 + "default-customer": "Client par défaut",
  354 + "default-customer-required": "Le client par défaut est requis pour déboguer le tableau de bord au niveau du Tenant",
  355 + "delete": "Supprimer le client",
  356 + "delete-customer-text": "Faites attention, après la confirmation, le client et toutes les données associées deviendront irrécupérables.",
  357 + "delete-customer-title": "Êtes-vous sûr de vouloir supprimer le client '{{customerTitle}}'?",
  358 + "delete-customers-action-title": "Supprimer {count, plural, 1 {1 client} other {# clients}}",
  359 + "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.",
  360 + "delete-customers-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 client} other {# clients}}?",
  361 + "description": "Description",
  362 + "details": "Détails",
  363 + "devices": "Dispositifs du client",
  364 + "events": "Événements",
  365 + "idCopiedMessage": "L'Id du client a été copié dans le presse-papier",
  366 + "manage-assets": "Gérer les Assets",
  367 + "manage-customer-assets": "Gérer les Assets du client",
  368 + "manage-customer-dashboards": "Gérer les tableaux de bord du client",
  369 + "manage-customer-devices": "Gérer les dispositifs du client",
  370 + "manage-customer-users": "Gérer les utilisateurs du client",
  371 + "manage-dashboards": "Gérer les tableaux de bord",
  372 + "manage-devices": "Gérer les dispositifs",
  373 + "manage-public-assets": "Gérer les Assets publics",
  374 + "manage-public-dashboards": "Gérer les tableaux de bord publics",
  375 + "manage-public-devices": "Gérer les dispositifs publics",
  376 + "manage-users": "Gérer les utilisateurs",
  377 + "management": "Gestion des clients",
  378 + "no-customers-matching": "Aucun client correspondant à '{{entity}} n'a été trouvé.",
  379 + "no-customers-text": "Aucun client trouvé",
  380 + "public-assets": "Assets publics",
  381 + "public-dashboards": "Tableaux de bord publics",
  382 + "public-devices": "Dispositifs publics",
  383 + "select-customer": "Sélectionner un client",
  384 + "select-default-customer": "Sélectionnez le client par défaut",
  385 + "title": "Titre",
  386 + "title-required": "Le titre est requis."
  387 + },
  388 +"dashboard":{
  389 + "add": "Ajouter un tableau de bord",
  390 + "add-dashboard-text": "Ajouter un nouveau tableau de bord",
  391 + "add-state": "Ajouter un état du tableau de bord",
  392 + "add-widget": "Ajouter un nouveau widget",
  393 + "alias-resolution-error-title": "Erreur de configuration des alias de tableau de bord",
  394 + "assign-dashboard-to-customer": "Attribuer des tableaux de bord au client",
  395 + "assign-dashboard-to-customer-text": "Veuillez sélectionner les tableaux de bord à affecter au client",
  396 + "assign-dashboards": "Attribuer des tableaux de bord",
  397 + "assign-dashboards-text": "Attribuer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} aux clients",
  398 + "assign-new-dashboard": "Attribuer un nouveau tableau de bord",
  399 + "assign-to-customer": "Attribuer au client",
  400 + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les tableaux de bord",
  401 + "assign-to-customers": "Attribuer des tableaux de bord aux clients",
  402 + "assign-to-customers-text": "Veuillez sélectionner les clients pour attribuer les tableaux de bord",
  403 + "assigned-customers": "clients affectés",
  404 + "assignedToCustomer": "Attribué au client",
  405 + "assignedToCustomers": "attribué aux clients",
  406 + "autofill-height": "Hauteur de remplissage automatique",
  407 + "background-color": "Couleur de fond",
  408 + "background-image": "Image d'arrière-plan",
  409 + "background-size-mode": "Mode de taille d'arrière-plan",
  410 + "close-toolbar": "Fermer la barre d'outils",
  411 + "columns-count": "Nombre de colonnes",
  412 + "columns-count-required": "Le nombre de colonnes est requis.",
  413 + "configuration-error": "Erreur de configuration",
  414 + "copy-public-link": "Copier le lien public",
  415 + "create-new": "Créer un nouveau tableau de bord",
  416 + "create-new-dashboard": "Créer un nouveau tableau de bord",
  417 + "create-new-widget": "Créer un nouveau widget",
  418 + "dashboard": "Tableau de bord",
  419 + "dashboard-details": "Détails du tableau de bord",
  420 + "dashboard-file": "Fichier du tableau de bord",
  421 + "dashboard-import-missing-aliases-title": "Configurer les alias utilisés par le tableau de bord importé",
  422 + "dashboard-required": "Le tableau de bord est requis.",
  423 + "dashboards": "Tableaux de bord",
  424 + "delete": "Supprimer le tableau de bord",
  425 + "delete-dashboard-text": "Faites attention, après la confirmation, le tableau de bord et toutes les données associées deviendront irrécupérables.",
  426 + "delete-dashboard-title": "Êtes-vous sûr de vouloir supprimer le tableau de bord '{{dashboardTitle}}'?",
  427 + "delete-dashboards": "Supprimer les tableaux de bord",
  428 + "delete-dashboards-action-title": "Supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}",
  429 + "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.",
  430 + "delete-dashboards-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?",
  431 + "delete-state": "Supprimer l'état du tableau de bord",
  432 + "delete-state-text": "Etes-vous sûr de vouloir supprimer l'état du tableau de bord avec le nom '{{stateName}}'?",
  433 + "delete-state-title": "Supprimer l'état du tableau de bord",
  434 + "description": "Description",
  435 + "details": "Détails",
  436 + "display-dashboard-export": "Afficher l'exportation",
  437 + "display-dashboard-timewindow": "Afficher fenêtre de temps",
  438 + "display-dashboards-selection": "Afficher la sélection des tableaux de bord",
  439 + "display-entities-selection": "Afficher la sélection des entités",
  440 + "display-title": "Afficher le titre du tableau de bord",
  441 + "drop-image": "Déposer une image ou cliquez pour sélectionner un fichier à télécharger.",
  442 + "edit-state": "Modifier l'état du tableau de bord",
  443 + "export": "Exporter le tableau de bord",
  444 + "export-failed-error": "Impossible d'exporter le tableau de bord: {{error}}",
  445 + "hide-details": "Masquer les détails",
  446 + "horizontal-margin": "Marge horizontale",
  447 + "horizontal-margin-required": "Une valeur de marge horizontale est requise.",
  448 + "import": "Importer le tableau de bord",
  449 + "import-widget": "Importer un widget",
  450 + "invalid-aliases-config": "Impossible de trouver des dispositifs correspondant à certains filtres d'alias. <br/> Veuillez contacter votre administrateur pour résoudre ce problème.",
  451 + "invalid-dashboard-file-error": "Impossible d'importer le tableau de bord: structure de données du tableau de bord non valide",
  452 + "invalid-widget-file-error": "Impossible d'importer le widget: structure de données de widget invalide.",
  453 + "is-root-state": "Etat racine",
  454 + "make-private": "Rendre privé le tableau de bord",
  455 + "make-private-dashboard": "Rendre privé le tableau de bord",
  456 + "make-private-dashboard-text": "Après la confirmation, le tableau de bord sera rendu privé et ne sera plus accessible aux autres.",
  457 + "make-private-dashboard-title": "Etes-vous sûr de vouloir rendre le tableau de bord '{{dashboardTitle}}' privé?",
  458 + "make-public": "Rendre public le tableau de bord",
  459 + "manage-assigned-customers": "Gérer les clients affectés",
  460 + "manage-states": "Gérer les états du tableau de bord",
  461 + "management": "Gestion du tableau de bord",
  462 + "max-columns-count-message": "Seulement 1000 colonnes maximum sont autorisées.",
  463 + "max-horizontal-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge horizontale maximale.",
  464 + "max-mobile-row-height-message": "Seuls 200 pixels sont autorisés en tant que valeur maximale de hauteur de ligne mobile.",
  465 + "max-vertical-margin-message": "Seulement 50 sont autorisés en tant que valeur de marge verticale maximale.",
  466 + "min-columns-count-message": "Seul un nombre minimum de 10 colonnes est autorisé.",
  467 + "min-horizontal-margin-message": "Seul 0 est autorisé comme valeur de marge horizontale minimale.",
  468 + "min-mobile-row-height-message": "Seuls 5 pixels sont autorisés en tant que valeur minimale de hauteur de ligne mobile.",
  469 + "min-vertical-margin-message": "Seul 0 est autorisé comme valeur de marge verticale minimale.",
  470 + "mobile-layout": "Paramètres de mise en page mobiles",
  471 + "mobile-row-height": "Hauteur de ligne mobile, px",
  472 + "mobile-row-height-required": "Une valeur de hauteur de ligne mobile est requise.",
  473 + "new-dashboard-title": "Nouveau titre du tableau de bord",
  474 + "no-dashboards-matching": "Aucun tableau de bord correspondant à {{entity}} n'a été trouvé. ",
  475 + "no-dashboards-text": "Aucun tableau de bord trouvé",
  476 + "no-image": "Aucune image sélectionnée",
  477 + "no-widgets": "Aucun widget configuré",
  478 + "open-dashboard": "Ouvrir le tableau de bord",
  479 + "open-toolbar": "Ouvrir la barre d'outils du tableau de bord",
  480 + "public": "Public",
  481 + "public-dashboard-notice": "<b> Remarque: </ b> N'oubliez pas de rendre publics les dispositifs associés pour accéder à leurs données.",
  482 + "public-dashboard-text": "Votre tableau de bord <b> {{dashboardTitle}} </ b> est maintenant public et accessible via le lien public <a href='{{publicLink}}' target='_blank'> </a>: ",
  483 + "public-dashboard-title": "Le tableau de bord est maintenant public",
  484 + "public-link": "Lien public",
  485 + "public-link-copied-message": "Le lien public du tableau de bord a été copié dans le presse-papier",
  486 + "search-states": "Recherche des états du tableau de bord",
  487 + "select-dashboard": "Sélectionner le tableau de bord",
  488 + "select-devices": "Selectionner les dispositifs",
  489 + "select-existing": "Sélectionnez un tableau de bord existant",
  490 + "select-state": "Sélectionnez l'état cible",
  491 + "select-widget-subtitle": "Liste des types de widgets disponibles",
  492 + "select-widget-title": "Sélectionner un widget",
  493 + "selected-states": "{count, plural, 1 {1 état du tableau de bord} other {# états du tableau de bord}} sélectionnés",
  494 + "set-background": "Définir l'arrière-plan",
  495 + "settings": "Paramètres",
  496 + "show-details": "Afficher les détails",
  497 + "socialshare-text": "'{{dashboardTitle}}' powered by ThingsBoard",
  498 + "socialshare-title": "'{{dashboardTitle}}' powered by ThingsBoard",
  499 + "state": "Etat du tableau de bord",
  500 + "state-controller": "Contrôleur d'état",
  501 + "state-id": "ID d'état",
  502 + "state-id-exists": "L'état du tableau de bord avec le même Id existe déjà.",
  503 + "state-id-required": "L'Id d'état du tableau de bord est requis.",
  504 + "state-name": "Nom",
  505 + "state-name-required": "Le nom de l'état du tableau de bord est requis",
  506 + "states": "Etats du tableau de bord",
  507 + "title": "Titre",
  508 + "title-color": "Couleur du titre",
  509 + "title-required": "Le titre est requis.",
  510 + "toolbar-always-open": "Garder la barre d'outils ouverte",
  511 + "unassign-dashboard": "Retirer le tableau de bord",
  512 + "unassign-dashboard-text": "Après la confirmation, le tableau de bord ne sera pas attribué et ne sera pas accessible au client.",
  513 + "unassign-dashboard-title": "Êtes-vous sûr de vouloir annuler l'affectation du tableau de bord '{{dashboardTitle}}'?",
  514 + "unassign-dashboards": "Retirer les tableaux de bord",
  515 + "unassign-dashboards-action-text": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} des clients",
  516 + "unassign-dashboards-action-title": "Annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}} du client",
  517 + "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.",
  518 + "unassign-dashboards-title": "Etes-vous sûr de vouloir annuler l'affectation {count, plural, 1 {1 tableau de bord} other {# tableaux de bord}}?",
  519 + "unassign-from-customer": "Retirer du client",
  520 + "unassign-from-customers": "Retirer les tableaux de bord des clients",
  521 + "unassign-from-customers-text": "Veuillez sélectionner les clients à annuler l'affectation du ou des tableaux de bord",
  522 + "vertical-margin": "Marge verticale",
  523 + "vertical-margin-required": "Une valeur de marge verticale est requise",
  524 + "view-dashboards": "Afficher les tableaux de bord",
  525 + "widget-file": "Fichier du Widget",
  526 + "widget-import-missing-aliases-title": "Configurer les alias utilisés par le widget importé",
  527 + "widgets-margins": "Marge entre les widgets"
  528 + },
  529 +"datakey":{
  530 + "advanced": "Avancé",
  531 + "alarm": "Champs d'alarme",
  532 + "alarm-fields-required": "Les champs d'alarme sont obligatoires.",
  533 + "attributes": "Attributs",
  534 + "color": "Couleur",
  535 + "configuration": "Configuration de la clé de données",
  536 + "data-generation-func": "Fonction de génération de données",
  537 + "decimals": "Nombre de chiffres après virgule flottante",
  538 + "function-types": "Types de fonctions",
  539 + "function-types-required": "Les types de fonctions sont obligatoires",
  540 + "label": "Label",
  541 + "maximum-function-types": "Maximum {count, plural, 1 {1 type de fonction est autorisé.} other {# types de fonctions sont autorisés}}",
  542 + "maximum-timeseries-or-attributes": "Maximum {count, plural, 1 {1 timeseries / attribut est autorisé.} other {# timeseries / attributs sont autorisés}}",
  543 + "settings": "Paramètres",
  544 + "timeseries": "Timeseries",
  545 + "timeseries-or-attributes-required": "Les timeseries / attributs d'entité sont obligatoires.",
  546 + "timeseries-required": "Les Timeseries de l'entité sont obligatoires.",
  547 + "units": "Symbole spécial à afficher à côté de la valeur",
  548 + "use-data-post-processing-func": "Utiliser la fonction de post-traitement des données"
  549 + },
  550 +"datasource":{
  551 + "add-datasource-prompt": "Veuillez ajouter une source de données",
  552 + "name": "Nom",
  553 + "type": "Type de source de données"
  554 + },
  555 +"datetime":{
  556 + "date-from": "Date de",
  557 + "date-to": "Date à",
  558 + "time-from": "Heure de",
  559 + "time-to": "Heure à"
  560 + },
  561 +"details":{
  562 + "edit-mode": "Mode édition",
  563 + "toggle-edit-mode": "Activer le mode édition"
  564 + },
  565 +"device":{
  566 + "access-token": "Jeton d'accès",
  567 + "access-token-invalid": "La longueur du jeton d'accès doit être comprise entre 1 et 20 caractères.",
  568 + "access-token-required": "Le jeton d'accès est requis.",
  569 + "accessTokenCopiedMessage": "Le jeton d'accès au dispositif a été copié dans le presse-papier",
  570 + "add": "Ajouter un dispositif",
  571 + "add-alias": "Ajouter un alias de dispositif",
  572 + "add-device-text": "Ajouter un nouveau dispositif",
  573 + "alias": "Alias",
  574 + "alias-required": "Un alias du dispositif est requis.",
  575 + "aliases": "Alias ​​du dispositif",
  576 + "any-device": "N'importe quel dispositif",
  577 + "assign-device-to-customer": "Affecter des dispositifs au client",
  578 + "assign-device-to-customer-text": "Veuillez sélectionner les dispositif à affecter au client",
  579 + "assign-devices": "Attribuer des dispositifs",
  580 + "assign-devices-text": "Attribuer {count, plural, 1 {1 dispositif} other {# dispositifs}} au client",
  581 + "assign-new-device": "Attribuer un nouveau dispositif",
  582 + "assign-to-customer": "Attribuer au client",
  583 + "assign-to-customer-text": "Veuillez sélectionner le client pour attribuer le ou les dispositifs",
  584 + "assignedToCustomer": "Attribué au client",
  585 + "configure-alias": "Configurer '{{alias}}' alias",
  586 + "copyAccessToken": "Copier le jeton d'accès",
  587 + "copyId": "Copier l'Id du dispositif",
  588 + "create-new-alias": "Créez un nouveau!",
  589 + "create-new-key": "Créez un nouveau!",
  590 + "credentials": "Informations d'identification",
  591 + "credentials-type": "Type d'identification",
  592 + "delete": "Supprimer le dispositif",
  593 + "delete-device-text": "Faites attention, après la confirmation, le dispositif et toutes les données associées deviendront irrécupérables.",
  594 + "delete-device-title": "Êtes-vous sûr de vouloir supprimer le dispositif '{{deviceName}}'?",
  595 + "delete-devices": "Supprimer les dispositifs",
  596 + "delete-devices-action-title": "Supprimer {count, plural, 1 {1 dispositif} other {# dispositifs}}",
  597 + "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.",
  598 + "delete-devices-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 dispositif} other {# dispositifs}}?",
  599 + "description": "Description",
  600 + "details": "Détails",
  601 + "device": "Dispositif",
  602 + "device-alias": "Alias ​​du dispositif",
  603 + "device-credentials": "Informations d'identification du dispositif",
  604 + "device-details": "Détails du dispositif",
  605 + "device-list": "Liste des dispositifs",
  606 + "device-list-empty": "Aucun dispositif sélectionné.",
  607 + "device-name-filter-no-device-matched": "Aucun dispositif commençant par '{{device}} n'a été trouvé.",
  608 + "device-name-filter-required": "Le filtre de nom de dispositif est requis.",
  609 + "device-public": "Le dispositif est public",
  610 + "device-required": "Le dispositif est requis.",
  611 + "device-type": "Type de dispositif",
  612 + "device-type-list-empty": "Aucun type de dispositif sélectionné.",
  613 + "device-type-required": "Le type de dispositif est requis.",
  614 + "device-types": "Types de dispositif",
  615 + "devices": "Dispositifs",
  616 + "duplicate-alias-error": "Alias ​​en double trouvé '{{alias}}'. <br> Les alias de dispositifs doivent être uniques dans le tableau de bord.",
  617 + "enter-device-type": "Entrez le type de dispositif",
  618 + "events": "Événements",
  619 + "idCopiedMessage": "l'Id du dispositif a été copié dans le presse-papiers",
  620 + "is-gateway": "Est une passerelle",
  621 + "make-private": "Rendre le dispositif privé",
  622 + "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.",
  623 + "make-private-device-title": "Etes-vous sûr de vouloir rendre le dispositif {{deviceName}} privé?",
  624 + "make-public": "Rendre le dispositif public",
  625 + "make-public-device-text": "Après la confirmation, le dispositif et toutes ses données seront rendus publics et accessibles par d'autres.",
  626 + "make-public-device-title": "Êtes-vous sûr de vouloir rendre le dispositif {{deviceName}} 'public?",
  627 + "manage-credentials": "Gérer les informations d'identification",
  628 + "management": "Gestion des dispositifs",
  629 + "name": "Nom",
  630 + "name-required": "Le nom est requis.",
  631 + "name-starts-with": "Le nom du dispositif commence par",
  632 + "no-alias-matching": "'{{alias}}' introuvable.",
  633 + "no-aliases-found": "Aucun alias trouvé.",
  634 + "no-device-types-matching": "Aucun type de dispositif correspondant à {{entitySubtype}} n'a été trouvé.",
  635 + "no-devices-matching": "Aucun dispositif correspondant à '{{entity}} n'a été trouvé.",
  636 + "no-devices-text": "Aucun dispositif trouvé",
  637 + "no-key-matching": "'{{key}}' introuvable.",
  638 + "no-keys-found": "Aucune clé trouvée",
  639 + "public": "Public",
  640 + "remove-alias": "Supprimer l'alias du dispositif",
  641 + "rsa-key": "Clé publique RSA",
  642 + "rsa-key-required": "La clé publique RSA est requise.",
  643 + "secret": "Secret",
  644 + "secret-required": "Code secret est requis.",
  645 + "select-device": "Selectionner un dispositif",
  646 + "select-device-type": "Sélectionner le type d'appareil",
  647 + "unable-delete-device-alias-text": "L'alias du dispositif '{{deviceAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants: <br/> {{widgetsList}}",
  648 + "unable-delete-device-alias-title": "Impossible de supprimer l'alias du dispositif",
  649 + "unassign-device": "Annuler l'affectation du dispositif",
  650 + "unassign-device-text": "Après la confirmation, le dispositif ne sera pas attribué et ne sera pas accessible au client.",
  651 + "unassign-device-title": "Êtes-vous sûr de vouloir annuler l'affection du dispositif {{deviceName}} '?",
  652 + "unassign-devices": "Annuler l'affectation des dispositifs",
  653 + "unassign-devices-action-title": "Annuler l'affectation de {count, plural, 1 {1 dispositif} other {#dispositifs}} du client",
  654 + "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.",
  655 + "unassign-devices-title": "Voulez-vous vraiment annuler l'affectation de {count, plural, 1 {1 dispositif} other {# dispositifs}}?",
  656 + "unassign-from-customer": "Retirer du client",
  657 + "use-device-name-filter": "Utiliser le filtre",
  658 + "view-credentials": "Afficher les informations d'identification",
  659 + "view-devices": "Afficher les dispositifs"
  660 + },
  661 +"dialog":{
  662 + "close": "Fermer le dialogue"
  663 + },
  664 +"entity" : {
  665 + "add-alias": "Ajouter un alias d'entité",
  666 + "alarm-name-starts-with": "Les alarmes dont le nom commence par '{{prefix}}'",
  667 + "alias": "Alias",
  668 + "alias-required": "Un alias d'entité est requis.",
  669 + "aliases": "alias d'entité",
  670 + "all-subtypes": "Tout",
  671 + "any-entity": "Toute entité",
  672 + "asset-name-starts-with": "Les Assets dont le nom commence par '{{prefix}}'",
  673 + "configure-alias": "Configurer '{{alias}}' alias",
  674 + "create-new-alias": "Créez un nouveau!",
  675 + "create-new-key": "Créez un nouveau!",
  676 + "customer-name-starts-with": "Les clients dont les noms commencent par '{{prefix}}'",
  677 + "dashboard-name-starts-with": "Les tableaux de bord dont les noms commencent par '{{prefix}}'",
  678 + "details": "Détails de l'entité",
  679 + "device-name-starts-with": "Dispositifs dont le nom commence par '{{prefix}}'",
  680 + "duplicate-alias-error": "Alias ​​en double trouvé '{{alias}}'. <br> Les alias d'entité doivent être uniques dans le tableau de bord.",
  681 + "enter-entity-type": "Entrez le type d'entité",
  682 + "entities": "Entités",
  683 + "entity": "Entité",
  684 + "entity-alias": "Alias de l'entité",
  685 + "entity-list": "Liste d'entités",
  686 + "entity-list-empty": "Aucune entité sélectionnée.",
  687 + "entity-name": "Nom de l'entité",
  688 + "entity-name-filter-no-entity-matched": "Aucune entité commençant par '{{entity}}' n'a été trouvée.",
  689 + "entity-name-filter-required": "Le filtre de nom d'entité est requis.",
  690 + "entity-type": "Type d'entité",
  691 + "entity-type-list": "Liste de types d'entités",
  692 + "entity-type-list-empty": "Aucun type d'entité sélectionné.",
  693 + "entity-types": "Types d'entité",
  694 + "key": "Clé",
  695 + "key-name": "Nom de la clé",
  696 + "list-of-alarms": "{count, plural, 1 {Une alarme} other {Liste de # alarmes}}",
  697 + "list-of-assets": "{count, plural, 1 {Un Asset} other {Liste de # Assets}}",
  698 + "list-of-customers": "{count, plural, 1 {Un client} other {Liste de # clients}}",
  699 + "list-of-dashboards": "{count, plural, 1 {Un tableau de bord} other {Liste de # tableaux de bord}}",
  700 + "list-of-devices": "{count, plural, 1 {Un dispositif} other {Liste de # dispositifs}}",
  701 + "list-of-plugins": "{count, plural, 1 {Un plugin} other {Liste de # plugins}}",
  702 + "list-of-rulechains": "{count, plural, 1 {Une chaîne de règles} other {Liste de # chaînes de règles}}",
  703 + "list-of-rulenodes": "{count, plural, 1 {Un noeud de règles} other {Liste de # noeuds de règles}}",
  704 + "list-of-rules": "{count, plural, 1 {Une règle} other {Liste de # règles}}",
  705 + "list-of-tenants": "{count, plural, 1 {Un tenant} other {Liste de # tenants}}",
  706 + "list-of-users": "{count, plural, 1 {Un utilisateur} other {Liste de # utilisateurs}}",
  707 + "missing-entity-filter-error": "Le filtre est manquant pour l'alias '{{alias}}'.",
  708 + "name-starts-with": "Nom commence par",
  709 + "no-alias-matching": "'{{alias}}' introuvable.",
  710 + "no-aliases-found": "Aucun alias trouvé.",
  711 + "no-data": "Aucune donnée à afficher",
  712 + "no-entities-matching": "Aucune entité correspondant à '{{entity}}' n'a été trouvée.",
  713 + "no-entities-prompt": "Aucune entité trouvée",
  714 + "no-entity-types-matching": "Aucun type d'entité correspondant à {{entityType}} n'a été trouvé. ",
  715 + "no-key-matching": "'{{key}}' introuvable.",
  716 + "no-keys-found": "Aucune clé trouvée",
  717 + "plugin-name-starts-with": "Plugins dont les noms commencent par '{{prefix}}'",
  718 + "remove-alias": "Supprimer l'alias d'entité",
  719 + "rule-name-starts-with": "Règles dont les noms commencent par '{{prefix}}'",
  720 + "rulechain-name-starts-with": "Chaînes de règles dont les noms commencent par '{{prefix}}'",
  721 + "rulenode-name-starts-with": "Les noeuds de règles dont le nom commence par '{{prefix}}'",
  722 + "search": "Recherche d'entités",
  723 + "select-entities": "Sélectionner des entités",
  724 + "selected-entities": "{count, plural, 1 {1 entité} other {# entités}} sélectionnées",
  725 + "tenant-name-starts-with": "Les Tenant dont le nom commence par '{{prefix}}'",
  726 + "type": "Type",
  727 + "type-alarm": "Alarme",
  728 + "type-alarms": "Alarmes",
  729 + "type-asset": "Asset",
  730 + "type-assets": "Assets",
  731 + "type-current-customer": "Client actuel",
  732 + "type-customer": "Client",
  733 + "type-customers": "Clients",
  734 + "type-dashboard": "Tableau de bord",
  735 + "type-dashboards": "Tableaux de bord",
  736 + "type-device": "Dispositif",
  737 + "type-devices": "Dispositifs",
  738 + "type-plugin": "Plugin",
  739 + "type-plugins": "Plugins",
  740 + "type-required": "Le type d'entité est obligatoire.",
  741 + "type-rule": "Règle",
  742 + "type-rulechain": "Chaîne de règles",
  743 + "type-rulechains": "Chaînes de règles",
  744 + "type-rulenode": "Noeud de règle",
  745 + "type-rulenodes": "Noeuds de règle",
  746 + "type-rules": "Règles",
  747 + "type-tenant": "Tenant",
  748 + "type-tenants": "Tenants",
  749 + "type-user": "Utilisateur",
  750 + "type-users": "Utilisateurs",
  751 + "unable-delete-entity-alias-text": "L'alias d'entité '{{entityAlias}}' ne peut pas être supprimé car il est utilisé par les widgets suivants: <br/> {{widgetsList}}",
  752 + "unable-delete-entity-alias-title": "Impossible de supprimer l'alias d'entité",
  753 + "use-entity-name-filter": "Utiliser un filtre",
  754 + "user-name-starts-with": "Utilisateurs dont les noms commencent par '{{prefix}}'"
  755 + },
  756 +"error":{
  757 + "unable-to-connect": "Impossible de se connecter au serveur! Veuillez vérifier votre connexion Internet.",
  758 + "unhandled-error-code": "Code d'erreur non géré: {{errorCode}}",
  759 + "unknown-error": "Erreur inconnue"
  760 + },
  761 +"event":{
  762 + "alarm": "Alarme",
  763 + "body": "Corps",
  764 + "data": "Données",
  765 + "data-type": "Type de données",
  766 + "entity": "Entité",
  767 + "error": "erreur",
  768 + "errors-occurred": "Des erreurs sont survenues",
  769 + "event": "événement",
  770 + "event-time": "Heure de l'événement",
  771 + "event-type": "Type d'événement",
  772 + "failed": "Échec",
  773 + "message-id": "Message Id",
  774 + "message-type": "Type de message",
  775 + "messages-processed": "Messages traités",
  776 + "metadata": "Métadonnées",
  777 + "method": "Méthode",
  778 + "no-events-prompt": "Aucun événement trouvé",
  779 + "relation-type": "Type de relation",
  780 + "server": "Serveur",
  781 + "status": "Etat",
  782 + "success": "Succès",
  783 + "type": "Type",
  784 + "type-debug-rule-chain": "Debug",
  785 + "type-debug-rule-node": "Debug",
  786 + "type-error": "Erreur",
  787 + "type-lc-event": "Evénement du cycle de vie",
  788 + "type-stats": "Statistiques"
  789 + },
  790 +"extension":{
  791 + "add": "Ajouter une extension",
  792 + "add-attribute": "Ajouter un attribut",
  793 + "add-attribute-request": "Ajouter une demande d'attribut",
  794 + "add-attribute-update": "Ajouter une mise à jour d'attribut",
  795 + "add-broker": "Ajouter un Broker",
  796 + "add-config": "Ajouter une configuration de convertisseur",
  797 + "add-connect-request": "Ajouter une demande de connexion",
  798 + "add-converter": "Ajouter un convertisseur",
  799 + "add-device": "Ajouter un dispositif",
  800 + "add-disconnect-request": "Ajouter une demande de déconnexion",
  801 + "add-map": "Ajouter un élément de mappage",
  802 + "add-server-side-rpc-request": "Ajouter une requête RPC côté serveur",
  803 + "add-timeseries": "Ajouter des timeseries",
  804 + "anonymous": "Anonyme",
  805 + "attr-json-key-expression": "Expression json de la clé d'attribut",
  806 + "attr-topic-key-expression": "Expression du topic de la clé d'attribut",
  807 + "attribute-filter": "Filtre d'attribut",
  808 + "attribute-key-expression": "Expression de clé d'attribut",
  809 + "attribute-requests": "Demandes d'attributs",
  810 + "attribute-updates": "Mises à jour des attributs",
  811 + "attributes": "Attributs",
  812 + "basic": "Basic",
  813 + "brokers": "Brokers",
  814 + "ca-cert": "Fichier de certificat CA",
  815 + "cert": "Fichier de certificat *",
  816 + "client-scope": "Portée client",
  817 + "configuration": "Configuration",
  818 + "connect-requests": "Demandes de connexion",
  819 + "converter-configurations": "Configurations du convertisseur",
  820 + "converter-id": "ID du convertisseur",
  821 + "converter-json": "Json",
  822 + "converter-json-parse": "Impossible d'analyser le convertisseur json.",
  823 + "converter-json-required": "Le convertisseur json est requis.",
  824 + "converter-type": "Type de convertisseur",
  825 + "converters": "Convertisseurs",
  826 + "credentials": "Informations d'identification",
  827 + "custom": "Custom",
  828 + "delete": "Supprimer l'extension",
  829 + "delete-extension-text": "Attention, après la confirmation, l'extension et toutes les données associées deviendront irrécupérables.",
  830 + "delete-extension-title": "Êtes-vous sûr de vouloir supprimer l'extension '{{extensionId}}'?",
  831 + "delete-extensions-text": "Attention, après la confirmation, toutes les extensions sélectionnées seront supprimées.",
  832 + "delete-extensions-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 extension} other {# extensions}}?",
  833 + "device-name-expression": "expression du nom du dispositif",
  834 + "device-name-filter": "Filtre de nom de dispositif",
  835 + "device-type-expression": "expression de type de dispositif",
  836 + "disconnect-requests": "Demandes de déconnection",
  837 + "drop-file": "Déposez un fichier ou cliquez pour sélectionner un fichier à télécharger.",
  838 + "edit": "Modifier l'extension",
  839 + "export-extension": "Exporter l'extension",
  840 + "export-extensions-configuration": "Exporter la configuration des extensions",
  841 + "extension-id": "Id de l'extension",
  842 + "extension-type": "Type d'extension",
  843 + "extensions": "Extensions",
  844 + "field-required": "Le champ est obligatoire",
  845 + "file": "Fichier d'extensions",
  846 + "filter-expression": "Expression du filtre",
  847 + "host": "Hôte",
  848 + "id": "Id",
  849 + "import-extension": "Importer une extension",
  850 + "import-extensions": "Importer des extensions",
  851 + "import-extensions-configuration": "Importer la configuration des extensions",
  852 + "invalid-file-error": "Fichier d'extension non valide",
  853 + "json-name-expression": "Expression json du nom du dispositif",
  854 + "json-parse": "Impossible d'analyser json transformer.",
  855 + "json-required": "Transformer json est requis.",
  856 + "json-type-expression": "Expression json du type de dispositif",
  857 + "key": "Clé",
  858 + "mapping": "Mappage",
  859 + "method-filter": "Filtre de méthode",
  860 + "modbus-add-server": "Ajouter serveur/esclave",
  861 + "modbus-add-server-prompt": "Veuillez ajouter serveur/esclave",
  862 + "modbus-attributes-poll-period": "Période d'interrogation des attributs (ms)",
  863 + "modbus-baudrate": "Débit en bauds",
  864 + "modbus-byte-order": "Ordre des octets",
  865 + "modbus-databits": "Bits de données",
  866 + "modbus-databits-range": "Les bits de données doivent être compris entre 7 et 8.",
  867 + "modbus-device-name": "Nom du dispositif",
  868 + "modbus-encoding": "Encodage",
  869 + "modbus-function": "Fonction",
  870 + "modbus-parity": "parité",
  871 + "modbus-poll-period": "Période d'interrogation (ms)",
  872 + "modbus-poll-period-range": "La période d'interrogation doit être une valeur positive.",
  873 + "modbus-port-name": "Nom du port série",
  874 + "modbus-register-address": "Adresse du registre",
  875 + "modbus-register-address-range": "L'adresse du registre doit être comprise entre 0 et 65535.",
  876 + "modbus-register-bit-index": "Bit index",
  877 + "modbus-register-bit-index-range": "L'index de bit doit être compris entre 0 et 15.",
  878 + "modbus-register-count": "Nombre de registre",
  879 + "modbus-register-count-range": "Le nombre de registres doit être une valeur positive.",
  880 + "modbus-server": "Serveurs / esclaves",
  881 + "modbus-stopbits": "Bits d'arrêt",
  882 + "modbus-stopbits-range": "Les bits d'arrêt doivent être compris entre 1 et 2.",
  883 + "modbus-tag": "Tag",
  884 + "modbus-timeseries-poll-period": "Période d'interrogation des Timeseries (ms)",
  885 + "modbus-transport": "Transport",
  886 + "modbus-unit-id": "Id de l'unité",
  887 + "modbus-unit-id-range": "L'ID de l'unité doit être compris entre 1 et 247.",
  888 + "no-file": "Aucun fichier sélectionné.",
  889 + "opc-add-server": "Ajouter un serveur",
  890 + "opc-add-server-prompt": "Veuillez ajouter un serveur",
  891 + "opc-application-name": "Nom de l'application",
  892 + "opc-application-uri": "Uri de l'application",
  893 + "opc-device-name-pattern": "modèle de nom du dispositif",
  894 + "opc-device-node-pattern": "modèle de noeud de dispositif",
  895 + "opc-identity": "Identité",
  896 + "opc-keystore": "Magasin de clés",
  897 + "opc-keystore-alias": "Alias",
  898 + "opc-keystore-key-password": "Mot de passe de la clé",
  899 + "opc-keystore-location": "Emplacement *",
  900 + "opc-keystore-password": "Mot de passe",
  901 + "opc-keystore-type": "Type",
  902 + "opc-scan-period-in-seconds": "Période d'analyse en secondes",
  903 + "opc-security": "Sécurité",
  904 + "opc-server": "Serveurs",
  905 + "opc-type": "Type",
  906 + "password": "Mot de passe",
  907 + "pem": "PEM",
  908 + "port": "Port",
  909 + "port-range": "Le port doit être compris entre 1 et 65535.",
  910 + "private-key": "Fichier de clé privée *",
  911 + "request-id-expression": "Expression de demande d'id",
  912 + "request-id-json-expression": "Expression json de la demande d'id",
  913 + "request-id-topic-expression": "Expression de la demande d'id du topic",
  914 + "request-topic-expression": "Expression de la demande du topic",
  915 + "response-timeout": "Délai de réponse en millisecondes",
  916 + "response-topic-expression": "Expression du topic de la réponse",
  917 + "retry-interval": "Intervalle de nouvelle tentative en millisecondes",
  918 + "selected-extensions": "{count, plural, 1 {1 extension} other {# extensions}} sélectionné",
  919 + "server-side-rpc": "RPC côté serveur",
  920 + "ssl": "Ssl",
  921 + "sync":{
  922 + "last-sync-time": "Dernière heure de synchronisation",
  923 + "not-available": "Non disponible",
  924 + "not-sync": "Non sync",
  925 + "status": "Status",
  926 + "sync": "Sync"
  927 + },
  928 + "timeout": "Délai d'attente en millisecondes",
  929 + "timeseries": "Timeseries",
  930 + "to-double": "To Double",
  931 + "token": "Jeton de sécurité",
  932 + "topic": "Topic",
  933 + "topic-expression": "Expression du topic",
  934 + "topic-filter": "Filtre du topic",
  935 + "topic-name-expression": "Expression du nom du dispositif (topic)",
  936 + "topic-type-expression": "Expression de type de dispositif (topic)",
  937 + "transformer": "Transformer",
  938 + "transformer-json": "JSON *",
  939 + "type": "Type",
  940 + "unique-id-required": "L'identifiant d'extension actuel existe déjà.",
  941 + "username": "Nom d'utilisateur",
  942 + "value": "Valeur",
  943 + "value-expression": "Expression de la valeur"
  944 + },
  945 +"fullscreen":{
  946 + "exit": "Quitter le plein écran",
  947 + "expand": "Afficher en plein écran",
  948 + "fullscreen": "Plein écran",
  949 + "toggle": "Activer le mode plein écran"
  950 + },
  951 +"function":{
  952 + "function": "Fonction"
  953 + },
  954 +"grid":{
  955 + "add-item-text": "Ajouter un nouvel élément",
  956 + "delete-item": "Supprimer l'élément",
  957 + "delete-item-text": "Faites attention, après la confirmation, cet élément et toutes les données associées deviendront irrécupérables.",
  958 + "delete-item-title": "Êtes-vous sûr de vouloir supprimer cet élément?",
  959 + "delete-items": "Supprimer les éléments",
  960 + "delete-items-action-title": "Supprimer {count, plural, 1 {1 élément} other {# éléments}}",
  961 + "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.",
  962 + "delete-items-title": "Etes-vous sûr de vouloir supprimer {count, plural, 1 {1 élément} other {# éléments}}?",
  963 + "item-details": "Détails de l'élément",
  964 + "no-items-text": "Aucun élément trouvé",
  965 + "scroll-to-top": "Défiler vers le haut"
  966 + },
  967 +"help":{
  968 + "goto-help-page": "Aller à la page d'aide"
  969 + },
  970 +"home":{
  971 + "avatar": "Avatar",
  972 + "home": "Accueil",
  973 + "logout": "Déconnexion",
  974 + "menu": "Menu",
  975 + "open-user-menu": "Ouvrir le menu utilisateur",
  976 + "profile": "Profile"
  977 + },
  978 +"icon":{
  979 + "icon": "Icône",
  980 + "material-icons": "Material icons",
  981 + "select-icon": "Sélectionner l'icône",
  982 + "show-all": "Afficher toutes les icônes"
  983 + },
  984 +"import":{
  985 + "drop-file": "Déposez un fichier JSON ou cliquez pour sélectionner un fichier à télécharger.",
  986 + "no-file": "Aucun fichier sélectionné"
  987 + },
  988 +"item":{
  989 + "selected": "Sélectionné"
  990 + },
  991 +"js-func":{
  992 + "no-return-error": "La fonction doit renvoyer une valeur!",
  993 + "return-type-mismatch": "La fonction doit renvoyer une valeur de type '{{type}}' !",
  994 + "tidy": "Tidy"
  995 + },
  996 +"key-val":{
  997 + "add-entry": "Ajouter une entrée",
  998 + "key": "Clé",
  999 + "no-data": "Aucune entrée",
  1000 + "remove-entry": "Supprimer l'entrée",
  1001 + "value": "Valeur"
  1002 + },
  1003 +"language":{
  1004 + "language": "Language",
  1005 + "locales":{
  1006 + "en_US": "Anglais",
  1007 + "fr_FR": "Français",
  1008 + "es_ES": "Espagnol",
  1009 + "it_IT": "Italien",
  1010 + "ko_KR": "Coréen",
  1011 + "ru_RU": "Russe",
  1012 + "zh_CN": "Chinois"
  1013 + }
  1014 + },
  1015 +"layout":{
  1016 + "color": "Couleur",
  1017 + "layout": "Mise en page",
  1018 + "main": "Principal",
  1019 + "manage": "Gérer les mises en page",
  1020 + "right": "Droite",
  1021 + "select": "Sélectionner la mise en page cible",
  1022 + "settings": "Paramètres de mise en page"
  1023 + },
  1024 +"legend":{
  1025 + "avg": "avg",
  1026 + "max": "max",
  1027 + "min": "min",
  1028 + "position": "Position de la légende",
  1029 + "settings": "Paramètres de la légende",
  1030 + "show-avg": "Afficher la valeur moyenne",
  1031 + "show-max": "Afficher la valeur maximale",
  1032 + "show-min": "Afficher la valeur min",
  1033 + "show-total": "Afficher la valeur totale",
  1034 + "total": "total"
  1035 + },
  1036 +"login":{
  1037 + "create-password": "Créer un mot de passe",
  1038 + "email": "Email",
  1039 + "forgot-password": "Mot de passe oublié?",
  1040 + "login": "Login",
  1041 + "new-password": "Nouveau mot de passe",
  1042 + "new-password-again": "nouveau mot de passe",
  1043 + "password-again": "Mot de passe à nouveau",
  1044 + "password-link-sent-message": "Le lien de réinitialisation du mot de passe a été envoyé avec succès!",
  1045 + "password-reset": "Mot de passe réinitialisé",
  1046 + "passwords-mismatch-error": "Les mots de passe saisis doivent être identiques!",
  1047 + "remember-me": "Se souvenir de moi",
  1048 + "request-password-reset": "Demander la réinitialisation du mot de passe",
  1049 + "reset-password": "Réinitialiser le mot de passe",
  1050 + "sign-in": "Veuillez vous connecter",
  1051 + "username": "Nom d'utilisateur (email)"
  1052 + },
  1053 +"position":{
  1054 + "bottom": "Bas",
  1055 + "left": "Gauche",
  1056 + "right": "Droite",
  1057 + "top": "Haut"
  1058 + },
  1059 +"profile":{
  1060 + "change-password": "Modifier le mot de passe",
  1061 + "current-password": "Mot de passe actuel",
  1062 + "profile": "Profile"
  1063 + },
  1064 +"relation":{
  1065 + "add": "Ajouter une relation",
  1066 + "add-relation-filter": "Ajouter un filtre de relation",
  1067 + "additional-info": "Informations supplémentaires (JSON)",
  1068 + "any-relation": "toute relation",
  1069 + "any-relation-type": "N'importe quel type",
  1070 + "delete": "Supprimer la relation",
  1071 + "delete-from-relation-text": "Attention, après la confirmation, l'entité actuelle ne sera pas liée à l'entité '{{entityName}}'.",
  1072 + "delete-from-relation-title": "Etes-vous sûr de vouloir supprimer la relation de l'entité '{{entityName}}'?",
  1073 + "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.",
  1074 + "delete-from-relations-title": "Êtes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?",
  1075 + "delete-to-relation-text": "Attention, après la confirmation, l'entité '{{entityName}} ne sera plus liée à l'entité actuelle.",
  1076 + "delete-to-relation-title": "Êtes-vous sûr de vouloir supprimer la relation avec l'entité '{{entityName}}'?",
  1077 + "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.",
  1078 + "delete-to-relations-title": "Etes-vous sûr de vouloir supprimer {count, plural, 1 {1 relation} other {# relations}}?",
  1079 + "direction": "Sens",
  1080 + "direction-type":{
  1081 + "FROM": "de",
  1082 + "TO": "à"
  1083 + },
  1084 + "edit": "Modifier la relation",
  1085 + "from-entity": "De l'entité",
  1086 + "from-entity-name": "Du nom d'entité",
  1087 + "from-entity-type": "Du type d'entité",
  1088 + "from-relations": "Relations sortantes",
  1089 + "invalid-additional-info": "Impossible d'analyser les informations supplémentaires json.",
  1090 + "relation-filters": "Filtres de relation",
  1091 + "relation-type": "Type de relation",
  1092 + "relation-type-required": "Le type de relation est requis.",
  1093 + "relations": "Relations",
  1094 + "remove-relation-filter": "Supprimer le filtre de relation",
  1095 + "search-direction":{
  1096 + "FROM": "De",
  1097 + "TO": "À"
  1098 + },
  1099 + "selected-relations": "{count, plural, 1 {1 relation} other {# relations}} sélectionné",
  1100 + "to-entity": "À l'entité",
  1101 + "to-entity-name": "vers le nom de l'entité",
  1102 + "to-entity-type": "Vers le type d'entité",
  1103 + "to-relations": "Relations entrantes",
  1104 + "type": "Type"
  1105 + },
  1106 +"rulechain":{
  1107 + "add": "Ajouter une chaîne de règles",
  1108 + "add-rulechain-text": "Ajouter une nouvelle chaîne de règles",
  1109 + "copyId": "Copier l'identifiant de la chaîne de règles",
  1110 + "create-new-rulechain": "Créer une nouvelle chaîne de règles",
  1111 + "debug-mode": "Mode de débogage",
  1112 + "delete": "Supprimer la chaîne de règles",
  1113 + "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.",
  1114 + "delete-rulechain-title": "Voulez-vous vraiment supprimer la chaîne de règles '{{ruleChainName}}'?",
  1115 + "delete-rulechains-action-title": "Supprimer {count, plural, 1 {1 chaîne de règles} other {# chaînes de règles}}",
  1116 + "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.",
  1117 + "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}}?",
  1118 + "description": "Description",
  1119 + "details": "Détails",
  1120 + "events": "Evénements",
  1121 + "export": "Exporter la chaîne de règles",
  1122 + "export-failed-error": "Impossible d'exporter la chaîne de règles: {{error}}",
  1123 + "idCopiedMessage": "L'ID de la chaîne de règles a été copié dans le presse-papier",
  1124 + "import": "Importer la chaîne de règles",
  1125 + "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",
  1126 + "management": "Gestion des règles",
  1127 + "name": "Nom",
  1128 + "name-required": "Le nom est requis.",
  1129 + "no-rulechains-matching": "Aucune chaîne de règles correspondant à {{entity}} n'a été trouvée.",
  1130 + "no-rulechains-text": "Aucune chaîne de règles trouvée",
  1131 + "root": "Racine",
  1132 + "rulechain": "Chaîne de règles",
  1133 + "rulechain-details": "Détails de la chaîne de règles",
  1134 + "rulechain-file": "Fichier de chaîne de règles",
  1135 + "rulechain-required": "Chaîne de règles requise",
  1136 + "rulechains": "Chaînes de règles",
  1137 + "select-rulechain": "Sélectionner la chaîne de règles",
  1138 + "set-root": "Rend la chaîne de règles racine (root) ",
  1139 + "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.",
  1140 + "set-root-rulechain-title": "Voulez-vous vraiment que la chaîne de règles '{{ruleChainName}} soit racine (root) ?",
  1141 + "system": "Système"
  1142 + },
  1143 +"rulenode":{
  1144 + "add": "Ajouter un noeud de règle",
  1145 + "add-link": "Ajouter un lien",
  1146 + "configuration": "Configuration",
  1147 + "copy-selected": "Copier les éléments sélectionnés",
  1148 + "create-new-link-label": "Créez un nouveau!",
  1149 + "custom-link-label": "Etiquette de lien personnalisée",
  1150 + "custom-link-label-required": "Une étiquette de lien personnalisée est requise",
  1151 + "debug-mode": "Mode de débogage",
  1152 + "delete": "Supprimer le noeud de règle",
  1153 + "delete-selected": "Supprimer les éléments sélectionnés",
  1154 + "delete-selected-objects": "Supprimer les nœuds et les connexions sélectionnés",
  1155 + "description": "Description",
  1156 + "deselect-all": "Désélectionner tout",
  1157 + "deselect-all-objects": "Désélectionnez tous les nœuds et toutes les connexions",
  1158 + "details": "Détails",
  1159 + "directive-is-not-loaded": "La directive de configuration définie '{{directiveName}} n'est pas disponible.",
  1160 + "events": "Événements",
  1161 + "help": "Aide",
  1162 + "invalid-target-rulechain": "Impossible de résoudre la chaîne de règles cible!",
  1163 + "link": "Lien",
  1164 + "link-details": "Détails du lien du noeud de la règle",
  1165 + "link-label": "Étiquette du lien",
  1166 + "link-label-required": "L'étiquette du lien est obligatoire",
  1167 + "link-labels": "Étiquettes de lien",
  1168 + "link-labels-required": "Les étiquettes de lien sont obligatoires",
  1169 + "message": "Message",
  1170 + "message-type": "Type de message",
  1171 + "message-type-required": "Le type de message est obligatoire",
  1172 + "metadata": "Métadonnées",
  1173 + "metadata-required": "Les entrées de métadonnées ne peuvent pas être vides.",
  1174 + "name": "Nom",
  1175 + "name-required": "Le nom est requis.",
  1176 + "no-link-label-matching": "'{{label}}' introuvable.",
  1177 + "no-link-labels-found": "Aucune étiquette de lien trouvée",
  1178 + "open-node-library": "Ouvrir la bibliothèque de noeud",
  1179 + "output": "Output",
  1180 + "rulenode-details": "Détails du noeud de la règle",
  1181 + "search": "Recherche de noeuds",
  1182 + "select-all": "Tout sélectionner",
  1183 + "select-all-objects": "Sélectionnez tous les noeuds et connexions",
  1184 + "select-message-type": "Sélectionner le type de message",
  1185 + "test": "Test",
  1186 + "test-script-function": "Tester le script",
  1187 + "type": "Type",
  1188 + "type-action": "Action",
  1189 + "type-action-details": "Effectuer une action spéciale",
  1190 + "type-enrichment": "Enrichissement",
  1191 + "type-enrichment-details": "Ajouter des informations supplémentaires dans les métadonnées de message",
  1192 + "type-external": "Externe",
  1193 + "type-external-details": "Interagit avec le système externe",
  1194 + "type-filter": "Filtre",
  1195 + "type-filter-details": "Filtrer les messages entrants avec des conditions configurées",
  1196 + "type-input": "Input",
  1197 + "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é",
  1198 + "type-rule-chain": "Chaîne de règles",
  1199 + "type-rule-chain-details": "Transmet les messages entrants à la chaîne de règles spécifiée",
  1200 + "type-transformation": "Transformation",
  1201 + "type-transformation-details": "Modifier le payload du message et les métadonnées ",
  1202 + "type-unknown": "Inconnu",
  1203 + "type-unknown-details": "Noeud de règle non résolu",
  1204 + "ui-resources-load-error": "Impossible de charger les ressources de configuration de l'interface utilisateur."
  1205 + },
  1206 +"tenant":{
  1207 + "add": "Ajouter un Tenant",
  1208 + "add-tenant-text": "Ajouter un nouveau Tenant",
  1209 + "admins": "Admins",
  1210 + "copyId": "Copier l'Id du Tenant",
  1211 + "delete": "Supprimer le Tenant",
  1212 + "delete-tenant-text": "Attention, après la confirmation, le Tenant et toutes les données associées deviendront irrécupérables.",
  1213 + "delete-tenant-title": "Etes-vous sûr de vouloir supprimer le tenant '{{tenantTitle}}'?",
  1214 + "delete-tenants-action-title": "Supprimer {count, plural, 1 {1 tenant} other {# tenants}}",
  1215 + "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.",
  1216 + "delete-tenants-title": "Etes-vous sûr de vouloir supprimer {count, plural, 1 {1 tenant} other {# tenants}}?",
  1217 + "description": "Description",
  1218 + "details": "Détails",
  1219 + "events": "Événements",
  1220 + "idCopiedMessage": "L'Id du Tenant a été copié dans le Presse-papiers",
  1221 + "manage-tenant-admins": "Gérer les administrateurs du Tenant",
  1222 + "management": "Gestion des Tenants",
  1223 + "no-tenants-matching": "Aucun Tenant correspondant à {{entity}} n'a été trouvé. ",
  1224 + "no-tenants-text": "Aucun Tenant trouvé",
  1225 + "select-tenant": "Sélectionner un Tenant",
  1226 + "tenant": "Tenant",
  1227 + "tenant-details": "Détails du Tenant",
  1228 + "tenant-required": "Tenant requis",
  1229 + "tenants": "Tenants",
  1230 + "title": "Titre",
  1231 + "title-required": "Le titre est requis."
  1232 + },
  1233 +"timeinterval":{
  1234 + "advanced": "Avancé",
  1235 + "days": "Jours",
  1236 + "days-interval": "{days, plural, 1 {1 jour} other {# jours}}",
  1237 + "hours": "Heures",
  1238 + "hours-interval": "{hours, plural, 1 {1 heure} other {# heures}}",
  1239 + "minutes": "Minutes",
  1240 + "minutes-interval": "{minutes, plural, 1 {1 minute} other {# minutes}}",
  1241 + "seconds": "Secondes",
  1242 + "seconds-interval": "{seconds, plural, 1 {1 seconde} other {# secondes}}"
  1243 + },
  1244 +"timewindow":{
  1245 + "date-range": "Plage de dates",
  1246 + "days": "{days, plural, 1 {jour} other {# jours}}",
  1247 + "edit": "Modifier timewindow",
  1248 + "history": "Historique",
  1249 + "hours": "{hours, plural, 0 {heure} 1 {1 heure} other {# heures}}",
  1250 + "last": "Dernier",
  1251 + "last-prefix": "dernier",
  1252 + "minutes": "{minutes, plural, 0 {minute} 1 {1 minute} other {# minutes}}",
  1253 + "period": "de {{startTime}} à {{endTime}}",
  1254 + "realtime": "Temps réel",
  1255 + "seconds": "{seconds, plural, 0 {second} 1 {1 second} other {# seconds}}",
  1256 + "time-period": "Période"
  1257 + },
  1258 +"user":{
  1259 + "activation-email-sent-message": "L'e-mail d'activation a été envoyé avec succès!",
  1260 + "activation-link": "Lien d'activation utilisateur",
  1261 + "activation-link-copied-message": "le lien d'activation de l'utilisateur a été copié dans le presse-papier",
  1262 + "activation-link-text": "Pour activer l'utilisateur, utilisez le lien d'activation suivant: <a href='{{activationLink}}' target='_blank'></a>",
  1263 + "activation-method": "Méthode d'activation",
  1264 + "add": "Ajouter un utilisateur",
  1265 + "add-user-text": "Ajouter un nouvel utilisateur",
  1266 + "always-fullscreen": "Toujours en plein écran",
  1267 + "anonymous": "Anonyme",
  1268 + "copy-activation-link": "Copier le lien d'activation",
  1269 + "customer": "Client",
  1270 + "customer-users": "Utilisateurs du client",
  1271 + "default-dashboard": "Tableau de bord par défaut",
  1272 + "delete": "Supprimer l'utilisateur",
  1273 + "delete-user-text": "Attention, après la confirmation, l'utilisateur et toutes les données associées deviendront irrécupérables.",
  1274 + "delete-user-title": "Etes-vous sûr de vouloir supprimer l'utilisateur '{{userEmail}}'?",
  1275 + "delete-users-action-title": "Supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}",
  1276 + "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.",
  1277 + "delete-users-title": "Etes-vous sûr de vouloir supprimer {count, plural, 1 {1 utilisateur} other {# utilisateurs}}?",
  1278 + "description": "Description",
  1279 + "details": "Détails",
  1280 + "display-activation-link": "Afficher le lien d'activation",
  1281 + "email": "Email",
  1282 + "email-required": "Email est requis.",
  1283 + "first-name": "Prénom",
  1284 + "invalid-email-format": "Format de courrier électronique non valide",
  1285 + "last-name": "Nom de famille",
  1286 + "no-users-matching": "Aucun utilisateur correspondant à '{{entity}}' n'a été trouvé.",
  1287 + "no-users-text": "Aucun utilisateur trouvé",
  1288 + "resend-activation": "Renvoyer l'activation",
  1289 + "select-user": "Sélectionner l'utilisateur",
  1290 + "send-activation-mail": "Envoyer un mail d'activation",
  1291 + "sys-admin": "Administrateur du système",
  1292 + "tenant-admin": "Administrateur du Tenant",
  1293 + "tenant-admins": "administrateurs du Tenant",
  1294 + "user": "utilisateur",
  1295 + "user-details": "Détails de l'utilisateur",
  1296 + "user-required": "L'utilisateur est requis",
  1297 + "users": "Utilisateurs"
  1298 + },
  1299 +"value":{
  1300 + "boolean": "booléen",
  1301 + "boolean-value": "Valeur booléenne",
  1302 + "double": "Double",
  1303 + "double-value": "Valeur double",
  1304 + "false": "Faux",
  1305 + "integer": "Entier",
  1306 + "integer-value": "Valeur entière",
  1307 + "invalid-integer-value": "Valeur entière invalide",
  1308 + "long": "Long",
  1309 + "string": "String",
  1310 + "string-value": "Valeur String",
  1311 + "true": "Vrai",
  1312 + "type": "Type de valeur"
  1313 + },
  1314 +"widget":{
  1315 + "add": "Ajouter un widget",
  1316 + "add-resource": "Ajouter une ressource",
  1317 + "add-widget-type": "Ajouter un nouveau type de widget",
  1318 + "alarm": "Widget d'alarme",
  1319 + "css": "CSS",
  1320 + "datakey-settings-schema": "Schéma des paramètres de Data key",
  1321 + "edit": "Modifier le widget",
  1322 + "editor": " Editeur de widget",
  1323 + "export": "Exporter widget",
  1324 + "html": "HTML",
  1325 + "javascript": "Javascript",
  1326 + "latest-values": "Dernières valeurs",
  1327 + "management": "Gestion des widgets",
  1328 + "missing-widget-title-error": "Le titre du widget doit être spécifié!",
  1329 + "no-data-found": "Aucune donnée trouvée",
  1330 + "remove": "Supprimer le widget",
  1331 + "remove-resource": "Supprimer une ressource",
  1332 + "remove-widget-text": "Après la confirmation, le widget et toutes les données associées deviendront irrécupérables.",
  1333 + "remove-widget-title": "Êtes-vous sûr de vouloir supprimer le widget '{{widgetTitle}}'?",
  1334 + "remove-widget-type": "Supprimer le type de widget",
  1335 + "remove-widget-type-text": "Après la confirmation, le type de widget et toutes les données associées deviendront irrécupérables.",
  1336 + "remove-widget-type-title": "Êtes-vous sûr de vouloir supprimer le type de widget '{{widgetName}}'?",
  1337 + "resource-url": "URL JavaScript / CSS",
  1338 + "resources": "Ressources",
  1339 + "rpc": "Widget de contrôle",
  1340 + "run": "Exécuter un widget",
  1341 + "save": "Enregistrer le widget",
  1342 + "save-widget-type-as": "Enregistrer le type de widget sous",
  1343 + "save-widget-type-as-text": "Veuillez saisir un nouveau titre de widget et / ou sélectionner un ensemble de widgets cibles",
  1344 + "saveAs": "Enregistrer le widget sous",
  1345 + "search-data": "Rechercher des données",
  1346 + "select-widget-type": "Sélectionnez le type de widget",
  1347 + "select-widgets-bundle": "Sélectionner un ensemble de widgets",
  1348 + "settings-schema": "Schéma des paramètres",
  1349 + "static": "Widget statique",
  1350 + "tidy": "Tidy",
  1351 + "timeseries": "Séries chronologiques",
  1352 + "title": "Titre du widget",
  1353 + "title-required": "Le titre du widget est requis.",
  1354 + "toggle-fullscreen": "Basculer le mode plein écran",
  1355 + "type": "Type de widget",
  1356 + "unable-to-save-widget-error": "Impossible de sauvegarder le widget! Le widget a des erreurs!",
  1357 + "undo": "Annuler les modifications du widget",
  1358 + "widget-bundle": "Ensemble de widget",
  1359 + "widget-library": "Bibliothèque de widgets",
  1360 + "widget-saved": "Widget enregistré",
  1361 + "widget-template-load-failed-error": "Impossible de charger le modèle de widget!",
  1362 + "widget-type-load-error": "Le widget n'a pas été chargé à cause des erreurs suivantes:",
  1363 + "widget-type-load-failed-error": "Impossible de charger le type de widget!",
  1364 + "widget-type-not-found": "Problème de chargement de la configuration du widget. <br> Le type de widget associé a probablement été supprimé."
  1365 + },
  1366 +"widget-action":{
  1367 + "custom": "Action personnalisée",
  1368 + "header-button": "Bouton d'en-tête de widget",
  1369 + "open-dashboard": "Naviguer vers un autre tableau de bord",
  1370 + "open-dashboard-state": "Naviguer vers un nouvel état du tableau de bord",
  1371 + "open-right-layout": "Ouvrir la disposition du tableau de bord droite (vue mobile)",
  1372 + "set-entity-from-widget": "Définir l'entité à partir du widget",
  1373 + "target-dashboard": "Tableau de bord cible",
  1374 + "target-dashboard-state": "Etat du tableau de bord cible",
  1375 + "target-dashboard-state-required": "L'état du tableau de bord cible est requis",
  1376 + "update-dashboard-state": "Mettre à jour l'état actuel du tableau de bord"
  1377 + },
  1378 +"widget-config":{
  1379 + "action": "Action",
  1380 + "action-icon": "Icône",
  1381 + "action-name": "Nom",
  1382 + "action-name-not-unique": "Une autre action portant le même nom existe déjà. <br/> Le nom de l'action doit être unique dans la même source d'action.",
  1383 + "action-name-required": "Le nom de l'action est requis",
  1384 + "action-source": "Source de l'action",
  1385 + "action-source-required": "Une source d'action est requise.",
  1386 + "action-type": "Type",
  1387 + "action-type-required": "Le type d'action est requis.",
  1388 + "actions": "Actions",
  1389 + "add-action": "Ajouter une action",
  1390 + "add-datasource": "Ajouter une source de données",
  1391 + "advanced": "Avancé",
  1392 + "alarm-source": "Source d'alarme",
  1393 + "background-color": "couleur de fond",
  1394 + "data": "Données",
  1395 + "datasource-parameters": "Paramètres",
  1396 + "datasource-type": "Type",
  1397 + "datasources": "Sources de données",
  1398 + "decimals": "Nombre de chiffres après virgule flottante",
  1399 + "delete-action": "Supprimer l'action",
  1400 + "delete-action-text": "Etes-vous sûr de vouloir supprimer l'action du widget nommé '{{actionName}}'?",
  1401 + "delete-action-title": "Supprimer l'action du widget",
  1402 + "display-legend": "Afficher la légende",
  1403 + "display-title": "Afficher le titre",
  1404 + "drop-shadow": "Ombre portée",
  1405 + "edit-action": "Modifier l'action",
  1406 + "enable-fullscreen": "Activer le plein écran",
  1407 + "general-settings": "Paramètres généraux",
  1408 + "height": "Hauteur",
  1409 + "margin": "Marge",
  1410 + "maximum-datasources": "Maximum {count, plural, 1 {1 datasource est autorisé.} other {# datasources sont autorisés}}",
  1411 + "mobile-mode-settings": "Paramètres du mode mobile",
  1412 + "order": "Ordre",
  1413 + "padding": "Padding",
  1414 + "remove-datasource": "Supprimer la source de données",
  1415 + "search-actions": "Recherche d'actions",
  1416 + "settings": "Paramètres",
  1417 + "target-device": "Dispositif cible",
  1418 + "text-color": "Couleur du texte",
  1419 + "timewindow": "Fenêtre de temps",
  1420 + "title": "Titre",
  1421 + "title-style": "Style de titre",
  1422 + "units": "Symbole spécial à afficher à côté de la valeur",
  1423 + "use-dashboard-timewindow": "Utiliser la fenêtre de temps du tableau de bord",
  1424 + "widget-style": "Style du widget"
  1425 + },
  1426 +"widget-type":{
  1427 + "create-new-widget-type": "Créer un nouveau type de widget",
  1428 + "export": "Exporter le type de widget",
  1429 + "export-failed-error": "Impossible d'exporter le type de widget: {{error}}",
  1430 + "import": "Importer le type de widget",
  1431 + "invalid-widget-type-file-error": "Impossible d'importer le type de widget: structure de données de type widget invalide.",
  1432 + "widget-type-file": "Fichier de type Widget"
  1433 + },
  1434 +"widgets-bundle":{
  1435 + "add": "Ajouter un groupe de widgets",
  1436 + "add-widgets-bundle-text": "Ajouter un nouveau groupe de widgets",
  1437 + "create-new-widgets-bundle": "Créer un nouveau groupe de widgets",
  1438 + "current": "Groupe actuel",
  1439 + "delete": "Supprimer le groupe de widgets",
  1440 + "delete-widgets-bundle-text": "Attention, après la confirmation, le groupe de widgets et toutes les données associées deviendront irrécupérables.",
  1441 + "delete-widgets-bundle-title": "Êtes-vous sûr de vouloir supprimer le groupe de widgets '{{widgetsBundleTitle}}'?",
  1442 + "delete-widgets-bundles-action-title": "Supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}",
  1443 + "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.",
  1444 + "delete-widgets-bundles-title": "Voulez-vous vraiment supprimer {count, plural, 1 {1 groupe de widgets} other {# groupes de widgets}}?",
  1445 + "details": "Détails",
  1446 + "empty": "Le groupe de widgets est vide",
  1447 + "export": "Exporter le groupe de widgets",
  1448 + "export-failed-error": "Impossible d'exporter le groupe de widgets: {{error}}",
  1449 + "import": "Importer un groupe de widgets",
  1450 + "invalid-widgets-bundle-file-error": "Impossible d'importer un groupe de widgets: structure de données du groupe de widgets non valides.",
  1451 + "no-widgets-bundles-matching": "Aucun groupe de widgets correspondant à {{widgetsBundle}} n'a été trouvé.",
  1452 + "no-widgets-bundles-text": "Aucun groupe de widgets trouvé",
  1453 + "system": "Système",
  1454 + "title": "Titre",
  1455 + "title-required": "Le titre est requis.",
  1456 + "widgets-bundle-details": "Détails des groupes de widgets",
  1457 + "widgets-bundle-file": "Fichier de groupe de widgets",
  1458 + "widgets-bundle-required": "Un groupe de widgets est requis.",
  1459 + "widgets-bundles": "Groupes de widgets"
  1460 + }
  1461 +}
... ...
... ... @@ -30,8 +30,8 @@
30 30 "apply": "Applica",
31 31 "apply-changes": "Applica modifiche",
32 32 "edit-mode": "Modalità modifica",
33   - "enter-edit-mode": "Attiva la modalità di modifica",
34   - "decline-changes": "Annulla le modifiche",
  33 + "enter-edit-mode": "Attiva modalità di modifica",
  34 + "decline-changes": "Annulla modifiche",
35 35 "close": "Chiudi",
36 36 "back": "Indietro",
37 37 "run": "Esegui",
... ... @@ -108,7 +108,7 @@
108 108 "no-alarms-prompt": "Nessun allarme trovato",
109 109 "created-time": "Orario di creazione",
110 110 "type": "Tipo",
111   - "severity": "Gravità",
  111 + "severity": "Livello di gravità",
112 112 "originator": "Origine",
113 113 "originator-type": "Tipo origine",
114 114 "details": "Dettagli",
... ... @@ -125,7 +125,7 @@
125 125 "severity-indeterminate": "Indeterminato",
126 126 "acknowledge": "Conferma",
127 127 "clear": "Cancella",
128   - "search": "Ricerca allarmi",
  128 + "search": "Cerca allarmi",
129 129 "selected-alarms": "{ count, plural, 1 {1 allarme selezionato} other {# allarmi selezionati} }",
130 130 "no-data": "Nessun dato da visualizzare",
131 131 "polling-interval": "Intervallo di polling (sec) Allarmi",
... ... @@ -267,7 +267,7 @@
267 267 },
268 268 "audit-log": {
269 269 "audit": "Audit",
270   - "audit-logs": "Audit Logs",
  270 + "audit-logs": "Log Audit",
271 271 "timestamp": "Timestamp",
272 272 "entity-type": "Tipo Entità",
273 273 "entity-name": "Nome Entità",
... ... @@ -294,7 +294,7 @@
294 294 "no-audit-logs-prompt": "Log non trovati",
295 295 "action-data": "Action data",
296 296 "failure-details": "Failure details",
297   - "search": "Ricerca log audit",
  297 + "search": "Cerca log audit",
298 298 "clear-search": "Cancella ricerca"
299 299 },
300 300 "confirm-on-exit": {
... ... @@ -319,7 +319,7 @@
319 319 "password": "Password",
320 320 "enter-username": "Inserisci nome utente",
321 321 "enter-password": "Inserisci password",
322   - "enter-search": "Inserisci ricerca"
  322 + "enter-search": "Cerca ..."
323 323 },
324 324 "content-type": {
325 325 "json": "Json",
... ... @@ -391,7 +391,7 @@
391 391 "unassign-from-customer": "Unassign from customer",
392 392 "make-public": "Rendi pubblica la dashboard",
393 393 "make-private": "Rendi privata la dashboard",
394   - "manage-assigned-customers": "Gestisci i clienti assegnati",
  394 + "manage-assigned-customers": "Gestisci clienti assegnati",
395 395 "assigned-customers": "Clienti assegnati",
396 396 "assign-to-customers": "Assegna Dashboard ai Clienti",
397 397 "assign-to-customers-text": "Seleziona i clienti da assegnare alla/alle dashboard",
... ... @@ -407,7 +407,7 @@
407 407 "title-required": "Titolo obbligatorio.",
408 408 "description": "Descrizione",
409 409 "details": "Dettagli",
410   - "dashboard-details": "Dettagli Dashboard",
  410 + "dashboard-details": "Dettagli dashboard",
411 411 "add-dashboard-text": "Aggiungi nuova dashboard",
412 412 "assign-dashboards": "Assegna dashboard",
413 413 "assign-new-dashboard": "Assegna nuova dashboard",
... ... @@ -472,7 +472,7 @@
472 472 "title-color": "Colore titolo",
473 473 "display-dashboards-selection": "Mostra selezione dashboard",
474 474 "display-entities-selection": "Mostra selezione entità",
475   - "display-dashboard-timewindow": "Mostra finestra temporale",
  475 + "display-dashboard-timewindow": "Mostra intervallo temporale",
476 476 "display-dashboard-export": "Mostra esportazione",
477 477 "import": "Importa dashboard",
478 478 "export": "Esporta dashboard",
... ... @@ -498,25 +498,25 @@
498 498 "public-link": "Link pubblico",
499 499 "copy-public-link": "Copia link pubblico",
500 500 "public-link-copied-message": "Link pubblico della dashboard copiato negli appunti",
501   - "manage-states": "Manage dashboard states",
502   - "states": "Dashboard states",
503   - "search-states": "Search dashboard states",
504   - "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard states} } selected",
505   - "edit-state": "Edit dashboard state",
506   - "delete-state": "Delete dashboard state",
507   - "add-state": "Add dashboard state",
508   - "state": "Dashboard state",
  501 + "manage-states": "Gestisci stati dashboard",
  502 + "states": "Stati dashboard",
  503 + "search-states": "Ricerca stati dashboard",
  504 + "selected-states": "{ count, plural, 1 {1 stato dashboard selezionato} other {# stati dashboard selezionati} }",
  505 + "edit-state": "Modifica stato dashboard",
  506 + "delete-state": "Elimina stato dashboard",
  507 + "add-state": "Aggiungi stato dashboard",
  508 + "state": "Stato dashboard",
509 509 "state-name": "Nome",
510   - "state-name-required": "Dashboard state name is required.",
511   - "state-id": "State Id",
512   - "state-id-required": "Dashboard state id is required.",
513   - "state-id-exists": "Dashboard state with the same id is already exists.",
514   - "is-root-state": "Root state",
515   - "delete-state-title": "Delete dashboard state",
516   - "delete-state-text": "Are you sure you want delete dashboard state with name '{{stateName}}'?",
  510 + "state-name-required": "Nome stato dashboard obbligatorio.",
  511 + "state-id": "Id stato",
  512 + "state-id-required": "Id stato dashboard obbligatorio.",
  513 + "state-id-exists": "Uno stato della dashboard con lo stesso id è già presente.",
  514 + "is-root-state": "Stato radice",
  515 + "delete-state-title": "Elimina stato dashboard",
  516 + "delete-state-text": "Sei sicuro di voler eliminare lo stato della dashboard di nome '{{stateName}}'?",
517 517 "show-details": "Mostra dettagli",
518 518 "hide-details": "Nascondi dettagli",
519   - "select-state": "Select target state",
  519 + "select-state": "Seleziona stato target",
520 520 "state-controller": "Stato controller"
521 521 },
522 522 "datakey": {
... ... @@ -570,14 +570,14 @@
570 570 "alias-required": "Alias dispositivo richesto.",
571 571 "remove-alias": "Rimuovi alias dispositivo",
572 572 "add-alias": "Aggiungi alias dispositivo",
573   - "name-starts-with": "Dispositivo il cui nome comincia per",
  573 + "name-starts-with": "Dispositivo il cui nome inizia per",
574 574 "device-list": "Lista dispositivi",
575 575 "use-device-name-filter": "Usa filtro",
576 576 "device-list-empty": "Nessun dispositivo selezionato.",
577 577 "device-name-filter-required": "Filtro nome dispositivo obbligatorio.",
578 578 "device-name-filter-no-device-matched": "Nessun dispositivo il cui nome inizia per '{{device}}' è stato trovato.",
579 579 "add": "Aggiungi Dispositivo",
580   - "assign-to-customer": "Assigna al cliente",
  580 + "assign-to-customer": "Assegna al cliente",
581 581 "assign-device-to-customer": "Assegna dispositivo/dispositivi al Cliente",
582 582 "assign-device-to-customer-text": "Seleziona i dispositivi da assegnare al cliente",
583 583 "make-public": "Rendi pubblico il dispositivo",
... ... @@ -605,7 +605,7 @@
605 605 "delete-device-text": "Attenzione, dopo la conferma il dispositivo e tutti i suoi dati non saranno più recuperabili.",
606 606 "delete-devices-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 dispositivo} other {# dispositivi} }?",
607 607 "delete-devices-action-title": "Elimina { count, plural, 1 {1 dispositivo} other {# dispositivi} }",
608   - "delete-devices-text": "Attenzione, dopo la conferma tutti i dispositivi selezionati saranno elimininati e i relativi dati non saranno più recuperabili.",
  608 + "delete-devices-text": "Attenzione, dopo la conferma tutti i dispositivi selezionati saranno eliminati e i relativi dati non saranno più recuperabili.",
609 609 "unassign-device-title": "Sei sicuro di voler annullare l'assegnazione del dispositivo '{{deviceName}}'?",
610 610 "unassign-device-text": "Dopo la conferma sarà annullata l'assegnazione del dispositivo e questo non sarà più accessibile dal cliente.",
611 611 "unassign-device": "Annulla assegnazione dispositivo",
... ... @@ -680,7 +680,7 @@
680 680 "entity-list-empty": "Nessuna entità selezionata.",
681 681 "entity-type-list-empty": "Nessun tipo di entità selezionato.",
682 682 "entity-name-filter-required": "Filtro nome entità obbligatorio.",
683   - "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.",
  683 + "entity-name-filter-no-entity-matched": "Nessuna entità che inizia per '{{entity}}' è stata trovata.",
684 684 "all-subtypes": "Tutte",
685 685 "select-entities": "Seleziona entità",
686 686 "no-aliases-found": "Nessun alias trovato.",
... ... @@ -733,7 +733,7 @@
733 733 "type-rulechains": "Rule chains",
734 734 "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }",
735 735 "rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'",
736   - "type-current-customer": "Current Customer",
  736 + "type-current-customer": "Cliente attuale",
737 737 "search": "Ricerca entità",
738 738 "selected-entities": "{ count, plural, 1 {1 entità selezionata} other {# entità selezionate} }",
739 739 "entity-name": "Nome entità",
... ... @@ -788,13 +788,13 @@
788 788 "delete-extension-text": "Attenzione, dopo la conferma l'estensione e tutti i suoi data non saranno più recuperabili.",
789 789 "delete-extensions-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 estensione} other {# estensioni} }?",
790 790 "delete-extensions-text": "Attenzione, dopo la conferma tutte le estensioni selezionate saranno eliminate.",
791   - "converters": "Converters",
792   - "converter-id": "Converter id",
  791 + "converters": "Convertitori",
  792 + "converter-id": "Id convertitore",
793 793 "configuration": "Configurazione",
794   - "converter-configurations": "Converter configurations",
  794 + "converter-configurations": "Configurazioni convertitore",
795 795 "token": "Token di sicurezza",
796   - "add-converter": "Add converter",
797   - "add-config": "Add converter configuration",
  796 + "add-converter": "Aggiungi convertitore",
  797 + "add-config": "Aggiungi configurazione convertitore",
798 798 "device-name-expression": "Device name expression",
799 799 "device-type-expression": "Device type expression",
800 800 "custom": "Custom",
... ... @@ -828,7 +828,7 @@
828 828 "drop-file": "Trascina un file o fai clic per selezionare un file da caricare.",
829 829 "mapping": "Mapping",
830 830 "topic-filter": "Filtro topic",
831   - "converter-type": "Converter type",
  831 + "converter-type": "Tipo convertitore",
832 832 "converter-json": "Json",
833 833 "json-name-expression": "Device name json expression",
834 834 "topic-name-expression": "Device name topic expression",
... ... @@ -847,10 +847,10 @@
847 847 "converter-json-required": "Convertitore json obbligatorio.",
848 848 "converter-json-parse": "Unable to parse converter json.",
849 849 "filter-expression": "Filter expression",
850   - "connect-requests": "Connect requests",
851   - "add-connect-request": "Add connect request",
852   - "disconnect-requests": "Disconnect requests",
853   - "add-disconnect-request": "Add disconnect request",
  850 + "connect-requests": "Richieste di connessione",
  851 + "add-connect-request": "Aggiungi richiesta di connessione",
  852 + "disconnect-requests": "Richieste di disconnessione",
  853 + "add-disconnect-request": "Aggiungi richiesta di disconnessione",
854 854 "attribute-requests": "Attribute requests",
855 855 "add-attribute-request": "Add attribute request",
856 856 "attribute-updates": "Attribute updates",
... ... @@ -919,8 +919,8 @@
919 919 "not-available": "Non disponibile"
920 920 },
921 921
922   - "export-extensions-configuration": "Export extensions configuration",
923   - "import-extensions-configuration": "Import extensions configuration",
  922 + "export-extensions-configuration": "Esporta configurazione estensioni",
  923 + "import-extensions-configuration": "Importa configurazione estensioni",
924 924 "import-extensions": "Importa estensione",
925 925 "import-extension": "Importa estensione",
926 926 "export-extension": "Esporta estensione",
... ... @@ -928,7 +928,7 @@
928 928 "invalid-file-error": "File estensione non valido"
929 929 },
930 930 "fullscreen": {
931   - "expand": "Expand to fullscreen",
  931 + "expand": "Espandi a tutto schermo",
932 932 "exit": "Esci da schermo intero",
933 933 "toggle": "Commuta modalità schermo intero",
934 934 "fullscreen": "Schermo intero"
... ... @@ -937,17 +937,17 @@
937 937 "function": "Funzione"
938 938 },
939 939 "grid": {
940   - "delete-item-title": "Are you sure you want to delete this item?",
941   - "delete-item-text": "Be careful, after the confirmation this item and all related data will become unrecoverable.",
942   - "delete-items-title": "Are you sure you want to delete { count, plural, 1 {1 item} other {# items} }?",
943   - "delete-items-action-title": "Delete { count, plural, 1 {1 item} other {# items} }",
944   - "delete-items-text": "Be careful, after the confirmation all selected items will be removed and all related data will become unrecoverable.",
945   - "add-item-text": "Add new item",
946   - "no-items-text": "No items found",
947   - "item-details": "Item details",
948   - "delete-item": "Delete Item",
949   - "delete-items": "Delete Items",
950   - "scroll-to-top": "Scroll to top"
  940 + "delete-item-title": "Sei sicuro di voler eliminare questo elemento?",
  941 + "delete-item-text": "Attenzione, dopo la conferma questo elemento e tutti i suoi dati non saranno più recuperabili.",
  942 + "delete-items-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 elemento} other {# elementi} }?",
  943 + "delete-items-action-title": "Elimina { count, plural, 1 {1 elemento} other {# elementi} }",
  944 + "delete-items-text": "Attenzione, dopo la conferma tutti gli elementi selezionati saranno rimossi e i relativi dati non saranno più recuperabili.",
  945 + "add-item-text": "Aggiungi nuovo elemento",
  946 + "no-items-text": "Nessun elemento trovato",
  947 + "item-details": "Dettagli elemento",
  948 + "delete-item": "Elimina elemento",
  949 + "delete-items": "Elimina elementi",
  950 + "scroll-to-top": "Scorri verso l'alto"
951 951 },
952 952 "help": {
953 953 "goto-help-page": "Go to help page"
... ... @@ -985,7 +985,7 @@
985 985 "settings": "Impostazioni layout",
986 986 "color": "Colore",
987 987 "main": "Main",
988   - "right": "Right",
  988 + "right": "Destra",
989 989 "select": "Select target layout"
990 990 },
991 991 "legend": {
... ... @@ -1030,7 +1030,7 @@
1030 1030 },
1031 1031 "relation": {
1032 1032 "relations": "Relations",
1033   - "direction": "Direction",
  1033 + "direction": "Direzione",
1034 1034 "search-direction": {
1035 1035 "FROM": "Da",
1036 1036 "TO": "A"
... ... @@ -1072,39 +1072,39 @@
1072 1072 },
1073 1073 "rulechain": {
1074 1074 "rulechain": "Rule chain",
1075   - "rulechains": "Rule chains",
  1075 + "rulechains": "Rule chain",
1076 1076 "root": "Root",
1077   - "delete": "Delete rule chain",
  1077 + "delete": "Cancella rule chain",
1078 1078 "name": "Nome",
1079 1079 "name-required": "Nome obbligatorio.",
1080 1080 "description": "Descrizione",
1081   - "add": "Add Rule Chain",
  1081 + "add": "Aggiungi Rule Chain",
1082 1082 "set-root": "Make rule chain root",
1083 1083 "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?",
1084 1084 "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.",
1085   - "delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?",
1086   - "delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.",
1087   - "delete-rulechains-title": "Are you sure you want to delete { count, plural, 1 {1 rule chain} other {# rule chains} }?",
1088   - "delete-rulechains-action-title": "Delete { count, plural, 1 {1 rule chain} other {# rule chains} }",
1089   - "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.",
1090   - "add-rulechain-text": "Add new rule chain",
1091   - "no-rulechains-text": "No rule chains found",
1092   - "rulechain-details": "Rule chain details",
  1085 + "delete-rulechain-title": "Sei sicuro di voler eliminare la rule chain '{{ruleChainName}}'?",
  1086 + "delete-rulechain-text": "Attenzione, dopo la conferma la rule chain e tutti i dati relativi non saranno più recuperabili.",
  1087 + "delete-rulechains-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 rule chain} other {# rule chain} }?",
  1088 + "delete-rulechains-action-title": "Elimina { count, plural, 1 {1 rule chain} other {# rule chain} }",
  1089 + "delete-rulechains-text": "Attenzione, dopo la conferma tutte le rule chain selezionate saranno rimosse e tutti i relativi dati non saranno più recuperabili.",
  1090 + "add-rulechain-text": "Aggiungi nuova rule chain",
  1091 + "no-rulechains-text": "Nessuna rule chain trovata",
  1092 + "rulechain-details": "Dettagli rule chain",
1093 1093 "details": "Dettagli",
1094 1094 "events": "Eventi",
1095 1095 "system": "Sistema",
1096   - "import": "Import rule chain",
1097   - "export": "Export rule chain",
1098   - "export-failed-error": "Unable to export rule chain: {{error}}",
1099   - "create-new-rulechain": "Create new rule chain",
1100   - "rulechain-file": "Rule chain file",
1101   - "invalid-rulechain-file-error": "Unable to import rule chain: Invalid rule chain data structure.",
1102   - "copyId": "Copy rule chain Id",
1103   - "idCopiedMessage": "Rule chain Id has been copied to clipboard",
1104   - "select-rulechain": "Select rule chain",
1105   - "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.",
1106   - "rulechain-required": "Rule chain is required",
1107   - "management": "Rules management",
  1096 + "import": "Importa rule chain",
  1097 + "export": "Esporta rule chain",
  1098 + "export-failed-error": "Impossibile esportare rule chain: {{error}}",
  1099 + "create-new-rulechain": "Crea nuova rule chain",
  1100 + "rulechain-file": "File rule chain",
  1101 + "invalid-rulechain-file-error": "Impossibile importare rule chain: struttura dati rule chain non valida.",
  1102 + "copyId": "Copia Id rule chain",
  1103 + "idCopiedMessage": "Id rule chain copiato negli appunti",
  1104 + "select-rulechain": "Seleziona rule chain",
  1105 + "no-rulechains-matching": "Nessuna rule chain corrispondente a '{{entity}}' è stata trovata.",
  1106 + "rulechain-required": "Rule chain obbligatoria",
  1107 + "management": "Gestione regole",
1108 1108 "debug-mode": "Modalità debug"
1109 1109 },
1110 1110 "rulenode": {
... ... @@ -1209,10 +1209,10 @@
1209 1209 "history": "Cronologia",
1210 1210 "last-prefix": "ultimo",
1211 1211 "period": "from {{ startTime }} to {{ endTime }}",
1212   - "edit": "Edit timewindow",
1213   - "date-range": "Date range",
  1212 + "edit": "Modifica intervallo temporale",
  1213 + "date-range": "Intervallo date",
1214 1214 "last": "Ultimo",
1215   - "time-period": "Time period"
  1215 + "time-period": "Intervallo temporale"
1216 1216 },
1217 1217 "user": {
1218 1218 "user": "Utente",
... ... @@ -1379,10 +1379,10 @@
1379 1379 "mobile-mode-settings": "Impostazioni modalità mobile",
1380 1380 "order": "Ordinamento",
1381 1381 "height": "Altezza",
1382   - "units": "Simbolo speciale da mostrare vicino al valore",
  1382 + "units": "Simbolo speciale da mostrare accanto al valore",
1383 1383 "decimals": "Numero di cifre decimali",
1384   - "timewindow": "Timewindow",
1385   - "use-dashboard-timewindow": "Use dashboard timewindow",
  1384 + "timewindow": "Intervallo temporale",
  1385 + "use-dashboard-timewindow": "Usa intervallo temporale dashboard",
1386 1386 "display-legend": "Mostra legenda",
1387 1387 "datasources": "Sorgenti dei dati",
1388 1388 "maximum-datasources": "Massimo { count, plural, 1 {1 sorgente dati consentita.} other {# sorgenti dati consentite} }",
... ... @@ -1434,12 +1434,14 @@
1434 1434 "language": {
1435 1435 "language": "Lingua",
1436 1436 "locales": {
  1437 + "fr_FR": "Francese",
1437 1438 "zh_CN": "Cinese",
1438 1439 "ko_KR": "Coreano",
1439 1440 "en_US": "Inglese",
1440 1441 "it_IT": "Italiano",
1441 1442 "ru_RU": "Russo",
1442   - "es_ES": "Spagnolo"
  1443 + "es_ES": "Spagnolo",
  1444 + "ja_JA": "Giapponese"
1443 1445 }
1444 1446 }
1445 1447 }
... ...
  1 +{
  2 + "access": {
  3 + "unauthorized": "無許可",
  4 + "unauthorized-access": "不正アクセス",
  5 + "unauthorized-access-text": "このリソースにアクセスするにはサインインする必要があります。",
  6 + "access-forbidden": "アクセス禁止",
  7 + "access-forbidden-text": "あなたはこの場所へのアクセス権を持っていません!この場所にアクセスしたい場合は、別のユーザーとサインインしてみてください。",
  8 + "refresh-token-expired": "セッションが終了しました",
  9 + "refresh-token-failed": "セッションをリフレッシュできません"
  10 + },
  11 + "action": {
  12 + "activate": "アクティブ化する",
  13 + "suspend": "サスペンド",
  14 + "save": "セーブ",
  15 + "saveAs": "名前を付けて保存",
  16 + "cancel": "キャンセル",
  17 + "ok": "[OK]",
  18 + "delete": "削除",
  19 + "add": "追加",
  20 + "yes": "はい",
  21 + "no": "いいえ",
  22 + "update": "更新",
  23 + "remove": "削除する",
  24 + "search": "サーチ",
  25 + "clear-search": "検索をクリアする",
  26 + "assign": "割り当てます",
  27 + "unassign": "割り当て解除",
  28 + "share": "シェア",
  29 + "make-private": "プライベートにする",
  30 + "apply": "適用",
  31 + "apply-changes": "変更を適用する",
  32 + "edit-mode": "編集モード",
  33 + "enter-edit-mode": "編集モードに入る",
  34 + "decline-changes": "変更を拒否する",
  35 + "close": "閉じる",
  36 + "back": "バック",
  37 + "run": "走る",
  38 + "sign-in": "サインイン!",
  39 + "edit": "編集",
  40 + "view": "ビュー",
  41 + "create": "作成する",
  42 + "drag": "ドラッグ",
  43 + "refresh": "リフレッシュ",
  44 + "undo": "元に戻す",
  45 + "copy": "コピー",
  46 + "paste": "ペースト",
  47 + "copy-reference": "コピーリファレンス",
  48 + "paste-reference": "参照貼り付け",
  49 + "import": "インポート",
  50 + "export": "輸出する",
  51 + "share-via": "{{provider}}"
  52 + },
  53 + "aggregation": {
  54 + "aggregation": "集約",
  55 + "function": "データ集約機能",
  56 + "limit": "最大値",
  57 + "group-interval": "グループ化の間隔",
  58 + "min": "分",
  59 + "max": "最大",
  60 + "avg": "平均",
  61 + "sum": "和",
  62 + "count": "カウント",
  63 + "none": "なし"
  64 + },
  65 + "admin": {
  66 + "general": "一般",
  67 + "general-settings": "一般設定",
  68 + "outgoing-mail": "送信メール",
  69 + "outgoing-mail-settings": "送信メールの設定",
  70 + "system-settings": "システム設定",
  71 + "test-mail-sent": "テストメールが正常に送信されました!",
  72 + "base-url": "ベースURL",
  73 + "base-url-required": "ベースURLは必須です。",
  74 + "mail-from": "メール",
  75 + "mail-from-required": "メールの送信元が必要です。",
  76 + "smtp-protocol": "SMTPプロトコル",
  77 + "smtp-host": "SMTPホスト",
  78 + "smtp-host-required": "SMTPホストが必要です。",
  79 + "smtp-port": "SMTPポート",
  80 + "smtp-port-required": "smtpポートを指定する必要があります。",
  81 + "smtp-port-invalid": "それは有効なsmtpポートのようには見えません。",
  82 + "timeout-msec": "タイムアウト(ミリ秒)",
  83 + "timeout-required": "タイムアウトが必要です。",
  84 + "timeout-invalid": "それは有効なタイムアウトのようには見えません。",
  85 + "enable-tls": "TLSを有効にする",
  86 + "send-test-mail": "テストメールを送信する"
  87 + },
  88 + "alarm": {
  89 + "alarm": "警報",
  90 + "alarms": "アラーム",
  91 + "select-alarm": "アラームを選択",
  92 + "no-alarms-matching": "'{{entity}}'発見されました。",
  93 + "alarm-required": "アラームが必要です",
  94 + "alarm-status": "アラーム状態",
  95 + "search-status": {
  96 + "ANY": "どれか",
  97 + "ACTIVE": "アクティブ",
  98 + "CLEARED": "クリアされた",
  99 + "ACK": "承認された",
  100 + "UNACK": "未確認の"
  101 + },
  102 + "display-status": {
  103 + "ACTIVE_UNACK": "アクティブ未確認",
  104 + "ACTIVE_ACK": "Active Acknowledged",
  105 + "CLEARED_UNACK": "クリアされた未確認のメッセージ",
  106 + "CLEARED_ACK": "承認された承認済み"
  107 + },
  108 + "no-alarms-prompt": "アラームが見つかりません",
  109 + "created-time": "作成時刻",
  110 + "type": "タイプ",
  111 + "severity": "重大度",
  112 + "originator": "創始者",
  113 + "originator-type": "発信者タイプ",
  114 + "details": "詳細",
  115 + "status": "状態",
  116 + "alarm-details": "アラームの詳細",
  117 + "start-time": "始まる時間",
  118 + "end-time": "終了時間",
  119 + "ack-time": "確認された時間",
  120 + "clear-time": "クリアされた時間",
  121 + "severity-critical": "クリティカル",
  122 + "severity-major": "メジャー",
  123 + "severity-minor": "マイナー",
  124 + "severity-warning": "警告",
  125 + "severity-indeterminate": "不確定",
  126 + "acknowledge": "認める",
  127 + "clear": "クリア",
  128 + "search": "アラームの検索",
  129 + "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} }選択された",
  130 + "no-data": "表示するデータがありません",
  131 + "polling-interval": "アラームポーリング間隔(秒)",
  132 + "polling-interval-required": "アラームのポーリング間隔が必要です。",
  133 + "min-polling-interval-message": "少なくとも1秒間のポーリング間隔が許可されます。",
  134 + "aknowledge-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }",
  135 + "aknowledge-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?",
  136 + "clear-alarms-title": "{ count, plural, 1 {1 alarm} other {# alarms} }",
  137 + "clear-alarms-text": "{ count, plural, 1 {1 alarm} other {# alarms} }?"
  138 + },
  139 + "alias": {
  140 + "add": "エイリアスを追加する",
  141 + "edit": "エイリアスを編集する",
  142 + "name": "エイリアス名",
  143 + "name-required": "エイリアス名は必須です",
  144 + "duplicate-alias": "同じ名前のエイリアスは既に存在します。",
  145 + "filter-type-single-entity": "単一のエンティティ",
  146 + "filter-type-entity-list": "エンティティリスト",
  147 + "filter-type-entity-name": "エンティティ名",
  148 + "filter-type-state-entity": "ダッシュボード状態からのエンティティ",
  149 + "filter-type-state-entity-description": "ダッシュボードの状態パラメータから取得されたエンティティ",
  150 + "filter-type-asset-type": "資産の種類",
  151 + "filter-type-asset-type-description": "'{{assetType}}'",
  152 + "filter-type-asset-type-and-name-description": "'{{assetType}}''{{prefix}}'",
  153 + "filter-type-device-type": "デバイスタイプ",
  154 + "filter-type-device-type-description": "'{{deviceType}}'",
  155 + "filter-type-device-type-and-name-description": "'{{deviceType}}''{{prefix}}'",
  156 + "filter-type-relations-query": "関係クエリ",
  157 + "filter-type-relations-query-description": "{{entities}}{{relationType}}{{direction}}{{rootEntity}}",
  158 + "filter-type-asset-search-query": "資産検索クエリ",
  159 + "filter-type-asset-search-query-description": "{{assetTypes}}{{relationType}}{{direction}}{{rootEntity}}",
  160 + "filter-type-device-search-query": "デバイス検索クエリ",
  161 + "filter-type-device-search-query-description": "{{deviceTypes}}{{relationType}}{{direction}}{{rootEntity}}",
  162 + "entity-filter": "エンティティフィルタ",
  163 + "resolve-multiple": "複数のエンティティとして解決する",
  164 + "filter-type": "フィルタタイプ",
  165 + "filter-type-required": "フィルタタイプが必要です。",
  166 + "entity-filter-no-entity-matched": "指定されたフィルタに一致するエンティティは見つかりませんでした。",
  167 + "no-entity-filter-specified": "エンティティフィルタが指定されていない",
  168 + "root-state-entity": "ルートとしてダッシュボードの状態エンティティを使用する",
  169 + "root-entity": "ルートエンティティ",
  170 + "state-entity-parameter-name": "状態エンティティのパラメータ名",
  171 + "default-state-entity": "デフォルト状態エンティティ",
  172 + "default-entity-parameter-name": "デフォルトでは",
  173 + "max-relation-level": "最大関連レベル",
  174 + "unlimited-level": "無制限レベル",
  175 + "state-entity": "ダッシュボードの状態エンティティ",
  176 + "all-entities": "すべてのエンティティ",
  177 + "any-relation": "どれか"
  178 + },
  179 + "asset": {
  180 + "asset": "資産",
  181 + "assets": "資産",
  182 + "management": "資産運用管理",
  183 + "view-assets": "アセットの表示",
  184 + "add": "アセットを追加",
  185 + "assign-to-customer": "顧客に割り当てる",
  186 + "assign-asset-to-customer": "顧客に資産を割り当てる",
  187 + "assign-asset-to-customer-text": "顧客に割り当てる資産を選択してください",
  188 + "no-assets-text": "アセットが見つかりません",
  189 + "assign-to-customer-text": "資産を割り当てる顧客を選択してください",
  190 + "public": "パブリック",
  191 + "assignedToCustomer": "顧客に割り当てられた",
  192 + "make-public": "アセットを公開する",
  193 + "make-private": "アセットをプライベートにする",
  194 + "unassign-from-customer": "顧客からの割り当て解除",
  195 + "delete": "アセットを削除",
  196 + "asset-public": "資産は公開されています",
  197 + "asset-type": "資産の種類",
  198 + "asset-type-required": "資産の種類が必要です。",
  199 + "select-asset-type": "アセットタイプを選択",
  200 + "enter-asset-type": "アセットタイプを入力",
  201 + "any-asset": "すべてのアセット",
  202 + "no-asset-types-matching": "'{{entitySubtype}}'発見されました。",
  203 + "asset-type-list-empty": "選択されたアセットタイプはありません。",
  204 + "asset-types": "資産タイプ",
  205 + "name": "名",
  206 + "name-required": "名前は必須です。",
  207 + "description": "説明",
  208 + "type": "タイプ",
  209 + "type-required": "タイプが必要です。",
  210 + "details": "詳細",
  211 + "events": "イベント",
  212 + "add-asset-text": "新しいアセットを追加する",
  213 + "asset-details": "資産の詳細",
  214 + "assign-assets": "アセットの割り当て",
  215 + "assign-assets-text": "{ count, plural, 1 {1 asset} other {# assets} }顧客に",
  216 + "delete-assets": "アセットを削除する",
  217 + "unassign-assets": "アセットの割り当てを解除する",
  218 + "unassign-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }顧客から",
  219 + "assign-new-asset": "新しいアセットを割り当てる",
  220 + "delete-asset-title": "'{{assetName}}'?",
  221 + "delete-asset-text": "確認後、資産と関連するすべてのデータが回復不能になることに注意してください。",
  222 + "delete-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?",
  223 + "delete-assets-action-title": "{ count, plural, 1 {1 asset} other {# assets} }",
  224 + "delete-assets-text": "確認後、選択したすべての資産が削除され、関連するすべてのデータは回復不能になりますので注意してください。",
  225 + "make-public-asset-title": "'{{assetName}}'パブリック?",
  226 + "make-public-asset-text": "確認後、資産とそのすべてのデータは公開され、他の人がアクセスできるようになります。",
  227 + "make-private-asset-title": "'{{assetName}}'プライベート?",
  228 + "make-private-asset-text": "確認後、資産とそのすべてのデータは非公開にされ、他の人がアクセスすることはできません。",
  229 + "unassign-asset-title": "'{{assetName}}'?",
  230 + "unassign-asset-text": "確認後、資産は割り当て解除され、顧客はアクセスできなくなります。",
  231 + "unassign-asset": "アセットの割り当てを解除する",
  232 + "unassign-assets-title": "{ count, plural, 1 {1 asset} other {# assets} }?",
  233 + "unassign-assets-text": "確認後、選択されたすべての資産が割り当て解除され、顧客がアクセスできなくなります。",
  234 + "copyId": "アセットIDをコピーする",
  235 + "idCopiedMessage": "アセットIDがクリップボードにコピーされました",
  236 + "select-asset": "アセットを選択",
  237 + "no-assets-matching": "'{{entity}}'発見されました。",
  238 + "asset-required": "資産が必要です",
  239 + "name-starts-with": "アセット名はで始まります"
  240 + },
  241 + "attribute": {
  242 + "attributes": "属性",
  243 + "latest-telemetry": "最新テレメトリ",
  244 + "attributes-scope": "エンティティ属性のスコープ",
  245 + "scope-latest-telemetry": "最新テレメトリ",
  246 + "scope-client": "クライアントの属性",
  247 + "scope-server": "サーバーの属性",
  248 + "scope-shared": "共有属性",
  249 + "add": "属性を追加する",
  250 + "key": "キー",
  251 + "last-update-time": "最終更新時間",
  252 + "key-required": "属性キーは必須です。",
  253 + "value": "値",
  254 + "value-required": "属性値は必須です。",
  255 + "delete-attributes-title": "{ count, plural, 1 {1 attribute} other {# attributes} }?",
  256 + "delete-attributes-text": "注意してください。確認後、選択したすべての属性が削除されます。",
  257 + "delete-attributes": "属性を削除する",
  258 + "enter-attribute-value": "属性値を入力",
  259 + "show-on-widget": "ウィジェットで表示",
  260 + "widget-mode": "ウィジェットモード",
  261 + "next-widget": "次のウィジェット",
  262 + "prev-widget": "前のウィジェット",
  263 + "add-to-dashboard": "ダッシュボードに追加",
  264 + "add-widget-to-dashboard": "ウィジェットをダッシュ​​ボードに追加する",
  265 + "selected-attributes": "{ count, plural, 1 {1 attribute} other {# attributes} }選択された",
  266 + "selected-telemetry": "{ count, plural, 1 {1 telemetry unit} other {# telemetry units} }選択された"
  267 + },
  268 + "audit-log": {
  269 + "audit": "監査",
  270 + "audit-logs": "監査ログ",
  271 + "timestamp": "タイムスタンプ",
  272 + "entity-type": "エンティティタイプ",
  273 + "entity-name": "エンティティ名",
  274 + "user": "ユーザー",
  275 + "type": "タイプ",
  276 + "status": "状態",
  277 + "details": "詳細",
  278 + "type-added": "追加された",
  279 + "type-deleted": "削除済み",
  280 + "type-updated": "更新しました",
  281 + "type-attributes-updated": "属性が更新されました",
  282 + "type-attributes-deleted": "属性が削除されました",
  283 + "type-rpc-call": "RPC呼び出し",
  284 + "type-credentials-updated": "資格が更新されました",
  285 + "type-assigned-to-customer": "顧客に割り当てられた",
  286 + "type-unassigned-from-customer": "顧客から割り当てられていない",
  287 + "type-activated": "活性化",
  288 + "type-suspended": "一時停止中",
  289 + "type-credentials-read": "信用証明書を読む",
  290 + "type-attributes-read": "読み取られた属性",
  291 + "type-relation-add-or-update": "関係が更新されました",
  292 + "type-relation-delete": "関係が削除されました",
  293 + "type-relations-delete": "すべてのリレーションを削除",
  294 + "type-alarm-ack": "承認された",
  295 + "type-alarm-clear": "クリアされた",
  296 + "status-success": "成功",
  297 + "status-failure": "失敗",
  298 + "audit-log-details": "監査ログの詳細",
  299 + "no-audit-logs-prompt": "ログが見つかりません",
  300 + "action-data": "行動データ",
  301 + "failure-details": "失敗の詳細",
  302 + "search": "監査ログの検索",
  303 + "clear-search": "検索をクリアする"
  304 + },
  305 + "confirm-on-exit": {
  306 + "message": "保存されていない変更があります。あなたは本当にこのページを出るのですか?",
  307 + "html-message": "保存していない変更があります。<br/>このページを終了してもよろしいですか?",
  308 + "title": "保存されていない変更"
  309 + },
  310 + "contact": {
  311 + "country": "国",
  312 + "city": "シティ",
  313 + "state": "州/県",
  314 + "postal-code": "郵便番号",
  315 + "postal-code-invalid": "無効な郵便番号形式です。",
  316 + "address": "住所",
  317 + "address2": "アドレス2",
  318 + "phone": "電話",
  319 + "email": "Eメール",
  320 + "no-address": "住所がありません"
  321 + },
  322 + "common": {
  323 + "username": "ユーザー名",
  324 + "password": "パスワード",
  325 + "enter-username": "ユーザーネームを入力してください",
  326 + "enter-password": "パスワードを入力する",
  327 + "enter-search": "検索を入力"
  328 + },
  329 + "content-type": {
  330 + "json": "Json",
  331 + "text": "テキスト",
  332 + "binary": "バイナリ(Base64)"
  333 + },
  334 + "customer": {
  335 + "customer": "顧客",
  336 + "customers": "顧客",
  337 + "management": "顧客管理",
  338 + "dashboard": "カスタマーダッシュボード",
  339 + "dashboards": "カスタマーダッシュボード",
  340 + "devices": "顧客デバイス",
  341 + "assets": "顧客資産",
  342 + "public-dashboards": "パブリックダッシュボード",
  343 + "public-devices": "パブリックデバイス",
  344 + "public-assets": "公的資産",
  345 + "add": "顧客を追加",
  346 + "delete": "顧客を削除する",
  347 + "manage-customer-users": "顧客ユーザーを管理する",
  348 + "manage-customer-devices": "顧客のデバイスを管理する",
  349 + "manage-customer-dashboards": "顧客ダッシュボードの管理",
  350 + "manage-public-devices": "パブリックデバイスを管理する",
  351 + "manage-public-dashboards": "公開ダッシュボードの管理",
  352 + "manage-customer-assets": "顧客資産の管理",
  353 + "manage-public-assets": "公的資産を管理する",
  354 + "add-customer-text": "新規顧客を追加",
  355 + "no-customers-text": "顧客が見つかりません",
  356 + "customer-details": "お客様情報",
  357 + "delete-customer-title": "'{{customerTitle}}'?",
  358 + "delete-customer-text": "確認後、お客様および関連するすべてのデータが回復不能になるので注意してください。",
  359 + "delete-customers-title": "{ count, plural, 1 {1 customer} other {# customers} }?",
  360 + "delete-customers-action-title": "{ count, plural, 1 {1 customer} other {# customers} }",
  361 + "delete-customers-text": "確認後、選択したすべての顧客は削除され、関連するすべてのデータは回復不能になります。",
  362 + "manage-users": "ユーザーを管理する",
  363 + "manage-assets": "アセットを管理する",
  364 + "manage-devices": "デバイスを管理する",
  365 + "manage-dashboards": "ダッシュボードの管理",
  366 + "title": "タイトル",
  367 + "title-required": "タイトルは必須です。",
  368 + "description": "説明",
  369 + "details": "詳細",
  370 + "events": "イベント",
  371 + "copyId": "顧客IDをコピー",
  372 + "idCopiedMessage": "顧客IDがクリップボードにコピーされました",
  373 + "select-customer": "顧客を選択",
  374 + "no-customers-matching": "'{{entity}}'発見されました。",
  375 + "customer-required": "顧客は必須です",
  376 + "select-default-customer": "デフォルトの顧客を選択",
  377 + "default-customer": "デフォルトの顧客",
  378 + "default-customer-required": "テナントレベルのダッシュボードをデバッグするには、デフォルトの顧客が必要です"
  379 + },
  380 + "datetime": {
  381 + "date-from": "デートから",
  382 + "time-from": "からの時間",
  383 + "date-to": "日付",
  384 + "time-to": "の時間"
  385 + },
  386 + "dashboard": {
  387 + "dashboard": "ダッシュボード",
  388 + "dashboards": "ダッシュボード",
  389 + "management": "ダッシュボード管理",
  390 + "view-dashboards": "ダッシュボードを表示する",
  391 + "add": "ダッシュボードを追加",
  392 + "assign-dashboard-to-customer": "顧客にダッシュボードを割り当てる",
  393 + "assign-dashboard-to-customer-text": "顧客に割り当てるダッシュボードを選択してください",
  394 + "assign-to-customer-text": "ダッシュボードを割り当てる顧客を選択してください",
  395 + "assign-to-customer": "顧客に割り当てる",
  396 + "unassign-from-customer": "顧客からの割り当て解除",
  397 + "make-public": "ダッシュボードを公開する",
  398 + "make-private": "ダッシュボードを非公開にする",
  399 + "manage-assigned-customers": "割り当てられた顧客を管理する",
  400 + "assigned-customers": "割り当てられた顧客",
  401 + "assign-to-customers": "顧客にダッシュボードを割り当てる",
  402 + "assign-to-customers-text": "ダッシュボードを割り当てる顧客を選択してください",
  403 + "unassign-from-customers": "顧客からのダッシュボードの割り当て解除",
  404 + "unassign-from-customers-text": "ダッシュボードから割り当て解除する顧客を選択してください",
  405 + "no-dashboards-text": "ダッシュボードが見つかりません",
  406 + "no-widgets": "ウィジェットは設定されていません",
  407 + "add-widget": "新しいウィジェットを追加",
  408 + "title": "タイトル",
  409 + "select-widget-title": "ウィジェットを選択",
  410 + "select-widget-subtitle": "利用可能なウィジェットタイプのリスト",
  411 + "delete": "ダッシュボードの削除",
  412 + "title-required": "タイトルは必須です。",
  413 + "description": "説明",
  414 + "details": "詳細",
  415 + "dashboard-details": "ダッシュボードの詳細",
  416 + "add-dashboard-text": "新しいダッシュボードを追加する",
  417 + "assign-dashboards": "ダッシュボードの割り当て",
  418 + "assign-new-dashboard": "新しいダッシュボードを割り当てる",
  419 + "assign-dashboards-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客に",
  420 + "unassign-dashboards-action-text": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から",
  421 + "delete-dashboards": "ダッシュボードの削除",
  422 + "unassign-dashboards": "ダッシュボードの割り当てを解除する",
  423 + "unassign-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }顧客から",
  424 + "delete-dashboard-title": "'{{dashboardTitle}}'?",
  425 + "delete-dashboard-text": "確認後、ダッシュボードとすべての関連データが回復不能になるので注意してください。",
  426 + "delete-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?",
  427 + "delete-dashboards-action-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }",
  428 + "delete-dashboards-text": "注意してください。確認後、選択したダッシュボードはすべて削除され、関連するすべてのデータは回復不能になります。",
  429 + "unassign-dashboard-title": "'{{dashboardTitle}}'?",
  430 + "unassign-dashboard-text": "確認後、ダッシュボードは割り当てられなくなり、顧客はアクセスできなくなります。",
  431 + "unassign-dashboard": "ダッシュボードの割り当てを解除する",
  432 + "unassign-dashboards-title": "{ count, plural, 1 {1 dashboard} other {# dashboards} }?",
  433 + "unassign-dashboards-text": "確認の後、選択したすべてのダッシュボードは割り当てられなくなり、顧客はアクセスできなくなります。",
  434 + "public-dashboard-title": "ダッシュボードは公開されました",
  435 + "public-dashboard-text": "<b>{{dashboardTitle}}</b> is now public and accessible via next public <a href='{{publicLink}}' target='_blank'>link</a>:",
  436 + "public-dashboard-notice": "<b>注:</ b>データにアクセスするために、関連するデバイスを公開することを忘れないでください。",
  437 + "make-private-dashboard-title": "'{{dashboardTitle}}'プライベート?",
  438 + "make-private-dashboard-text": "確認の後、ダッシュボードはプライベートにされ、他の人がアクセスすることはできません。",
  439 + "make-private-dashboard": "ダッシュボードを非公開にする",
  440 + "socialshare-text": "'{{dashboardTitle}}'ThingsBoardを搭載",
  441 + "socialshare-title": "'{{dashboardTitle}}'ThingsBoardを搭載",
  442 + "select-dashboard": "ダッシュボードを選択",
  443 + "no-dashboards-matching": "'{{entity}}'発見されました。",
  444 + "dashboard-required": "ダッシュボードが必要です。",
  445 + "select-existing": "既存のダッシュボードを選択",
  446 + "create-new": "新しいダッシュボードを作成する",
  447 + "new-dashboard-title": "新しいダッシュボードのタイトル",
  448 + "open-dashboard": "ダッシュボードを開く",
  449 + "set-background": "背景を設定する",
  450 + "background-color": "背景色",
  451 + "background-image": "背景画像",
  452 + "background-size-mode": "背景サイズモード",
  453 + "no-image": "選択した画像がありません",
  454 + "drop-image": "画像をドロップするか、クリックしてアップロードするファイルを選択します。",
  455 + "settings": "設定",
  456 + "columns-count": "列数",
  457 + "columns-count-required": "列数が必要です。",
  458 + "min-columns-count-message": "わずか10の最小列数が許可されます。",
  459 + "max-columns-count-message": "最大1000の列カウントのみが許可されます。",
  460 + "widgets-margins": "ウィジェット間のマージン",
  461 + "horizontal-margin": "水平マージン",
  462 + "horizontal-margin-required": "水平余白値が必要です。",
  463 + "min-horizontal-margin-message": "最小水平マージン値としては0だけが許容されます。",
  464 + "max-horizontal-margin-message": "最大水平マージン値は50だけです。",
  465 + "vertical-margin": "垂直マージン",
  466 + "vertical-margin-required": "垂直マージン値が必要です。",
  467 + "min-vertical-margin-message": "最小の垂直マージン値として0のみが許可されます。",
  468 + "max-vertical-margin-message": "最大垂直マージン値は50のみです。",
  469 + "autofill-height": "自動レイアウトの高さ",
  470 + "mobile-layout": "モバイルレイアウトの設定",
  471 + "mobile-row-height": "モバイル行の高さ、px",
  472 + "mobile-row-height-required": "モバイル行の高さ値が必要です。",
  473 + "min-mobile-row-height-message": "最小の行の高さの値として、5ピクセルしか許可されません。",
  474 + "max-mobile-row-height-message": "移動可能な行の高さの最大値として許可されるのは200ピクセルだけです。",
  475 + "display-title": "ダッシュボードのタイトルを表示する",
  476 + "toolbar-always-open": "ツールバーを開いたままにする",
  477 + "title-color": "タイトルカラー",
  478 + "display-dashboards-selection": "ダッシュボードの選択を表示する",
  479 + "display-entities-selection": "エンティティの選択を表示する",
  480 + "display-dashboard-timewindow": "タイムウィンドウを表示する",
  481 + "display-dashboard-export": "エクスポートの表示",
  482 + "import": "インポートダッシュボード",
  483 + "export": "エクスポートダッシュボード",
  484 + "export-failed-error": "{{error}}",
  485 + "create-new-dashboard": "新しいダッシュボードを作成する",
  486 + "dashboard-file": "ダッシュボードファイル",
  487 + "invalid-dashboard-file-error": "ダッシュボードをインポートできません:ダッシュボードのデータ構造が無効です。",
  488 + "dashboard-import-missing-aliases-title": "インポートされたダッシュボードで使用されるエイリアスを設定する",
  489 + "create-new-widget": "新しいウィジェットを作成する",
  490 + "import-widget": "インポートウィジェット",
  491 + "widget-file": "ウィジェットファイル",
  492 + "invalid-widget-file-error": "ウィジェットをインポートできません:ウィジェットのデータ構造が無効です。",
  493 + "widget-import-missing-aliases-title": "インポートされたウィジェットで使用されるエイリアスを設定する",
  494 + "open-toolbar": "ダッシュボードツールバーを開く",
  495 + "close-toolbar": "ツールバーを閉じる",
  496 + "configuration-error": "設定エラー",
  497 + "alias-resolution-error-title": "ダッシュボードエイリアス設定エラー",
  498 + "invalid-aliases-config": "エイリアスフィルタの一部に一致するデバイスを見つけることができません。<br/>この問題を解決するには、管理者に連絡してください。",
  499 + "select-devices": "デバイスの選択",
  500 + "assignedToCustomer": "顧客に割り当てられた",
  501 + "assignedToCustomers": "顧客に割り当てられた",
  502 + "public": "パブリック",
  503 + "public-link": "パブリックリンク",
  504 + "copy-public-link": "パブリックリンクをコピーする",
  505 + "public-link-copied-message": "ダッシュボードのパブリックリンクがクリップボードにコピーされました",
  506 + "manage-states": "ダッシュボードの状態を管理する",
  507 + "states": "ダッシュボードの状態",
  508 + "search-states": "検索ダッシュボードの状態",
  509 + "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard states} }選択された",
  510 + "edit-state": "ダッシュボードの状態を編集する",
  511 + "delete-state": "ダッシュボードの状態を削除する",
  512 + "add-state": "ダッシュボードの状態を追加する",
  513 + "state": "ダッシュボードの状態",
  514 + "state-name": "名",
  515 + "state-name-required": "ダッシュボードの状態名は必須です。",
  516 + "state-id": "状態ID",
  517 + "state-id-required": "ダッシュボードの状態IDは必須です。",
  518 + "state-id-exists": "同じIDを持つダッシュボードの状態は既に存在します。",
  519 + "is-root-state": "ルート状態",
  520 + "delete-state-title": "ダッシュボードの状態を削除する",
  521 + "delete-state-text": "'{{stateName}}'?",
  522 + "show-details": "詳細を表示",
  523 + "hide-details": "詳細を隠す",
  524 + "select-state": "ターゲット状態を選択する",
  525 + "state-controller": "状態コントローラ"
  526 + },
  527 + "datakey": {
  528 + "settings": "設定",
  529 + "advanced": "上級",
  530 + "label": "ラベル",
  531 + "color": "色",
  532 + "units": "値の隣に表示する特別なシンボル",
  533 + "decimals": "浮動小数点の後の桁数",
  534 + "data-generation-func": "データ生成関数",
  535 + "use-data-post-processing-func": "データ後処理機能を使用する",
  536 + "configuration": "データキー設定",
  537 + "timeseries": "タイムズ",
  538 + "attributes": "属性",
  539 + "alarm": "アラームフィールド",
  540 + "timeseries-required": "エンティティの時系列データが必要です。",
  541 + "timeseries-or-attributes-required": "エンティティのtimeseries /属性は必須です。",
  542 + "maximum-timeseries-or-attributes": "{ count, plural, 1 {1 timeseries/attribute is allowed.} other {# timeseries/attributes are allowed} }",
  543 + "alarm-fields-required": "アラームフィールドが必要です。",
  544 + "function-types": "関数型",
  545 + "function-types-required": "関数型が必要です。",
  546 + "maximum-function-types": "{ count, plural, 1 {1 function type is allowed.} other {# function types are allowed} }"
  547 + },
  548 + "datasource": {
  549 + "type": "データソースタイプ",
  550 + "name": "名",
  551 + "add-datasource-prompt": "データソースを追加してください"
  552 + },
  553 + "details": {
  554 + "edit-mode": "編集モード",
  555 + "toggle-edit-mode": "編集モードを切り替える"
  556 + },
  557 + "device": {
  558 + "device": "デバイス",
  559 + "device-required": "デバイスが必要です。",
  560 + "devices": "デバイス",
  561 + "management": "端末管理",
  562 + "view-devices": "デバイスの表示",
  563 + "device-alias": "デバイスエイリアス",
  564 + "aliases": "デバイスエイリアス",
  565 + "no-alias-matching": "'{{alias}}'見つかりません。",
  566 + "no-aliases-found": "別名は見つかりませんでした。",
  567 + "no-key-matching": "'{{key}}'見つかりません。",
  568 + "no-keys-found": "キーが見つかりません。",
  569 + "create-new-alias": "新しいものを作成してください!",
  570 + "create-new-key": "新しいものを作成してください!",
  571 + "duplicate-alias-error": "'{{alias}}'<br>デバイスエイリアスは、ダッシュボード内で一意である必要があります。",
  572 + "configure-alias": "'{{alias}}'エイリアス",
  573 + "no-devices-matching": "'{{entity}}'発見されました。",
  574 + "alias": "エイリアス",
  575 + "alias-required": "デバイスエイリアスが必要です。",
  576 + "remove-alias": "デバイスエイリアスを削除する",
  577 + "add-alias": "デバイスエイリアスを追加する",
  578 + "name-starts-with": "デバイス名はで始まります",
  579 + "device-list": "デバイスリスト",
  580 + "use-device-name-filter": "フィルタを使用する",
  581 + "device-list-empty": "デバイスが選択されていません。",
  582 + "device-name-filter-required": "デバイス名フィルタが必要です。",
  583 + "device-name-filter-no-device-matched": "'{{device}}'発見されました。",
  584 + "add": "デバイスを追加",
  585 + "assign-to-customer": "顧客に割り当てる",
  586 + "assign-device-to-customer": "顧客にデバイスを割り当てる",
  587 + "assign-device-to-customer-text": "顧客に割り当てるデバイスを選択してください",
  588 + "make-public": "端末を公開する",
  589 + "make-private": "デバイスを非公開にする",
  590 + "no-devices-text": "デバイスが見つかりません",
  591 + "assign-to-customer-text": "デバイスを割り当てる顧客を選択してください",
  592 + "device-details": "デバイスの詳細",
  593 + "add-device-text": "新しいデバイスを追加する",
  594 + "credentials": "資格情報",
  595 + "manage-credentials": "資格情報を管理する",
  596 + "delete": "デバイスを削除する",
  597 + "assign-devices": "デバイスを割り当てる",
  598 + "assign-devices-text": "{ count, plural, 1 {1 device} other {# devices} }顧客に",
  599 + "delete-devices": "デバイスを削除する",
  600 + "unassign-from-customer": "顧客からの割り当て解除",
  601 + "unassign-devices": "デバイスの割り当てを解除する",
  602 + "unassign-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }顧客から",
  603 + "assign-new-device": "新しいデバイスを割り当てる",
  604 + "make-public-device-title": "'{{deviceName}}'パブリック?",
  605 + "make-public-device-text": "確認後、デバイスとそのすべてのデータは公開され、他のユーザーがアクセスできるようになります。",
  606 + "make-private-device-title": "'{{deviceName}}'プライベート?",
  607 + "make-private-device-text": "確認後、デバイスとそのすべてのデータは非公開になり、他人がアクセスできなくなります。",
  608 + "view-credentials": "資格情報を表示する",
  609 + "delete-device-title": "'{{deviceName}}'?",
  610 + "delete-device-text": "確認後、デバイスと関連するすべてのデータが回復不能になるので注意してください。",
  611 + "delete-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?",
  612 + "delete-devices-action-title": "{ count, plural, 1 {1 device} other {# devices} }",
  613 + "delete-devices-text": "注意してください。確認後、選択したすべてのデバイスが削除され、関連するすべてのデータは回復不能になります。",
  614 + "unassign-device-title": "'{{deviceName}}'?",
  615 + "unassign-device-text": "確認の後、デバイスは割り当てが解除され、顧客がアクセスできなくなります。",
  616 + "unassign-device": "デバイスの割り当てを解除する",
  617 + "unassign-devices-title": "{ count, plural, 1 {1 device} other {# devices} }?",
  618 + "unassign-devices-text": "確認の後、選択されたすべてのデバイスが割り当て解除され、顧客がアクセスできなくなります。",
  619 + "device-credentials": "デバイス資格情報",
  620 + "credentials-type": "資格情報タイプ",
  621 + "access-token": "アクセストークン",
  622 + "access-token-required": "アクセストークンが必要です。",
  623 + "access-token-invalid": "アクセストークンの長さは、1〜20文字でなければなりません。",
  624 + "rsa-key": "RSA公開鍵",
  625 + "rsa-key-required": "RSA公開鍵が必要です。",
  626 + "secret": "秘密",
  627 + "secret-required": "秘密が必要です。",
  628 + "device-type": "デバイスタイプ",
  629 + "device-type-required": "デバイスタイプが必要です。",
  630 + "select-device-type": "デバイスタイプを選択",
  631 + "enter-device-type": "デバイスタイプを入力",
  632 + "any-device": "すべてのデバイス",
  633 + "no-device-types-matching": "'{{entitySubtype}}'発見されました。",
  634 + "device-type-list-empty": "選択されたデバイスタイプはありません。",
  635 + "device-types": "デバイスの種類",
  636 + "name": "名",
  637 + "name-required": "名前は必須です。",
  638 + "description": "説明",
  639 + "events": "イベント",
  640 + "details": "詳細",
  641 + "copyId": "デバイスIDをコピーする",
  642 + "copyAccessToken": "コピーアクセストークン",
  643 + "idCopiedMessage": "デバイスIDがクリップボードにコピーされました",
  644 + "accessTokenCopiedMessage": "デバイスアクセストークンがクリップボードにコピーされました",
  645 + "assignedToCustomer": "顧客に割り当てられた",
  646 + "unable-delete-device-alias-title": "デバイスエイリアスを削除できません",
  647 + "unable-delete-device-alias-text": "'{{deviceAlias}}'{{widgetsList}}",
  648 + "is-gateway": "ゲートウェイです",
  649 + "public": "パブリック",
  650 + "device-public": "デバイスは公開されています",
  651 + "select-device": "デバイスの選択"
  652 + },
  653 + "dialog": {
  654 + "close": "ダイアログを閉じる"
  655 + },
  656 + "error": {
  657 + "unable-to-connect": "サーバーに接続できません!インターネット接続を確認してください。",
  658 + "unhandled-error-code": "{{errorCode}}",
  659 + "unknown-error": "不明なエラー"
  660 + },
  661 + "entity": {
  662 + "entity": "エンティティ",
  663 + "entities": "エンティティ",
  664 + "aliases": "エンティティエイリアス",
  665 + "entity-alias": "エンティティエイリアス",
  666 + "unable-delete-entity-alias-title": "エンティティエイリアスを削除できません",
  667 + "unable-delete-entity-alias-text": "'{{entityAlias}}'{{widgetsList}}",
  668 + "duplicate-alias-error": "'{{alias}}'<br>エンティティのエイリアスは、ダッシュボード内で一意である必要があります。",
  669 + "missing-entity-filter-error": "'{{alias}}'.",
  670 + "configure-alias": "'{{alias}}'エイリアス",
  671 + "alias": "エイリアス",
  672 + "alias-required": "エンティティエイリアスが必要です。",
  673 + "remove-alias": "エンティティエイリアスを削除する",
  674 + "add-alias": "エンティティエイリアスを追加する",
  675 + "entity-list": "エンティティリスト",
  676 + "entity-type": "エンティティタイプ",
  677 + "entity-types": "エンティティタイプ",
  678 + "entity-type-list": "エンティティタイプリスト",
  679 + "any-entity": "任意のエンティティ",
  680 + "enter-entity-type": "エンティティタイプを入力",
  681 + "no-entities-matching": "'{{entity}}'発見されました。",
  682 + "no-entity-types-matching": "'{{entityType}}'発見されました。",
  683 + "name-starts-with": "名前はで始まる",
  684 + "use-entity-name-filter": "フィルタを使用する",
  685 + "entity-list-empty": "選択されたエンティティはありません",
  686 + "entity-type-list-empty": "エンティティタイプは選択されていません。",
  687 + "entity-name-filter-required": "エンティティ名フィルタが必要です。",
  688 + "entity-name-filter-no-entity-matched": "'{{entity}}'発見されました。",
  689 + "all-subtypes": "すべて",
  690 + "select-entities": "エンティティの選択",
  691 + "no-aliases-found": "別名は見つかりませんでした。",
  692 + "no-alias-matching": "'{{alias}}'見つかりません。",
  693 + "create-new-alias": "新しいものを作成してください!",
  694 + "key": "キー",
  695 + "key-name": "キー名",
  696 + "no-keys-found": "キーが見つかりません。",
  697 + "no-key-matching": "'{{key}}'見つかりません。",
  698 + "create-new-key": "新しいものを作成してください!",
  699 + "type": "タイプ",
  700 + "type-required": "エンティティタイプが必要です。",
  701 + "type-device": "デバイス",
  702 + "type-devices": "デバイス",
  703 + "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }",
  704 + "device-name-starts-with": "'{{prefix}}'",
  705 + "type-asset": "資産",
  706 + "type-assets": "資産",
  707 + "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }",
  708 + "asset-name-starts-with": "'{{prefix}}'",
  709 + "type-rule": "ルール",
  710 + "type-rules": "ルール",
  711 + "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }",
  712 + "rule-name-starts-with": "'{{prefix}}'",
  713 + "type-plugin": "プラグイン",
  714 + "type-plugins": "プラグイン",
  715 + "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }",
  716 + "plugin-name-starts-with": "'{{prefix}}'",
  717 + "type-tenant": "テナント",
  718 + "type-tenants": "テナント",
  719 + "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }",
  720 + "tenant-name-starts-with": "'{{prefix}}'",
  721 + "type-customer": "顧客",
  722 + "type-customers": "顧客",
  723 + "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }",
  724 + "customer-name-starts-with": "'{{prefix}}'",
  725 + "type-user": "ユーザー",
  726 + "type-users": "ユーザー",
  727 + "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }",
  728 + "user-name-starts-with": "'{{prefix}}'",
  729 + "type-dashboard": "ダッシュボード",
  730 + "type-dashboards": "ダッシュボード",
  731 + "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }",
  732 + "dashboard-name-starts-with": "'{{prefix}}'",
  733 + "type-alarm": "警報",
  734 + "type-alarms": "アラーム",
  735 + "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }",
  736 + "alarm-name-starts-with": "'{{prefix}}'",
  737 + "type-rulechain": "ルールチェーン",
  738 + "type-rulechains": "ルールチェーン",
  739 + "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }",
  740 + "rulechain-name-starts-with": "'{{prefix}}'",
  741 + "type-rulenode": "ルールノード",
  742 + "type-rulenodes": "ルールノード",
  743 + "list-of-rulenodes": "{ count, plural, 1 {One rule node} other {List of # rule nodes} }",
  744 + "rulenode-name-starts-with": "'{{prefix}}'",
  745 + "type-current-customer": "現在の顧客",
  746 + "search": "検索エンティティ",
  747 + "selected-entities": "{ count, plural, 1 {1 entity} other {# entities} }選択された",
  748 + "entity-name": "エンティティ名",
  749 + "details": "エンティティの詳細",
  750 + "no-entities-prompt": "エンティティが見つかりません",
  751 + "no-data": "表示するデータがありません"
  752 + },
  753 + "event": {
  754 + "event-type": "イベントタイプ",
  755 + "type-error": "エラー",
  756 + "type-lc-event": "ライフサイクルイベント",
  757 + "type-stats": "統計",
  758 + "type-debug-rule-node": "デバッグ",
  759 + "type-debug-rule-chain": "デバッグ",
  760 + "no-events-prompt": "イベントは見つかりませんでした",
  761 + "error": "エラー",
  762 + "alarm": "警報",
  763 + "event-time": "イベント時間",
  764 + "server": "サーバ",
  765 + "body": "体",
  766 + "method": "方法",
  767 + "type": "タイプ",
  768 + "entity": "エンティティ",
  769 + "message-id": "メッセージID",
  770 + "message-type": "メッセージタイプ",
  771 + "data-type": "データ・タイプ",
  772 + "relation-type": "関係タイプ",
  773 + "metadata": "メタデータ",
  774 + "data": "データ",
  775 + "event": "イベント",
  776 + "status": "状態",
  777 + "success": "成功",
  778 + "failed": "失敗",
  779 + "messages-processed": "処理されたメッセージ",
  780 + "errors-occurred": "エラーが発生しました"
  781 + },
  782 + "extension": {
  783 + "extensions": "拡張機能",
  784 + "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} }選択された",
  785 + "type": "タイプ",
  786 + "key": "キー",
  787 + "value": "値",
  788 + "id": "イド",
  789 + "extension-id": "内線番号",
  790 + "extension-type": "拡張タイプ",
  791 + "transformer-json": "JSON *",
  792 + "unique-id-required": "現在の拡張IDは既に存在します。",
  793 + "delete": "拡張子を削除",
  794 + "add": "内線番号を追加",
  795 + "edit": "拡張機能を編集する",
  796 + "delete-extension-title": "'{{extensionId}}'?",
  797 + "delete-extension-text": "確認後、拡張子と関連するすべてのデータが回復不能になることに注意してください。",
  798 + "delete-extensions-title": "{ count, plural, 1 {1 extension} other {# extensions} }?",
  799 + "delete-extensions-text": "注意してください。確認後、選択したすべての内線番号が削除されます。",
  800 + "converters": "コンバーター",
  801 + "converter-id": "コンバーターID",
  802 + "configuration": "構成",
  803 + "converter-configurations": "コンバータ構成",
  804 + "token": "セキュリティトークン",
  805 + "add-converter": "コンバータを追加する",
  806 + "add-config": "コンバータ設定を追加する",
  807 + "device-name-expression": "デバイス名式",
  808 + "device-type-expression": "デバイスタイプの式",
  809 + "custom": "カスタム",
  810 + "to-double": "ダブル",
  811 + "transformer": "トランス",
  812 + "json-required": "トランスフォーマーjsonが必要です。",
  813 + "json-parse": "変圧器jsonを解析できません。",
  814 + "attributes": "属性",
  815 + "add-attribute": "属性を追加する",
  816 + "add-map": "マッピング要素を追加する",
  817 + "timeseries": "タイムズ",
  818 + "add-timeseries": "時系列を追加する",
  819 + "field-required": "フィールドは必須項目です",
  820 + "brokers": "ブローカー",
  821 + "add-broker": "ブローカーを追加",
  822 + "host": "ホスト",
  823 + "port": "ポート",
  824 + "port-range": "ポートは1〜65535の範囲内にある必要があります。",
  825 + "ssl": "SSL",
  826 + "credentials": "資格情報",
  827 + "username": "ユーザー名",
  828 + "password": "パスワード",
  829 + "retry-interval": "ミリ秒単位の再試行間隔",
  830 + "anonymous": "匿名",
  831 + "basic": "ベーシック",
  832 + "pem": "PEM",
  833 + "ca-cert": "CA証明書ファイル*",
  834 + "private-key": "秘密鍵ファイル*",
  835 + "cert": "証明書ファイル*",
  836 + "no-file": "ファイルが選択されていません。",
  837 + "drop-file": "ファイルをドロップするか、クリックしてアップロードするファイルを選択します。",
  838 + "mapping": "マッピング",
  839 + "topic-filter": "トピックフィルタ",
  840 + "converter-type": "コンバータタイプ",
  841 + "converter-json": "Json",
  842 + "json-name-expression": "デバイス名json式",
  843 + "topic-name-expression": "デバイス名トピック表現",
  844 + "json-type-expression": "デバイスタイプjson式",
  845 + "topic-type-expression": "デバイスタイプトピック表現",
  846 + "attribute-key-expression": "属性キー式",
  847 + "attr-json-key-expression": "属性キーjson式",
  848 + "attr-topic-key-expression": "属性キートピック式",
  849 + "request-id-expression": "要求ID式",
  850 + "request-id-json-expression": "リクエストID json式",
  851 + "request-id-topic-expression": "リクエストIDトピック表現",
  852 + "response-topic-expression": "応答トピック表現",
  853 + "value-expression": "値式",
  854 + "topic": "トピック",
  855 + "timeout": "タイムアウト(ミリ秒)",
  856 + "converter-json-required": "コンバータjsonが必要です。",
  857 + "converter-json-parse": "コンバータjsonを解析できません。",
  858 + "filter-expression": "フィルタ式",
  859 + "connect-requests": "接続要求",
  860 + "add-connect-request": "接続要求を追加",
  861 + "disconnect-requests": "切断要求",
  862 + "add-disconnect-request": "切断リクエストを追加する",
  863 + "attribute-requests": "属性要求",
  864 + "add-attribute-request": "属性要求を追加する",
  865 + "attribute-updates": "属性の更新",
  866 + "add-attribute-update": "属性の更新を追加する",
  867 + "server-side-rpc": "サーバー側RPC",
  868 + "add-server-side-rpc-request": "サーバー側RPC要求を追加する",
  869 + "device-name-filter": "デバイス名フィルタ",
  870 + "attribute-filter": "属性フィルタ",
  871 + "method-filter": "方法フィルター",
  872 + "request-topic-expression": "トピック表現を要求する",
  873 + "response-timeout": "応答タイムアウト(ミリ秒)",
  874 + "topic-expression": "トピック表現",
  875 + "client-scope": "クライアントスコープ",
  876 + "add-device": "デバイスを追加",
  877 + "opc-server": "サーバー",
  878 + "opc-add-server": "サーバーを追加",
  879 + "opc-add-server-prompt": "サーバーを追加してください",
  880 + "opc-application-name": "アプリケーション名",
  881 + "opc-application-uri": "アプリケーションURI",
  882 + "opc-scan-period-in-seconds": "スキャン時間(秒)",
  883 + "opc-security": "セキュリティ",
  884 + "opc-identity": "身元",
  885 + "opc-keystore": "キーストア",
  886 + "opc-type": "タイプ",
  887 + "opc-keystore-type": "タイプ",
  888 + "opc-keystore-location": "ロケーション*",
  889 + "opc-keystore-password": "パスワード",
  890 + "opc-keystore-alias": "エイリアス",
  891 + "opc-keystore-key-password": "キーのパスワード",
  892 + "opc-device-node-pattern": "デバイスノードパターン",
  893 + "opc-device-name-pattern": "デバイス名パターン",
  894 + "modbus-server": "サーバー/スレーブ",
  895 + "modbus-add-server": "サーバー/スレーブを追加する",
  896 + "modbus-add-server-prompt": "サーバー/スレーブを追加してください",
  897 + "modbus-transport": "輸送",
  898 + "modbus-port-name": "シリアルポート名",
  899 + "modbus-encoding": "エンコーディング",
  900 + "modbus-parity": "パリティ",
  901 + "modbus-baudrate": "ボーレート",
  902 + "modbus-databits": "データビット",
  903 + "modbus-stopbits": "ストップビット",
  904 + "modbus-databits-range": "データビットは7〜8の範囲内にある必要があります。",
  905 + "modbus-stopbits-range": "ストップビットは1〜2の範囲内でなければなりません。",
  906 + "modbus-unit-id": "ユニットID",
  907 + "modbus-unit-id-range": "ユニットIDは1〜247の範囲で指定してください。",
  908 + "modbus-device-name": "装置名",
  909 + "modbus-poll-period": "投票期間(ミリ秒)",
  910 + "modbus-attributes-poll-period": "属性のポーリング期間(ミリ秒)",
  911 + "modbus-timeseries-poll-period": "時系列ポーリング期間(ミリ秒)",
  912 + "modbus-poll-period-range": "投票期間は正の値でなければなりません。",
  913 + "modbus-tag": "タグ",
  914 + "modbus-function": "関数",
  915 + "modbus-register-address": "登録アドレス",
  916 + "modbus-register-address-range": "レジスタのアドレスは0〜65535の範囲内である必要があります。",
  917 + "modbus-register-bit-index": "ビットインデックス",
  918 + "modbus-register-bit-index-range": "ビットインデックスは0〜15の範囲内である必要があります。",
  919 + "modbus-register-count": "レジスタ数",
  920 + "modbus-register-count-range": "レジスタ数は正の値でなければなりません。",
  921 + "modbus-byte-order": "バイト順",
  922 +
  923 + "sync": {
  924 + "status": "状態",
  925 + "sync": "同期",
  926 + "not-sync": "同期しない",
  927 + "last-sync-time": "前回の同期時間",
  928 + "not-available": "利用不可"
  929 + },
  930 +
  931 + "export-extensions-configuration": "エクステンション設定のエクスポート",
  932 + "import-extensions-configuration": "エクステンション設定のインポート",
  933 + "import-extensions": "拡張機能のインポート",
  934 + "import-extension": "インポート拡張",
  935 + "export-extension": "輸出延長",
  936 + "file": "拡張機能ファイル",
  937 + "invalid-file-error": "無効な拡張ファイル"
  938 + },
  939 + "fullscreen": {
  940 + "expand": "フルスクリーンに拡大",
  941 + "exit": "全画面表示を終了",
  942 + "toggle": "フルスクリーンモードを切り替える",
  943 + "fullscreen": "全画面表示"
  944 + },
  945 + "function": {
  946 + "function": "関数"
  947 + },
  948 + "grid": {
  949 + "delete-item-title": "このアイテムを削除してもよろしいですか?",
  950 + "delete-item-text": "注意してください。確認後、この項目と関連するすべてのデータは回復不能になります。",
  951 + "delete-items-title": "{ count, plural, 1 {1 item} other {# items} }?",
  952 + "delete-items-action-title": "{ count, plural, 1 {1 item} other {# items} }",
  953 + "delete-items-text": "注意してください。確認後、選択したすべてのアイテムが削除され、関連するすべてのデータは回復不能になります。",
  954 + "add-item-text": "新しいアイテムを追加",
  955 + "no-items-text": "項目は見つかりませんでした",
  956 + "item-details": "商品詳細",
  957 + "delete-item": "アイテムを削除",
  958 + "delete-items": "アイテムを削除する",
  959 + "scroll-to-top": "トップにスクロールします"
  960 + },
  961 + "help": {
  962 + "goto-help-page": "ヘルプページに行く"
  963 + },
  964 + "home": {
  965 + "home": "ホーム",
  966 + "profile": "プロフィール",
  967 + "logout": "ログアウト",
  968 + "menu": "メニュー",
  969 + "avatar": "アバター",
  970 + "open-user-menu": "ユーザーメニューを開く"
  971 + },
  972 + "import": {
  973 + "no-file": "ファイルが選択されていません",
  974 + "drop-file": "JSONファイルをドロップするか、アップロードするファイルをクリックして選択します。"
  975 + },
  976 + "item": {
  977 + "selected": "選択された"
  978 + },
  979 + "js-func": {
  980 + "no-return-error": "関数は値を返す必要があります!",
  981 + "return-type-mismatch": "'{{type}}'タイプ!",
  982 + "tidy": "きちんとした"
  983 + },
  984 + "key-val": {
  985 + "key": "キー",
  986 + "value": "値",
  987 + "remove-entry": "エントリを削除",
  988 + "add-entry": "エントリを追加",
  989 + "no-data": "エントリなし"
  990 + },
  991 + "layout": {
  992 + "layout": "レイアウト",
  993 + "manage": "レイアウトの管理",
  994 + "settings": "レイアウト設定",
  995 + "color": "色",
  996 + "main": "メイン",
  997 + "right": "右",
  998 + "select": "ターゲットレイアウトを選択"
  999 + },
  1000 + "legend": {
  1001 + "position": "伝説の位置",
  1002 + "show-max": "最大値を表示",
  1003 + "show-min": "最小値を表示する",
  1004 + "show-avg": "平均値を表示",
  1005 + "show-total": "合計値を表示",
  1006 + "settings": "凡例の設定",
  1007 + "min": "分",
  1008 + "max": "最大",
  1009 + "avg": "平均",
  1010 + "total": "合計"
  1011 + },
  1012 + "login": {
  1013 + "login": "ログイン",
  1014 + "request-password-reset": "リクエストパスワードのリセット",
  1015 + "reset-password": "パスワードを再設定する",
  1016 + "create-password": "パスワードの作成",
  1017 + "passwords-mismatch-error": "入力されたパスワードは同じでなければなりません!",
  1018 + "password-again": "パスワードをもう一度",
  1019 + "sign-in": "サインインしてください",
  1020 + "username": "ユーザー名(電子メール)",
  1021 + "remember-me": "私を覚えてますか",
  1022 + "forgot-password": "パスワードをお忘れですか?",
  1023 + "password-reset": "パスワードのリセット",
  1024 + "new-password": "新しいパスワード",
  1025 + "new-password-again": "新しいパスワードを再入力",
  1026 + "password-link-sent-message": "パスワードリセットリンクが正常に送信されました!",
  1027 + "email": "Eメール"
  1028 + },
  1029 + "position": {
  1030 + "top": "上",
  1031 + "bottom": "ボトム",
  1032 + "left": "左",
  1033 + "right": "右"
  1034 + },
  1035 + "profile": {
  1036 + "profile": "プロフィール",
  1037 + "change-password": "パスワードを変更する",
  1038 + "current-password": "現在のパスワード"
  1039 + },
  1040 + "relation": {
  1041 + "relations": "関係",
  1042 + "direction": "方向",
  1043 + "search-direction": {
  1044 + "FROM": "から",
  1045 + "TO": "に"
  1046 + },
  1047 + "direction-type": {
  1048 + "FROM": "から",
  1049 + "TO": "に"
  1050 + },
  1051 + "from-relations": "アウトバウンド関係",
  1052 + "to-relations": "インバウンド関係",
  1053 + "selected-relations": "{ count, plural, 1 {1 relation} other {# relations} }選択された",
  1054 + "type": "タイプ",
  1055 + "to-entity-type": "エンティティタイプへ",
  1056 + "to-entity-name": "エンティティ名に",
  1057 + "from-entity-type": "エンティティタイプから",
  1058 + "from-entity-name": "エンティティ名から",
  1059 + "to-entity": "実体へ",
  1060 + "from-entity": "エンティティから",
  1061 + "delete": "関係を削除する",
  1062 + "relation-type": "関係タイプ",
  1063 + "relation-type-required": "関係タイプが必要です。",
  1064 + "any-relation-type": "いかなるタイプ",
  1065 + "add": "関係を追加する",
  1066 + "edit": "関係を編集する",
  1067 + "delete-to-relation-title": "'{{entityName}}'?",
  1068 + "delete-to-relation-text": "'{{entityName}}'現在のエンティティとは無関係です。",
  1069 + "delete-to-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?",
  1070 + "delete-to-relations-text": "注意してください。確認後、選択されたリレーションはすべて削除され、対応するエンティティは現在のエンティティとは無関係になります。",
  1071 + "delete-from-relation-title": "'{{entityName}}'?",
  1072 + "delete-from-relation-text": "'{{entityName}}'.",
  1073 + "delete-from-relations-title": "{ count, plural, 1 {1 relation} other {# relations} }?",
  1074 + "delete-from-relations-text": "注意してください。確認後、選択されたリレーションはすべて削除され、現在のエンティティは対応するエンティティとは無関係になります。",
  1075 + "remove-relation-filter": "関係フィルタを削除する",
  1076 + "add-relation-filter": "関係フィルタを追加する",
  1077 + "any-relation": "関係",
  1078 + "relation-filters": "関係フィルタ",
  1079 + "additional-info": "追加情報(JSON)",
  1080 + "invalid-additional-info": "追加情報jsonを解析できません。"
  1081 + },
  1082 + "rulechain": {
  1083 + "rulechain": "ルールチェーン",
  1084 + "rulechains": "ルールチェーン",
  1085 + "root": "ルート",
  1086 + "delete": "ルールチェーンの削除",
  1087 + "name": "名",
  1088 + "name-required": "名前は必須です。",
  1089 + "description": "説明",
  1090 + "add": "ルールチェーンを追加する",
  1091 + "set-root": "ルールチェーンのルートを作る",
  1092 + "set-root-rulechain-title": "'{{ruleChainName}}'ルート?",
  1093 + "set-root-rulechain-text": "確認後、ルールチェーンはルートになり、すべての受信トランスポートメッセージを処理します。",
  1094 + "delete-rulechain-title": "'{{ruleChainName}}'?",
  1095 + "delete-rulechain-text": "確認後、ルールチェーンと関連するすべてのデータが回復不能になるので注意してください。",
  1096 + "delete-rulechains-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }?",
  1097 + "delete-rulechains-action-title": "{ count, plural, 1 {1 rule chain} other {# rule chains} }",
  1098 + "delete-rulechains-text": "確認後、選択したすべてのルールチェーンが削除され、関連するすべてのデータが回復不能になるので注意してください。",
  1099 + "add-rulechain-text": "新しいルールチェーンを追加する",
  1100 + "no-rulechains-text": "ルールチェーンが見つかりません",
  1101 + "rulechain-details": "ルールチェーンの詳細",
  1102 + "details": "詳細",
  1103 + "events": "イベント",
  1104 + "system": "システム",
  1105 + "import": "ルールチェーンのインポート",
  1106 + "export": "ルールチェーンのエクスポート",
  1107 + "export-failed-error": "{{error}}",
  1108 + "create-new-rulechain": "新しいルールチェーンを作成する",
  1109 + "rulechain-file": "ルールチェーンファイル",
  1110 + "invalid-rulechain-file-error": "ルールチェーンをインポートできません:ルールチェーンのデータ構造が無効です。",
  1111 + "copyId": "ルールチェーンIDのコピー",
  1112 + "idCopiedMessage": "ルールチェーンIDがクリップボードにコピーされました",
  1113 + "select-rulechain": "ルールチェーンの選択",
  1114 + "no-rulechains-matching": "'{{entity}}'発見されました。",
  1115 + "rulechain-required": "ルールチェーンが必要です",
  1116 + "management": "ルール管理",
  1117 + "debug-mode": "デバッグモード"
  1118 + },
  1119 + "rulenode": {
  1120 + "details": "詳細",
  1121 + "events": "イベント",
  1122 + "search": "検索ノード",
  1123 + "open-node-library": "オープンノードライブラリ",
  1124 + "add": "ルールノードを追加する",
  1125 + "name": "名",
  1126 + "name-required": "名前は必須です。",
  1127 + "type": "タイプ",
  1128 + "description": "説明",
  1129 + "delete": "ルールノードを削除",
  1130 + "select-all-objects": "すべてのノードと接続を選択する",
  1131 + "deselect-all-objects": "すべてのノードと接続の選択を解除する",
  1132 + "delete-selected-objects": "選択したノードと接続を削除する",
  1133 + "delete-selected": "選択を削除します",
  1134 + "select-all": "すべて選択",
  1135 + "copy-selected": "選択したコピー",
  1136 + "deselect-all": "すべての選択を解除",
  1137 + "rulenode-details": "ルールノードの詳細",
  1138 + "debug-mode": "デバッグモード",
  1139 + "configuration": "構成",
  1140 + "link": "リンク",
  1141 + "link-details": "ルールノードのリンクの詳細",
  1142 + "add-link": "リンクを追加",
  1143 + "link-label": "リンクラベル",
  1144 + "link-label-required": "リンクラベルが必要です。",
  1145 + "custom-link-label": "カスタムリンクラベル",
  1146 + "custom-link-label-required": "カスタムリンクラベルが必要です。",
  1147 + "link-labels": "リンクラベル",
  1148 + "link-labels-required": "リンクラベルが必要です。",
  1149 + "no-link-labels-found": "リンクラベルが見つかりません",
  1150 + "no-link-label-matching": "'{{label}}'見つかりません。",
  1151 + "create-new-link-label": "新しいものを作成してください!",
  1152 + "type-filter": "フィルタ",
  1153 + "type-filter-details": "設定された条件で着信メッセージをフィルタリングする",
  1154 + "type-enrichment": "豊かな",
  1155 + "type-enrichment-details": "メッセージメタデータに追加情報を追加する",
  1156 + "type-transformation": "変換",
  1157 + "type-transformation-details": "メッセージペイロードとメタデータの変更",
  1158 + "type-action": "アクション",
  1159 + "type-action-details": "特別なアクションを実行する",
  1160 + "type-external": "外部",
  1161 + "type-external-details": "外部システムとの相互作用",
  1162 + "type-rule-chain": "ルールチェーン",
  1163 + "type-rule-chain-details": "受信したメッセージを指定したルールチェーンに転送する",
  1164 + "type-input": "入力",
  1165 + "type-input-details": "ルールチェーンの論理入力、次の関連ルールノードへの着信メッセージの転送",
  1166 + "type-unknown": "未知の",
  1167 + "type-unknown-details": "未解決のルールノード",
  1168 + "directive-is-not-loaded": "'{{directiveName}}'利用できません。",
  1169 + "ui-resources-load-error": "構成UIリソースをロードできませんでした。",
  1170 + "invalid-target-rulechain": "ターゲットルールチェーンを解決できません!",
  1171 + "test-script-function": "テストスクリプト機能",
  1172 + "message": "メッセージ",
  1173 + "message-type": "メッセージタイプ",
  1174 + "select-message-type": "メッセージタイプを選択",
  1175 + "message-type-required": "メッセージタイプは必須です",
  1176 + "metadata": "メタデータ",
  1177 + "metadata-required": "メタデータのエントリを空にすることはできません。",
  1178 + "output": "出力",
  1179 + "test": "テスト",
  1180 + "help": "助けて"
  1181 + },
  1182 + "tenant": {
  1183 + "tenant": "テナント",
  1184 + "tenants": "テナント",
  1185 + "management": "テナント管理",
  1186 + "add": "テナントを追加",
  1187 + "admins": "管理者",
  1188 + "manage-tenant-admins": "テナント管理者の管理",
  1189 + "delete": "テナントの削除",
  1190 + "add-tenant-text": "新しいテナントを追加する",
  1191 + "no-tenants-text": "テナントは見つかりませんでした",
  1192 + "tenant-details": "テナントの詳細",
  1193 + "delete-tenant-title": "'{{tenantTitle}}'?",
  1194 + "delete-tenant-text": "確認後、テナントと関連するすべてのデータが回復不能になるので注意してください。",
  1195 + "delete-tenants-title": "{ count, plural, 1 {1 tenant} other {# tenants} }?",
  1196 + "delete-tenants-action-title": "{ count, plural, 1 {1 tenant} other {# tenants} }",
  1197 + "delete-tenants-text": "注意してください。確認後、選択されたすべてのテナントが削除され、関連するすべてのデータは回復不能になります。",
  1198 + "title": "タイトル",
  1199 + "title-required": "タイトルは必須です。",
  1200 + "description": "説明",
  1201 + "details": "詳細",
  1202 + "events": "イベント",
  1203 + "copyId": "テナントIDをコピーする",
  1204 + "idCopiedMessage": "テナントIDがクリップボードにコピーされました",
  1205 + "select-tenant": "テナントを選択",
  1206 + "no-tenants-matching": "'{{entity}}'発見されました。",
  1207 + "tenant-required": "テナントが必要です"
  1208 + },
  1209 + "timeinterval": {
  1210 + "seconds-interval": "{ seconds, select, 1 {1 second} other {# seconds} }",
  1211 + "minutes-interval": "{ minutes, select, 1 {1 minute} other {# minutes} }",
  1212 + "hours-interval": "{ hours, select, 1 {1 hour} other {# hours} }",
  1213 + "days-interval": "{ days, select, 1 {1 day} other {# days} }",
  1214 + "days": "日々",
  1215 + "hours": "時間",
  1216 + "minutes": "分",
  1217 + "seconds": "秒",
  1218 + "advanced": "上級"
  1219 + },
  1220 + "timewindow": {
  1221 + "days": "{ days, select, 1 { day } other {# days } }",
  1222 + "hours": "{ hours, select, 0 { hour } 1 {1 hour } other {# hours } }",
  1223 + "minutes": "{ minutes, select, 0 { minute } 1 {1 minute } other {# minutes } }",
  1224 + "seconds": "{ seconds, select, 0 { second } 1 {1 second } other {# seconds } }",
  1225 + "realtime": "リアルタイム",
  1226 + "history": "歴史",
  1227 + "last-prefix": "最終",
  1228 + "period": "{{ startTime }}{{ endTime }}",
  1229 + "edit": "タイムウィンドウを編集",
  1230 + "date-range": "期間",
  1231 + "last": "最終",
  1232 + "time-period": "期間"
  1233 + },
  1234 + "user": {
  1235 + "user": "ユーザー",
  1236 + "users": "ユーザー",
  1237 + "customer-users": "顧客ユーザー",
  1238 + "tenant-admins": "テナント管理者",
  1239 + "sys-admin": "システム管理者",
  1240 + "tenant-admin": "テナント管理者",
  1241 + "customer": "顧客",
  1242 + "anonymous": "匿名",
  1243 + "add": "ユーザーを追加する",
  1244 + "delete": "ユーザーを削除",
  1245 + "add-user-text": "新しいユーザーを追加",
  1246 + "no-users-text": "ユーザが見つかりませんでした",
  1247 + "user-details": "ユーザーの詳細",
  1248 + "delete-user-title": "'{{userEmail}}'?",
  1249 + "delete-user-text": "確認後、ユーザーと関連するすべてのデータが回復不能になるので注意してください。",
  1250 + "delete-users-title": "{ count, plural, 1 {1 user} other {# users} }?",
  1251 + "delete-users-action-title": "{ count, plural, 1 {1 user} other {# users} }",
  1252 + "delete-users-text": "注意してください。確認後、選択したすべてのユーザーが削除され、関連するすべてのデータは回復不能になります。",
  1253 + "activation-email-sent-message": "アクティベーション電子メールが正常に送信されました!",
  1254 + "resend-activation": "アクティブ化を再送",
  1255 + "email": "Eメール",
  1256 + "email-required": "電子メールが必要です。",
  1257 + "invalid-email-format": "メールフォーマットが無効です。",
  1258 + "first-name": "ファーストネーム",
  1259 + "last-name": "苗字",
  1260 + "description": "説明",
  1261 + "default-dashboard": "デフォルトのダッシュボード",
  1262 + "always-fullscreen": "常に全画面表示",
  1263 + "select-user": "ユーザーを選択",
  1264 + "no-users-matching": "'{{entity}}'発見されました。",
  1265 + "user-required": "ユーザーは必須です",
  1266 + "activation-method": "起動方法",
  1267 + "display-activation-link": "アクティブ化リンクを表示する",
  1268 + "send-activation-mail": "アクティベーションメールを送信する",
  1269 + "activation-link": "ユーザーアクティベーションリンク",
  1270 + "activation-link-text": "<a href='{{activationLink}}' target='_blank'>activation link</a> :",
  1271 + "copy-activation-link": "アクティブ化リンクをコピーする",
  1272 + "activation-link-copied-message": "ユーザーのアクティベーションリンクがクリップボードにコピーされました",
  1273 + "details": "詳細"
  1274 + },
  1275 + "value": {
  1276 + "type": "値のタイプ",
  1277 + "string": "文字列",
  1278 + "string-value": "文字列値",
  1279 + "integer": "整数",
  1280 + "integer-value": "整数値",
  1281 + "invalid-integer-value": "整数値が無効です",
  1282 + "double": "ダブル",
  1283 + "double-value": "二重価値",
  1284 + "boolean": "ブール",
  1285 + "boolean-value": "ブール値",
  1286 + "false": "偽",
  1287 + "true": "真",
  1288 + "long": "長いです"
  1289 + },
  1290 + "widget": {
  1291 + "widget-library": "ウィジェットライブラリ",
  1292 + "widget-bundle": "ウィジェットバンドル",
  1293 + "select-widgets-bundle": "ウィジェットのバンドルを選択",
  1294 + "management": "ウィジェット管理",
  1295 + "editor": "ウィジェットエディタ",
  1296 + "widget-type-not-found": "ウィジェットの設定を読み込む際に問題が発生しました。<br>おそらく関連付けられているウィジェットのタイプが削除されています。",
  1297 + "widget-type-load-error": "次のエラーのためにウィジェットが読み込まれませんでした:",
  1298 + "remove": "ウィジェットを削除",
  1299 + "edit": "ウィジェットの編集",
  1300 + "remove-widget-title": "'{{widgetTitle}}'?",
  1301 + "remove-widget-text": "確認後、ウィジェットと関連するすべてのデータは回復不能になります。",
  1302 + "timeseries": "時系列",
  1303 + "search-data": "検索データ",
  1304 + "no-data-found": "何もデータが見つかりませんでした",
  1305 + "latest-values": "最新の値",
  1306 + "rpc": "コントロールウィジェット",
  1307 + "alarm": "アラームウィジェット",
  1308 + "static": "静的ウィジェット",
  1309 + "select-widget-type": "ウィジェットタイプを選択",
  1310 + "missing-widget-title-error": "ウィジェットのタイトルを指定する必要があります!",
  1311 + "widget-saved": "ウィジェットが保存されました",
  1312 + "unable-to-save-widget-error": "ウィジェットを保存できません!ウィジェットにエラーがあります!",
  1313 + "save": "ウィジェットを保存",
  1314 + "saveAs": "ウィジェットを次のように保存する",
  1315 + "save-widget-type-as": "ウィジェットタイプを次のように保存します",
  1316 + "save-widget-type-as-text": "新しいウィジェットのタイトルを入力したり、ターゲットウィジェットのバンドルを選択してください",
  1317 + "toggle-fullscreen": "フルスクリーン切り替え",
  1318 + "run": "ウィジェットを実行する",
  1319 + "title": "ウィジェットのタイトル",
  1320 + "title-required": "ウィジェットのタイトルが必要です。",
  1321 + "type": "ウィジェットタイプ",
  1322 + "resources": "リソース",
  1323 + "resource-url": "JavaScript / CSS URL",
  1324 + "remove-resource": "リソースを削除する",
  1325 + "add-resource": "リソースを追加",
  1326 + "html": "HTML",
  1327 + "tidy": "きちんとした",
  1328 + "css": "CSS",
  1329 + "settings-schema": "設定スキーマ",
  1330 + "datakey-settings-schema": "データキー設定のスキーマ",
  1331 + "javascript": "Javascript",
  1332 + "remove-widget-type-title": "'{{widgetName}}'?",
  1333 + "remove-widget-type-text": "確認後、ウィジェットのタイプと関連するすべてのデータは回復不能になります。",
  1334 + "remove-widget-type": "ウィジェットタイプを削除",
  1335 + "add-widget-type": "新しいウィジェットタイプを追加する",
  1336 + "widget-type-load-failed-error": "ウィジェットタイプの読み込みに失敗しました!",
  1337 + "widget-template-load-failed-error": "ウィジェットテンプレートを読み込めませんでした!",
  1338 + "add": "ウィジェットを追加",
  1339 + "undo": "ウィジェットの変更を元に戻す",
  1340 + "export": "ウィジェットの書き出し"
  1341 + },
  1342 + "widget-action": {
  1343 + "header-button": "ウィジェットのヘッダーボタン",
  1344 + "open-dashboard-state": "新しいダッシュボードの状態に移動する",
  1345 + "update-dashboard-state": "現在のダッシュボードの状態を更新する",
  1346 + "open-dashboard": "他のダッシュボードに移動する",
  1347 + "custom": "カスタムアクション",
  1348 + "target-dashboard-state": "ターゲットダッシュボードの状態",
  1349 + "target-dashboard-state-required": "ターゲットダッシュボードの状態が必要です",
  1350 + "set-entity-from-widget": "エンティティをウィジェットから設定する",
  1351 + "target-dashboard": "ターゲットダッシュボード",
  1352 + "open-right-layout": "右ダッシュボードレイアウトを開く(モバイルビュー)"
  1353 + },
  1354 + "widgets-bundle": {
  1355 + "current": "現在のバンドル",
  1356 + "widgets-bundles": "ウィジェットバンドル",
  1357 + "add": "ウィジェットのバンドルを追加",
  1358 + "delete": "ウィジェットのバンドルを削除する",
  1359 + "title": "タイトル",
  1360 + "title-required": "タイトルは必須です。",
  1361 + "add-widgets-bundle-text": "新しいウィジェットのバンドルを追加する",
  1362 + "no-widgets-bundles-text": "ウィジェットバンドルが見つかりません",
  1363 + "empty": "ウィジェットのバンドルが空です",
  1364 + "details": "詳細",
  1365 + "widgets-bundle-details": "ウィジェットのバンドルの詳細",
  1366 + "delete-widgets-bundle-title": "'{{widgetsBundleTitle}}'?",
  1367 + "delete-widgets-bundle-text": "確認後、ウィジェットはバンドルされ、関連するすべてのデータは回復不能になります。",
  1368 + "delete-widgets-bundles-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }?",
  1369 + "delete-widgets-bundles-action-title": "{ count, plural, 1 {1 widgets bundle} other {# widgets bundles} }",
  1370 + "delete-widgets-bundles-text": "確認後、選択したすべてのウィジェットバンドルは削除され、関連するすべてのデータは回復不能になります。",
  1371 + "no-widgets-bundles-matching": "'{{widgetsBundle}}'発見されました。",
  1372 + "widgets-bundle-required": "ウィジェットバンドルが必要です。",
  1373 + "system": "システム",
  1374 + "import": "インポートウィジェットバンドル",
  1375 + "export": "ウィジェットのエクスポートバンドル",
  1376 + "export-failed-error": "{{error}}",
  1377 + "create-new-widgets-bundle": "新しいウィジェットバンドルを作成する",
  1378 + "widgets-bundle-file": "ウィジェットのバンドルファイル",
  1379 + "invalid-widgets-bundle-file-error": "ウィジェットをインポートできません。bundle:データ構造が無効です。"
  1380 + },
  1381 + "widget-config": {
  1382 + "data": "データ",
  1383 + "settings": "設定",
  1384 + "advanced": "上級",
  1385 + "title": "タイトル",
  1386 + "general-settings": "一般設定",
  1387 + "display-title": "タイトルを表示",
  1388 + "drop-shadow": "影を落とす",
  1389 + "enable-fullscreen": "フルスクリーンを有効にする",
  1390 + "background-color": "背景色",
  1391 + "text-color": "テキストの色",
  1392 + "padding": "パディング",
  1393 + "margin": "マージン",
  1394 + "widget-style": "ウィジェットスタイル",
  1395 + "title-style": "タイトルスタイル",
  1396 + "mobile-mode-settings": "モバイルモードの設定",
  1397 + "order": "注文",
  1398 + "height": "高さ",
  1399 + "units": "値の隣に表示する特別なシンボル",
  1400 + "decimals": "浮動小数点の後の桁数",
  1401 + "timewindow": "タイムウィンドウ",
  1402 + "use-dashboard-timewindow": "ダッシュボードのタイムウィンドウを使用する",
  1403 + "display-legend": "伝説を表示",
  1404 + "datasources": "データソース",
  1405 + "maximum-datasources": "{ count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }",
  1406 + "datasource-type": "タイプ",
  1407 + "datasource-parameters": "パラメーター",
  1408 + "remove-datasource": "データソースを削除",
  1409 + "add-datasource": "データソースを追加",
  1410 + "target-device": "ターゲットデバイス",
  1411 + "alarm-source": "アラームソース",
  1412 + "actions": "行動",
  1413 + "action": "アクション",
  1414 + "add-action": "アクションを追加",
  1415 + "search-actions": "検索アクション",
  1416 + "action-source": "アクションソース",
  1417 + "action-source-required": "アクションソースが必要です。",
  1418 + "action-name": "名",
  1419 + "action-name-required": "アクション名は必須です。",
  1420 + "action-name-not-unique": "同じ名前の別のアクションがすでに存在します。<br/>アクション名は、同じアクションソース内で一意である必要があります。",
  1421 + "action-icon": "アイコン",
  1422 + "action-type": "タイプ",
  1423 + "action-type-required": "アクションタイプが必要です。",
  1424 + "edit-action": "アクションの編集",
  1425 + "delete-action": "アクションの削除",
  1426 + "delete-action-title": "ウィジェットアクションを削除する",
  1427 + "delete-action-text": "'{{actionName}}'?"
  1428 + },
  1429 + "widget-type": {
  1430 + "import": "インポートウィジェットタイプ",
  1431 + "export": "ウィジェットのタイプをエクスポートする",
  1432 + "export-failed-error": "{{error}}",
  1433 + "create-new-widget-type": "新しいウィジェットタイプを作成する",
  1434 + "widget-type-file": "ウィジェットタイプファイル",
  1435 + "invalid-widget-type-file-error": "ウィジェットタイプをインポートできません:ウィジェットタイプのデータ構造が無効です。"
  1436 + },
  1437 + "icon": {
  1438 + "icon": "アイコン",
  1439 + "select-icon": "選択アイコン",
  1440 + "material-icons": "マテリアルアイコン",
  1441 + "show-all": "すべてのアイコンを表示する"
  1442 + },
  1443 + "custom": {
  1444 + "widget-action": {
  1445 + "action-cell-button": "アクションセルボタン",
  1446 + "row-click": "行のクリック",
  1447 + "marker-click": "マーカークリック",
  1448 + "tooltip-tag-action": "ツールチップのタグアクション"
  1449 + }
  1450 + },
  1451 + "language": {
  1452 + "language": "言語",
  1453 + "locales": {
  1454 + "en_US": "英語",
  1455 + "ko_KR": "韓国語",
  1456 + "it_IT": "イタリアの",
  1457 + "zh_CN": "中国語",
  1458 + "ru_RU": "ロシア",
  1459 + "es_ES": "スペイン語",
  1460 + "ja_JA": "日本語"
  1461 + }
  1462 + }
  1463 +}
... ...
... ... @@ -1329,11 +1329,13 @@
1329 1329 "language": "언어",
1330 1330 "locales": {
1331 1331 "en_US": "영어",
  1332 + "fr_FR": "프랑스의",
1332 1333 "ko_KR": "한글",
1333 1334 "zh_CN": "중국어",
1334 1335 "ru_RU": "러시아어",
1335 1336 "es_ES": "스페인어",
1336   - "it_IT": "이탈리아 사람"
  1337 + "it_IT": "이탈리아 사람",
  1338 + "ja_JA": "일본어"
1337 1339 }
1338 1340 }
1339   -}
\ No newline at end of file
  1341 +}
... ...
... ... @@ -1354,12 +1354,14 @@
1354 1354 "language": "Язык",
1355 1355 "locales": {
1356 1356 "en_US": "Английский",
  1357 + "fr_FR": "Французский",
1357 1358 "zh_CN": "Китайский",
1358 1359 "ko_KR": "Корейский",
1359 1360 "es_ES": "Испанский",
1360 1361 "it_IT": "Итальянский",
1361   - "ru_RU": "Русский"
  1362 + "ru_RU": "Русский",
  1363 + "ja_JA": "Японский"
1362 1364 }
1363 1365
1364 1366 }
1365   -}
\ No newline at end of file
  1367 +}
... ...
... ... @@ -1438,11 +1438,13 @@
1438 1438 "language": "语言",
1439 1439 "locales": {
1440 1440 "en_US": "英语",
  1441 + "fr_FR": "法国",
1441 1442 "ko_KR": "韩语",
1442 1443 "zh_CN": "汉语",
1443 1444 "ru_RU": "俄语",
1444 1445 "es_ES": "西班牙语",
1445   - "it_IT": "意大利"
  1446 + "it_IT": "意大利",
  1447 + "ja_JA": "日本"
1446 1448 }
1447 1449 }
1448 1450 }
... ...
... ... @@ -21,6 +21,9 @@
21 21 <md-button ng-click="onResendActivation({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{
22 22 'user.resend-activation' | translate }}
23 23 </md-button>
  24 +<md-button ng-click="onLoginAsUser({event: $event})" ng-show="!isEdit && loginAsUserEnabled" class="md-raised md-primary">{{
  25 + (isTenantAdmin() ? 'user.login-as-tenant-admin' : 'user.login-as-customer-user') | translate }}
  26 +</md-button>
24 27 <md-button ng-click="onDeleteUser({event: $event})" ng-show="!isEdit" class="md-raised md-primary">{{ 'user.delete' |
25 28 translate }}
26 29 </md-button>
... ...
... ... @@ -32,6 +32,17 @@ export default function UserController(userService, toast, $scope, $mdDialog, $d
32 32 var userActionsList = [
33 33 {
34 34 onAction: function ($event, item) {
  35 + loginAsUser(item);
  36 + },
  37 + name: function() { return $translate.instant('login.login') },
  38 + details: function() { return $translate.instant(usersType === 'tenant' ? 'user.login-as-tenant-admin' : 'user.login-as-customer-user') },
  39 + icon: "login",
  40 + isEnabled: function() {
  41 + return userService.isUserTokenAccessEnabled();
  42 + }
  43 + },
  44 + {
  45 + onAction: function ($event, item) {
35 46 vm.grid.deleteItem($event, item);
36 47 },
37 48 name: function() { return $translate.instant('action.delete') },
... ... @@ -78,6 +89,7 @@ export default function UserController(userService, toast, $scope, $mdDialog, $d
78 89
79 90 vm.displayActivationLink = displayActivationLink;
80 91 vm.resendActivation = resendActivation;
  92 + vm.loginAsUser = loginAsUser;
81 93
82 94 initController();
83 95
... ... @@ -184,4 +196,8 @@ export default function UserController(userService, toast, $scope, $mdDialog, $d
184 196 toast.showSuccess($translate.instant('user.activation-email-sent-message'));
185 197 });
186 198 }
  199 +
  200 + function loginAsUser(user) {
  201 + userService.loginAsUser(user.id.id);
  202 + }
187 203 }
... ...
... ... @@ -22,18 +22,20 @@ import userFieldsetTemplate from './user-fieldset.tpl.html';
22 22 /* eslint-enable import/no-unresolved, import/default */
23 23
24 24 /*@ngInject*/
25   -export default function UserDirective($compile, $templateCache/*, dashboardService*/) {
  25 +export default function UserDirective($compile, $templateCache, userService) {
26 26 var linker = function (scope, element) {
27 27 var template = $templateCache.get(userFieldsetTemplate);
28 28 element.html(template);
29 29
30 30 scope.isTenantAdmin = function() {
31 31 return scope.user && scope.user.authority === 'TENANT_ADMIN';
32   - }
  32 + };
33 33
34 34 scope.isCustomerUser = function() {
35 35 return scope.user && scope.user.authority === 'CUSTOMER_USER';
36   - }
  36 + };
  37 +
  38 + scope.loginAsUserEnabled = userService.isUserTokenAccessEnabled();
37 39
38 40 $compile(element.contents())(scope);
39 41 }
... ... @@ -46,6 +48,7 @@ export default function UserDirective($compile, $templateCache/*, dashboardServi
46 48 theForm: '=',
47 49 onDisplayActivationLink: '&',
48 50 onResendActivation: '&',
  51 + onLoginAsUser: '&',
49 52 onDeleteUser: '&'
50 53 }
51 54 };
... ...
... ... @@ -27,6 +27,7 @@
27 27 the-form="vm.grid.detailsForm"
28 28 on-display-activation-link="vm.displayActivationLink(event, vm.grid.detailsConfig.currentItem)"
29 29 on-resend-activation="vm.resendActivation(vm.grid.detailsConfig.currentItem)"
  30 + on-login-as-user="vm.loginAsUser(vm.grid.detailsConfig.currentItem)"
30 31 on-delete-user="vm.grid.deleteItem(event, vm.grid.detailsConfig.currentItem)"></tb-user>
31 32 </md-tab>
32 33 <md-tab ng-if="!vm.grid.detailsConfig.isDetailsEditMode && vm.grid.isTenantAdmin()" md-on-select="vm.grid.triggerResize()" label="{{ 'audit-log.audit-logs' | translate }}">
... ...