diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 0000000000..1d760fe7bf --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,88 @@ +# +# Copyright © 2016-2023 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +changelog: + exclude: + labels: + - Ignore for release + categories: + - title: 'Major Core & Rule Engine' + labels: + - 'Major Core' + - 'Major Rule Engine' + exclude: + labels: + - 'Bug' + - title: 'Major UI' + labels: + - 'Major UI' + exclude: + labels: + - 'Bug' + - title: 'Major Transport' + labels: + - 'Major Transport' + exclude: + labels: + - 'Bug' + - title: 'Major Edge' + labels: + - 'Major Edge' + exclude: + labels: + - 'Bug' + - title: 'Core & Rule Engine' + labels: + - 'Core' + - 'Rule Engine' + exclude: + labels: + - 'Bug' + - title: 'UI' + labels: + - 'UI' + exclude: + labels: + - 'Bug' + - title: 'Transport' + labels: + - 'Transport' + exclude: + labels: + - 'Bug' + - title: 'Edge' + labels: + - 'Edge' + exclude: + labels: + - 'Bug' + - title: 'Bug: Core & Rule Engine' + labels: + - 'Core' + - 'Rule Engine' + - 'Bug' + - title: 'Bug: UI' + labels: + - 'UI' + - 'Bug' + - title: 'Bug: Transport' + labels: + - 'Transport' + - 'Bug' + - title: 'Bug: Edge' + labels: + - 'Edge' + - 'Bug' diff --git a/application/pom.xml b/application/pom.xml index 33b21b3243..d398210b52 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -1,6 +1,6 @@ + diff --git a/common/actor/pom.xml b/common/actor/pom.xml index a565ed9052..9768c032ac 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -1,6 +1,6 @@ + + 4.0.0 + + org.thingsboard + 3.4.4-SNAPSHOT + common + + org.thingsboard.common + script + pom + + Thingsboard Script Invoke Commons + https://thingsboard.io + + + UTF-8 + ${basedir}/../.. + + + script-api + remote-js-client + + + diff --git a/common/script/remote-js-client/pom.xml b/common/script/remote-js-client/pom.xml new file mode 100644 index 0000000000..dc4bc12dbb --- /dev/null +++ b/common/script/remote-js-client/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + org.thingsboard.common + 3.4.4-SNAPSHOT + script + + org.thingsboard.common.script + remote-js-client + jar + + Thingsboard Server JS Client for remote JS execution + https://thingsboard.io + + + UTF-8 + ${basedir}/../../.. + + + + + org.thingsboard.common + queue + + + org.thingsboard.common.script + script-api + + + org.thingsboard.rule-engine + rule-engine-api + + + org.thingsboard.common + data + + + org.thingsboard.common + message + + + org.springframework.boot + spring-boot-starter-web + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.awaitility + awaitility + test + + + + + + thingsboard-repo-deploy + ThingsBoard Repo Deployment + https://repo.thingsboard.io/artifactory/libs-release-public + + + + diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java similarity index 91% rename from application/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java rename to common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java index 78000a6e78..025836d976 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java +++ b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/JsExecutorService.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import org.thingsboard.common.util.AbstractListeningExecutor; @Component public class JsExecutorService extends AbstractListeningExecutor { - @Value("${actors.rule.js_thread_pool_size}") + @Value("${js.remote.js_thread_pool_size:50}") private int jsExecutorThreadPoolSize; @Override diff --git a/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java new file mode 100644 index 0000000000..82c806ad4f --- /dev/null +++ b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsInvokeService.java @@ -0,0 +1,284 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.script; + +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.script.api.TbScriptException; +import org.thingsboard.script.api.js.AbstractJsInvokeService; +import org.thingsboard.script.api.js.JsScriptInfo; +import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; +import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.queue.TbQueueRequestTemplate; +import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Slf4j +@ConditionalOnExpression("'${js.evaluator:null}'=='remote' && ('${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core' || '${service.type:null}'=='tb-rule-engine')") +@Service +public class RemoteJsInvokeService extends AbstractJsInvokeService { + + @Getter + @Value("${queue.js.max_eval_requests_timeout}") + private long maxEvalRequestsTimeout; + + @Getter + @Value("${queue.js.max_requests_timeout}") + private long maxInvokeRequestsTimeout; + + @Value("${queue.js.max_exec_requests_timeout:2000}") + private long maxExecRequestsTimeout; + + @Getter + @Value("${js.remote.max_errors}") + private int maxErrors; + + @Getter + @Value("${js.remote.max_black_list_duration_sec:60}") + private int maxBlackListDurationSec; + + @Getter + @Value("${js.remote.stats.enabled:false}") + private boolean statsEnabled; + + private final ExecutorService callbackExecutor = Executors.newFixedThreadPool( + Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("js-executor-remote-callback")); + + public RemoteJsInvokeService(Optional apiUsageStateClient, Optional apiUsageClient) { + super(apiUsageStateClient, apiUsageClient); + } + + @Override + protected Executor getCallbackExecutor() { + return callbackExecutor; + } + + @Override + protected String getStatsName() { + return "Queue JS Invoke Stats"; + } + + @Scheduled(fixedDelayString = "${js.remote.stats.print_interval_ms}") + public void printStats() { + super.printStats(); + } + + @Autowired + protected TbQueueRequestTemplate, TbProtoQueueMsg> requestTemplate; + + protected final Map scriptHashToBodysMap = new ConcurrentHashMap<>(); + private final Lock scriptsLock = new ReentrantLock(); + + @PostConstruct + public void init() { + super.init(); + requestTemplate.init(); + } + + @PreDestroy + public void destroy() { + super.stop(); + if (requestTemplate != null) { + requestTemplate.stop(); + } + } + + @Override + protected ListenableFuture doEval(UUID scriptId, JsScriptInfo jsInfo, String scriptBody) { + JsInvokeProtos.JsCompileRequest jsRequest = JsInvokeProtos.JsCompileRequest.newBuilder() + .setScriptHash(jsInfo.getHash()) + .setFunctionName(jsInfo.getFunctionName()) + .setScriptBody(scriptBody).build(); + + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() + .setCompileRequest(jsRequest) + .build(); + + log.trace("Post compile request for scriptId [{}] (hash: {})", scriptId, jsInfo.getHash()); + ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); + return Futures.transform(future, response -> { + JsInvokeProtos.JsCompileResponse compilationResult = response.getValue().getCompileResponse(); + if (compilationResult.getSuccess()) { + scriptsLock.lock(); + try { + scriptInfoMap.put(scriptId, jsInfo); + scriptHashToBodysMap.put(jsInfo.getHash(), scriptBody); + } finally { + scriptsLock.unlock(); + } + return scriptId; + } else { + log.debug("[{}] (hash: {}) Failed to compile script due to [{}]: {}", scriptId, compilationResult.getScriptHash(), + compilationResult.getErrorCode().name(), compilationResult.getErrorDetails()); + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, new RuntimeException(compilationResult.getErrorDetails())); + } + }, callbackExecutor); + } + + @Override + protected ListenableFuture doInvokeFunction(UUID scriptId, JsScriptInfo jsInfo, Object[] args) { + var scriptHash = jsInfo.getHash(); + String scriptBody = scriptHashToBodysMap.get(scriptHash); + if (scriptBody == null) { + return Futures.immediateFailedFuture(new RuntimeException("No script body found for script hash [" + scriptHash + "] (script id: [" + scriptId + "])")); + } + + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = buildJsInvokeRequest(jsInfo, args, false, null); + + StopWatch stopWatch; + if (log.isTraceEnabled()) { + stopWatch = new StopWatch(); + stopWatch.start(); + } else { + stopWatch = null; + } + + UUID requestKey = UUID.randomUUID(); + ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(requestKey, jsRequestWrapper)); + return Futures.transformAsync(future, response -> { + if (log.isTraceEnabled()) { + stopWatch.stop(); + log.trace("doInvokeFunction js-response took {}ms for uuid {}", stopWatch.getTotalTimeMillis(), response.getKey()); + } + JsInvokeProtos.JsInvokeResponse invokeResult = response.getValue().getInvokeResponse(); + if (invokeResult.getSuccess()) { + return Futures.immediateFuture(invokeResult.getResult()); + } else { + return handleInvokeError(requestKey, scriptId, jsInfo, invokeResult.getErrorCode(), invokeResult.getErrorDetails(), scriptBody, args); + } + }, callbackExecutor); + } + + @NotNull + private JsInvokeProtos.RemoteJsRequest buildJsInvokeRequest(JsScriptInfo jsInfo, Object[] args, boolean includeScriptBody, String scriptBody) { + JsInvokeProtos.JsInvokeRequest.Builder jsRequestBuilder = JsInvokeProtos.JsInvokeRequest.newBuilder() + .setScriptHash(jsInfo.getHash()) + .setFunctionName(jsInfo.getFunctionName()) + .setTimeout((int) maxExecRequestsTimeout); + if (includeScriptBody) { + jsRequestBuilder.setScriptBody(scriptBody); + } + + for (Object arg : args) { + jsRequestBuilder.addArgs(arg.toString()); + } + + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() + .setInvokeRequest(jsRequestBuilder.build()) + .build(); + return jsRequestWrapper; + } + + private ListenableFuture handleInvokeError(UUID requestKey, UUID scriptId, JsScriptInfo jsInfo, + JsInvokeProtos.JsInvokeErrorCode errorCode, String errorDetails, + String scriptBody, Object[] args) { + final RuntimeException e = new RuntimeException(errorDetails); + log.debug("[{}] Failed to invoke function due to [{}]: {}", scriptId, errorCode.name(), errorDetails); + if (JsInvokeProtos.JsInvokeErrorCode.TIMEOUT_ERROR.equals(errorCode)) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.TIMEOUT, scriptBody, new TimeoutException()); + } else if (JsInvokeProtos.JsInvokeErrorCode.COMPILATION_ERROR.equals(errorCode)) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); + } else if (JsInvokeProtos.JsInvokeErrorCode.NOT_FOUND_ERROR.equals(errorCode)) { + log.debug("[{}] Remote JS executor couldn't find the script", scriptId); + if (scriptBody != null) { + JsInvokeProtos.RemoteJsRequest invokeRequestWithScriptBody = buildJsInvokeRequest(jsInfo, args, true, scriptBody); + log.debug("[{}] Sending invoke request again with script body", scriptId); + ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(requestKey, invokeRequestWithScriptBody)); + return Futures.transformAsync(future, response -> { + JsInvokeProtos.JsInvokeResponse result = response.getValue().getInvokeResponse(); + if (result.getSuccess()) { + return Futures.immediateFuture(result.getResult()); + } else { + return handleInvokeError(requestKey, scriptId, jsInfo, result.getErrorCode(), result.getErrorDetails(), null, args); + } + }, MoreExecutors.directExecutor()); + } + } + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.RUNTIME, scriptBody, e); + } + + @Override + protected void doRelease(UUID scriptId, JsScriptInfo jsInfo) throws Exception { + String scriptHash = jsInfo.getHash(); + if (scriptInfoMap.values().stream().map(JsScriptInfo::getHash).anyMatch(hash -> hash.equals(scriptHash))) { + return; + } + + JsInvokeProtos.JsReleaseRequest jsRequest = JsInvokeProtos.JsReleaseRequest.newBuilder() + .setScriptHash(scriptHash) + .setFunctionName(jsInfo.getFunctionName()).build(); + + JsInvokeProtos.RemoteJsRequest jsRequestWrapper = JsInvokeProtos.RemoteJsRequest.newBuilder() + .setReleaseRequest(jsRequest) + .build(); + + ListenableFuture> future = requestTemplate.send(new TbProtoJsQueueMsg<>(UUID.randomUUID(), jsRequestWrapper)); + if (getMaxInvokeRequestsTimeout() > 0) { + future = Futures.withTimeout(future, getMaxInvokeRequestsTimeout(), TimeUnit.MILLISECONDS, timeoutExecutorService); + } + JsInvokeProtos.RemoteJsResponse response = future.get().getValue(); + + JsInvokeProtos.JsReleaseResponse releaseResponse = response.getReleaseResponse(); + if (releaseResponse.getSuccess()) { + scriptsLock.lock(); + try { + if (scriptInfoMap.values().stream().map(JsScriptInfo::getHash).noneMatch(hash -> hash.equals(scriptHash))) { + scriptHashToBodysMap.remove(scriptHash); + } + } finally { + scriptsLock.unlock(); + } + } else { + log.debug("[{}] Failed to release script", scriptHash); + } + } + + protected String constructFunctionName(UUID scriptId, String scriptHash) { + return "invokeInternal_" + scriptHash; + } + + protected String getScriptHash(UUID scriptId) { + JsScriptInfo jsScriptInfo = scriptInfoMap.get(scriptId); + return jsScriptInfo != null ? jsScriptInfo.getHash() : null; + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java similarity index 96% rename from application/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java rename to common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java index 8e604fdac7..17ec326dd1 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java +++ b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsRequestEncoder.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,8 @@ package org.thingsboard.server.service.script; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.util.JsonFormat; -import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.gen.js.JsInvokeProtos; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.kafka.TbKafkaEncoder; import java.nio.charset.StandardCharsets; diff --git a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java similarity index 96% rename from application/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java rename to common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java index 3b647f6669..e364aa52a7 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java +++ b/common/script/remote-js-client/src/main/java/org/thingsboard/server/service/script/RemoteJsResponseDecoder.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,9 @@ package org.thingsboard.server.service.script; import com.google.protobuf.util.JsonFormat; +import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.queue.TbQueueMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.gen.js.JsInvokeProtos; import org.thingsboard.server.queue.kafka.TbKafkaDecoder; import java.io.IOException; diff --git a/common/script/script-api/pom.xml b/common/script/script-api/pom.xml new file mode 100644 index 0000000000..28bc1a4bab --- /dev/null +++ b/common/script/script-api/pom.xml @@ -0,0 +1,125 @@ + + + 4.0.0 + + org.thingsboard.common + 3.4.4-SNAPSHOT + script + + org.thingsboard.common.script + script-api + jar + + Thingsboard Server Script invoke API + https://thingsboard.io + + + UTF-8 + ${basedir}/../../.. + + + + + org.thingsboard.common + data + + + org.thingsboard.common + stats + + + org.thingsboard.common + util + + + org.javadelight + delight-nashorn-sandbox + + + com.google.code.gson + gson + + + com.github.ben-manes.caffeine + caffeine + + + org.slf4j + slf4j-api + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + + + org.springframework + spring-context + + + com.google.guava + guava + + + org.apache.commons + commons-lang3 + + + org.thingsboard + tbel + + + org.springframework.boot + spring-boot-starter-web + provided + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + test + + + org.awaitility + awaitility + test + + + + + + thingsboard-repo-deploy + ThingsBoard Repo Deployment + https://repo.thingsboard.io/artifactory/libs-release-public + + + + diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java new file mode 100644 index 0000000000..fdb13212b7 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java @@ -0,0 +1,288 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.util.Pair; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.ApiUsageRecordKey; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.String.format; + +@Slf4j +public abstract class AbstractScriptInvokeService implements ScriptInvokeService { + + protected final Map disabledScripts = new ConcurrentHashMap<>(); + + private final Optional apiUsageStateClient; + private final Optional apiUsageReportClient; + private final AtomicInteger pushedMsgs = new AtomicInteger(0); + private final AtomicInteger invokeMsgs = new AtomicInteger(0); + private final AtomicInteger evalMsgs = new AtomicInteger(0); + protected final AtomicInteger failedMsgs = new AtomicInteger(0); + protected final AtomicInteger timeoutMsgs = new AtomicInteger(0); + + private final FutureCallback evalCallback = new ScriptStatCallback<>(evalMsgs, timeoutMsgs, failedMsgs); + private final FutureCallback invokeCallback = new ScriptStatCallback<>(invokeMsgs, timeoutMsgs, failedMsgs); + + protected ScheduledExecutorService timeoutExecutorService; + + protected AbstractScriptInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { + this.apiUsageStateClient = apiUsageStateClient; + this.apiUsageReportClient = apiUsageReportClient; + } + + protected long getMaxEvalRequestsTimeout() { + return getMaxInvokeRequestsTimeout(); + } + + protected abstract long getMaxInvokeRequestsTimeout(); + + protected abstract long getMaxScriptBodySize(); + + protected abstract long getMaxTotalArgsSize(); + + protected abstract long getMaxResultSize(); + + protected abstract int getMaxBlackListDurationSec(); + + protected abstract int getMaxErrors(); + + protected abstract boolean isStatsEnabled(); + + protected abstract String getStatsName(); + + protected abstract Executor getCallbackExecutor(); + + protected abstract boolean isScriptPresent(UUID scriptId); + + protected abstract ListenableFuture doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames); + + protected abstract TbScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args); + + protected abstract void doRelease(UUID scriptId) throws Exception; + + public void init() { + if (getMaxEvalRequestsTimeout() > 0 || getMaxInvokeRequestsTimeout() > 0) { + timeoutExecutorService = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("script-timeout")); + } + } + + public void stop() { + if (timeoutExecutorService != null) { + timeoutExecutorService.shutdownNow(); + } + } + + public void printStats() { + if (isStatsEnabled()) { + int pushed = pushedMsgs.getAndSet(0); + int invoked = invokeMsgs.getAndSet(0); + int evaluated = evalMsgs.getAndSet(0); + int failed = failedMsgs.getAndSet(0); + int timedOut = timeoutMsgs.getAndSet(0); + if (pushed > 0 || invoked > 0 || evaluated > 0 || failed > 0 || timedOut > 0) { + log.info("{}: pushed [{}] received [{}] invoke [{}] eval [{}] failed [{}] timedOut [{}]", + getStatsName(), pushed, invoked + evaluated, invoked, evaluated, failed, timedOut); + } + } + } + + @Override + public ListenableFuture eval(TenantId tenantId, ScriptType scriptType, String scriptBody, String... argNames) { + if (!apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isJsExecEnabled()) { + if (scriptBodySizeExceeded(scriptBody)) { + return error(format("Script body exceeds maximum allowed size of %s symbols", getMaxScriptBodySize())); + } + UUID scriptId = UUID.randomUUID(); + pushedMsgs.incrementAndGet(); + return withTimeoutAndStatsCallback(scriptId, null, + doEvalScript(tenantId, scriptType, scriptBody, scriptId, argNames), evalCallback, getMaxEvalRequestsTimeout()); + } else { + return error("Script Execution is disabled due to API limits!"); + } + } + + @Override + public ListenableFuture invokeScript(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { + if (!apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isJsExecEnabled()) { + if (!isScriptPresent(scriptId)) { + return error("No compiled script found for scriptId: [" + scriptId + "]!"); + } + if (!isDisabled(scriptId)) { + if (argsSizeExceeded(args)) { + TbScriptException t = new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new IllegalArgumentException( + format("Script input arguments exceed maximum allowed total args size of %s symbols", getMaxTotalArgsSize()) + )); + return Futures.immediateFailedFuture(handleScriptException(scriptId, null, t)); + } + apiUsageReportClient.ifPresent(client -> client.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1)); + pushedMsgs.incrementAndGet(); + log.trace("InvokeScript uuid {} with timeout {}ms", scriptId, getMaxInvokeRequestsTimeout()); + var task = doInvokeFunction(scriptId, args); + + var resultFuture = Futures.transformAsync(task.getResultFuture(), output -> { + String result = JacksonUtil.toString(output); + if (resultSizeExceeded(result)) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException( + format("Script invocation result exceeds maximum allowed size of %s symbols", getMaxResultSize()) + )); + } + return Futures.immediateFuture(output); + }, MoreExecutors.directExecutor()); + + return withTimeoutAndStatsCallback(scriptId, task, resultFuture, invokeCallback, getMaxInvokeRequestsTimeout()); + } else { + String message = "Script invocation is blocked due to maximum error count " + + getMaxErrors() + ", scriptId " + scriptId + "!"; + log.warn(message); + return error(message); + } + } else { + return error("Script execution is disabled due to API limits!"); + } + } + + private ListenableFuture withTimeoutAndStatsCallback(UUID scriptId, TbScriptExecutionTask task, ListenableFuture future, FutureCallback statsCallback, long timeout) { + if (timeout > 0) { + future = Futures.withTimeout(future, timeout, TimeUnit.MILLISECONDS, timeoutExecutorService); + } + Futures.addCallback(future, statsCallback, getCallbackExecutor()); + return Futures.catchingAsync(future, Exception.class, + input -> Futures.immediateFailedFuture(handleScriptException(scriptId, task, input)), + MoreExecutors.directExecutor()); + } + + private Throwable handleScriptException(UUID scriptId, TbScriptExecutionTask task, Throwable t) { + boolean timeout = t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException); + if (timeout && task != null) { + task.stop(); + } + boolean blockList = timeout; + String scriptBody = null; + if (t instanceof TbScriptException) { + var scriptException = (TbScriptException) t; + scriptBody = scriptException.getBody(); + var cause = scriptException.getCause(); + switch (scriptException.getErrorCode()) { + case COMPILATION: + log.debug("[{}] Failed to compile script: {}", scriptId, scriptException.getBody(), cause); + break; + case TIMEOUT: + log.debug("[{}] Timeout to execute script: {}", scriptId, scriptException.getBody(), cause); + break; + case OTHER: + case RUNTIME: + log.debug("[{}] Failed to execute script: {}", scriptId, scriptException.getBody(), cause); + break; + } + blockList = timeout || scriptException.getErrorCode() != TbScriptException.ErrorCode.RUNTIME; + } + if (blockList) { + BlockedScriptInfo disableListInfo = disabledScripts.computeIfAbsent(scriptId, key -> new BlockedScriptInfo(getMaxBlackListDurationSec())); + int counter = disableListInfo.incrementAndGet(); + if (log.isDebugEnabled()) { + log.debug("Script has exception counter {} on disabledFunctions for id {}, exception {}, cause {}, scriptBody {}", + counter, scriptId, t, t.getCause(), scriptBody); + } else { + log.warn("Script has exception counter {} on disabledFunctions for id {}, exception {}", + counter, scriptId, t.getMessage()); + } + } + if (timeout) { + return new TimeoutException("Script timeout!"); + } else { + return t; + } + } + + @Override + public ListenableFuture release(UUID scriptId) { + if (isScriptPresent(scriptId)) { + try { + disabledScripts.remove(scriptId); + doRelease(scriptId); + } catch (Exception e) { + return Futures.immediateFailedFuture(e); + } + } + return Futures.immediateFuture(null); + } + + private boolean isDisabled(UUID scriptId) { + BlockedScriptInfo errorCount = disabledScripts.get(scriptId); + if (errorCount != null) { + if (errorCount.getExpirationTime() <= System.currentTimeMillis()) { + disabledScripts.remove(scriptId); + return false; + } else { + return errorCount.get() >= getMaxErrors(); + } + } else { + return false; + } + } + + private boolean scriptBodySizeExceeded(String scriptBody) { + if (getMaxScriptBodySize() <= 0) return false; + return scriptBody.length() > getMaxScriptBodySize(); + } + + private boolean argsSizeExceeded(Object[] args) { + if (getMaxTotalArgsSize() <= 0) return false; + long totalArgsSize = 0; + for (Object arg : args) { + if (arg instanceof CharSequence) { + totalArgsSize += ((CharSequence) arg).length(); + } else { + var str = JacksonUtil.toString(arg); + if (str != null) { + totalArgsSize += str.length(); + } + } + } + return totalArgsSize > getMaxTotalArgsSize(); + } + + private boolean resultSizeExceeded(String result) { + if (getMaxResultSize() <= 0) return false; + return result != null && result.length() > getMaxResultSize(); + } + + private ListenableFuture error(String message) { + return Futures.immediateFailedFuture(new RuntimeException(message)); + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/BlockedScriptInfo.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/BlockedScriptInfo.java new file mode 100644 index 0000000000..d49d734873 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/BlockedScriptInfo.java @@ -0,0 +1,44 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class BlockedScriptInfo { + private final long maxScriptBlockDurationMs; + private final AtomicInteger counter; + private long expirationTime; + + BlockedScriptInfo(int maxScriptBlockDuration) { + this.maxScriptBlockDurationMs = TimeUnit.SECONDS.toMillis(maxScriptBlockDuration); + this.counter = new AtomicInteger(0); + } + + public int get() { + return counter.get(); + } + + public int incrementAndGet() { + int result = counter.incrementAndGet(); + expirationTime = System.currentTimeMillis() + maxScriptBlockDurationMs; + return result; + } + + public long getExpirationTime() { + return expirationTime; + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeScriptFactory.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/RuleNodeScriptFactory.java similarity index 95% rename from application/src/main/java/org/thingsboard/server/service/script/RuleNodeScriptFactory.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/RuleNodeScriptFactory.java index 9aab3dde63..f0414aa546 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/RuleNodeScriptFactory.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/RuleNodeScriptFactory.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.script; +package org.thingsboard.script.api; public class RuleNodeScriptFactory { diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptInvokeService.java similarity index 64% rename from application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptInvokeService.java index 3e5d014bef..2a91c1fccc 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptInvokeService.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,23 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.script; +package org.thingsboard.script.api; import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.script.ScriptLanguage; import java.util.UUID; -public interface JsInvokeService { +public interface ScriptInvokeService { - ListenableFuture eval(TenantId tenantId, JsScriptType scriptType, String scriptBody, String... argNames); + ListenableFuture eval(TenantId tenantId, ScriptType scriptType, String scriptBody, String... argNames); - ListenableFuture invokeFunction(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args); + ListenableFuture invokeScript(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args); ListenableFuture release(UUID scriptId); + ScriptLanguage getLanguage(); + } diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptStatCallback.java similarity index 70% rename from application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptStatCallback.java index 75caa0511e..42131c9dc3 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsStatCallback.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptStatCallback.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,34 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.script; +package org.thingsboard.script.api; import com.google.common.util.concurrent.FutureCallback; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; +@Slf4j @AllArgsConstructor -public class JsStatCallback implements FutureCallback { - - private final AtomicInteger jsSuccessMsgs; - private final AtomicInteger jsTimeoutMsgs; - private final AtomicInteger jsFailedMsgs; +public class ScriptStatCallback implements FutureCallback { + private final AtomicInteger successMsgs; + private final AtomicInteger timeoutMsgs; + private final AtomicInteger failedMsgs; @Override public void onSuccess(@Nullable T result) { - jsSuccessMsgs.incrementAndGet(); + successMsgs.incrementAndGet(); } @Override public void onFailure(Throwable t) { if (t instanceof TimeoutException || (t.getCause() != null && t.getCause() instanceof TimeoutException)) { - jsTimeoutMsgs.incrementAndGet(); + timeoutMsgs.incrementAndGet(); } else { - jsFailedMsgs.incrementAndGet(); + failedMsgs.incrementAndGet(); } } } diff --git a/application/src/main/java/org/thingsboard/server/service/script/JsScriptType.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptType.java similarity index 82% rename from application/src/main/java/org/thingsboard/server/service/script/JsScriptType.java rename to common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptType.java index ee4b0c4c41..3da6543a43 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/JsScriptType.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/ScriptType.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.service.script; +package org.thingsboard.script.api; -public enum JsScriptType { +public enum ScriptType { RULE_NODE_SCRIPT } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptException.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptException.java new file mode 100644 index 0000000000..98221a27ea --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptException.java @@ -0,0 +1,40 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api; + +import lombok.Getter; + +import java.util.UUID; + +public class TbScriptException extends RuntimeException { + private static final long serialVersionUID = -1958193538782818284L; + + public static enum ErrorCode {COMPILATION, TIMEOUT, RUNTIME, OTHER} + + @Getter + private final UUID scriptId; + @Getter + private final ErrorCode errorCode; + @Getter + private final String body; + + public TbScriptException(UUID scriptId, ErrorCode errorCode, String body, Exception cause) { + super(cause); + this.scriptId = scriptId; + this.errorCode = errorCode; + this.body = body; + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptExecutionTask.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptExecutionTask.java new file mode 100644 index 0000000000..ac90387120 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/TbScriptExecutionTask.java @@ -0,0 +1,30 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api; + +import com.google.common.util.concurrent.ListenableFuture; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + + +@RequiredArgsConstructor +public abstract class TbScriptExecutionTask { + + @Getter + private final ListenableFuture resultFuture; + + public abstract void stop(); +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java new file mode 100644 index 0000000000..bd3c7a6cf5 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java @@ -0,0 +1,106 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.js; + +import com.google.common.hash.Hashing; +import com.google.common.util.concurrent.ListenableFuture; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.util.Pair; +import org.thingsboard.script.api.AbstractScriptInvokeService; +import org.thingsboard.script.api.RuleNodeScriptFactory; +import org.thingsboard.script.api.ScriptType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Created by ashvayka on 26.09.18. + */ +@Slf4j +public abstract class AbstractJsInvokeService extends AbstractScriptInvokeService implements JsInvokeService { + + protected final Map scriptInfoMap = new ConcurrentHashMap<>(); + + @Getter + @Value("${js.max_total_args_size:100000}") + private long maxTotalArgsSize; + @Getter + @Value("${js.max_result_size:300000}") + private long maxResultSize; + @Getter + @Value("${js.max_script_body_size:50000}") + private long maxScriptBodySize; + + protected AbstractJsInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { + super(apiUsageStateClient, apiUsageReportClient); + } + + @Override + protected boolean isScriptPresent(UUID scriptId) { + return scriptInfoMap.containsKey(scriptId); + } + + @Override + protected JsScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args) { + return new JsScriptExecutionTask(doInvokeFunction(scriptId, scriptInfoMap.get(scriptId), args)); + } + + @Override + protected ListenableFuture doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames) { + String scriptHash = hash(tenantId, scriptBody); + String functionName = constructFunctionName(scriptId, scriptHash); + String jsScript = generateJsScript(scriptType, functionName, scriptBody, argNames); + return doEval(scriptId, new JsScriptInfo(scriptHash, functionName), jsScript); + } + + @Override + protected void doRelease(UUID scriptId) throws Exception { + doRelease(scriptId, scriptInfoMap.remove(scriptId)); + } + + protected abstract ListenableFuture doEval(UUID scriptId, JsScriptInfo jsInfo, String scriptBody); + + protected abstract ListenableFuture doInvokeFunction(UUID scriptId, JsScriptInfo jsInfo, Object[] args); + + protected abstract void doRelease(UUID scriptId, JsScriptInfo scriptInfo) throws Exception; + + private String generateJsScript(ScriptType scriptType, String functionName, String scriptBody, String... argNames) { + if (scriptType == ScriptType.RULE_NODE_SCRIPT) { + return RuleNodeScriptFactory.generateRuleNodeScript(functionName, scriptBody, argNames); + } + throw new RuntimeException("No script factory implemented for scriptType: " + scriptType); + } + + protected String constructFunctionName(UUID scriptId, String scriptHash) { + return "invokeInternal_" + scriptId.toString().replace('-', '_'); + } + + protected String hash(TenantId tenantId, String scriptBody) { + return Hashing.murmur3_128().newHasher() + .putLong(tenantId.getId().getMostSignificantBits()) + .putLong(tenantId.getId().getLeastSignificantBits()) + .putUnencodedChars(scriptBody) + .hash().toString(); + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsInvokeService.java new file mode 100644 index 0000000000..cf91328368 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsInvokeService.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.js; + +import org.thingsboard.script.api.ScriptInvokeService; +import org.thingsboard.server.common.data.script.ScriptLanguage; + +public interface JsInvokeService extends ScriptInvokeService { + + @Override + default ScriptLanguage getLanguage() { + return ScriptLanguage.JS; + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptExecutionTask.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptExecutionTask.java new file mode 100644 index 0000000000..38623093ff --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptExecutionTask.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.js; + +import com.google.common.util.concurrent.ListenableFuture; +import org.thingsboard.script.api.TbScriptExecutionTask; + +public class JsScriptExecutionTask extends TbScriptExecutionTask { + + public JsScriptExecutionTask(ListenableFuture resultFuture) { + super(resultFuture); + } + + @Override + public void stop() { + // do nothing + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptInfo.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptInfo.java new file mode 100644 index 0000000000..ff71b2a8b1 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/JsScriptInfo.java @@ -0,0 +1,26 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.js; + +import lombok.Data; + +@Data +public class JsScriptInfo { + + private final String hash; + private final String functionName; + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/NashornJsInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/NashornJsInvokeService.java new file mode 100644 index 0000000000..c995474452 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/NashornJsInvokeService.java @@ -0,0 +1,179 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.js; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import delight.nashornsandbox.NashornSandbox; +import delight.nashornsandbox.NashornSandboxes; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.script.api.TbScriptException; +import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.locks.ReentrantLock; + +@Slf4j +@ConditionalOnProperty(prefix = "js", value = "evaluator", havingValue = "local", matchIfMissing = true) +@Service +public class NashornJsInvokeService extends AbstractJsInvokeService { + + private NashornSandbox sandbox; + private ScriptEngine engine; + private ExecutorService monitorExecutorService; + private ListeningExecutorService jsExecutor; + + private final ReentrantLock evalLock = new ReentrantLock(); + + @Value("${js.local.use_js_sandbox}") + private boolean useJsSandbox; + + @Value("${js.local.monitor_thread_pool_size}") + private int monitorThreadPoolSize; + + @Value("${js.local.max_cpu_time}") + private long maxCpuTime; + + @Getter + @Value("${js.local.max_errors}") + private int maxErrors; + + @Getter + @Value("${js.local.max_black_list_duration_sec:60}") + private int maxBlackListDurationSec; + + @Getter + @Value("${js.local.max_requests_timeout:0}") + private long maxInvokeRequestsTimeout; + + @Getter + @Value("${js.local.stats.enabled:false}") + private boolean statsEnabled; + + @Value("${js.local.js_thread_pool_size:50}") + private int jsExecutorThreadPoolSize; + + public NashornJsInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { + super(apiUsageStateClient, apiUsageReportClient); + } + + @Override + protected String getStatsName() { + return "Nashorn JS Invoke Stats"; + } + + @Override + protected Executor getCallbackExecutor() { + return MoreExecutors.directExecutor(); + } + + @Scheduled(fixedDelayString = "${js.local.stats.print_interval_ms:10000}") + public void printStats() { + super.printStats(); + } + + @PostConstruct + public void init() { + super.init(); + jsExecutor = MoreExecutors.listeningDecorator(Executors.newWorkStealingPool(jsExecutorThreadPoolSize)); + if (useJsSandbox) { + sandbox = NashornSandboxes.create(); + monitorExecutorService = ThingsBoardExecutors.newWorkStealingPool(monitorThreadPoolSize, "nashorn-js-monitor"); + sandbox.setExecutor(monitorExecutorService); + sandbox.setMaxCPUTime(maxCpuTime); + sandbox.allowNoBraces(false); + sandbox.allowLoadFunctions(true); + sandbox.setMaxPreparedStatements(30); + } else { + ScriptEngineManager factory = new ScriptEngineManager(); + engine = factory.getEngineByName("nashorn"); + } + } + + @PreDestroy + public void stop() { + super.stop(); + if (monitorExecutorService != null) { + monitorExecutorService.shutdownNow(); + } + } + + @Override + protected ListenableFuture doEval(UUID scriptId, JsScriptInfo scriptInfo, String jsScript) { + return jsExecutor.submit(() -> { + try { + evalLock.lock(); + try { + if (useJsSandbox) { + sandbox.eval(jsScript); + } else { + engine.eval(jsScript); + } + } finally { + evalLock.unlock(); + } + scriptInfoMap.put(scriptId, scriptInfo); + return scriptId; + } catch (Exception e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, jsScript, e); + } + }); + } + + @Override + protected ListenableFuture doInvokeFunction(UUID scriptId, JsScriptInfo scriptInfo, Object[] args) { + return jsExecutor.submit(() -> { + try { + if (useJsSandbox) { + return sandbox.getSandboxedInvocable().invokeFunction(scriptInfo.getFunctionName(), args); + } else { + return ((Invocable) engine).invokeFunction(scriptInfo.getFunctionName(), args); + } + } catch (ScriptException e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.RUNTIME, null, e); + } catch (Exception e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, e); + } + }); + } + + protected void doRelease(UUID scriptId, JsScriptInfo scriptInfo) throws ScriptException { + if (useJsSandbox) { + sandbox.eval(scriptInfo.getFunctionName() + " = undefined;"); + } else { + engine.eval(scriptInfo.getFunctionName() + " = undefined;"); + } + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java new file mode 100644 index 0000000000..7d2043557e --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -0,0 +1,236 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.google.common.hash.Hasher; +import com.google.common.hash.Hashing; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.mvel2.ExecutionContext; +import org.mvel2.MVEL; +import org.mvel2.ParserContext; +import org.mvel2.SandboxedParserConfiguration; +import org.mvel2.ScriptMemoryOverflowException; +import org.mvel2.optimizers.OptimizerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import org.thingsboard.common.util.ThingsBoardExecutors; +import org.thingsboard.script.api.AbstractScriptInvokeService; +import org.thingsboard.script.api.ScriptType; +import org.thingsboard.script.api.TbScriptException; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.stats.TbApiUsageStateClient; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.Calendar; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +@Slf4j +@ConditionalOnProperty(prefix = "tbel", value = "enabled", havingValue = "true", matchIfMissing = true) +@Service +public class DefaultTbelInvokeService extends AbstractScriptInvokeService implements TbelInvokeService { + + protected final Map scriptIdToHash = new ConcurrentHashMap<>(); + protected final Map scriptMap = new ConcurrentHashMap<>(); + protected Cache compiledScriptsCache; + + private SandboxedParserConfiguration parserConfig; + + @Getter + @Value("${tbel.max_total_args_size:100000}") + private long maxTotalArgsSize; + @Getter + @Value("${tbel.max_result_size:300000}") + private long maxResultSize; + @Getter + @Value("${tbel.max_script_body_size:50000}") + private long maxScriptBodySize; + + @Getter + @Value("${tbel.max_errors:3}") + private int maxErrors; + + @Getter + @Value("${tbel.max_black_list_duration_sec:60}") + private int maxBlackListDurationSec; + + @Getter + @Value("${tbel.max_requests_timeout:0}") + private long maxInvokeRequestsTimeout; + + @Getter + @Value("${tbel.stats.enabled:false}") + private boolean statsEnabled; + + @Value("${tbel.thread_pool_size:50}") + private int threadPoolSize; + + @Value("${tbel.max_memory_limit_mb:8}") + private long maxMemoryLimitMb; + + @Value("${tbel.compiled_scripts_cache_size:1000}") + private int compiledScriptsCacheSize; + + private ListeningExecutorService executor; + + private final Lock lock = new ReentrantLock(); + + protected DefaultTbelInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { + super(apiUsageStateClient, apiUsageReportClient); + } + + @Scheduled(fixedDelayString = "${tbel.stats.print_interval_ms:10000}") + public void printStats() { + super.printStats(); + } + + @SneakyThrows + @PostConstruct + public void init() { + super.init(); + OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE); + parserConfig = ParserContext.enableSandboxedMode(); + parserConfig.addImport("JSON", TbJson.class); + parserConfig.registerDataType("Date", TbDate.class, date -> 8L); + parserConfig.registerDataType("Random", Random.class, date -> 8L); + parserConfig.registerDataType("Calendar", Calendar.class, date -> 8L); + TbUtils.register(parserConfig); + executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "tbel-executor")); + try { + // Special command to warm up TBEL engine + Serializable script = compileScript("var warmUp = {}; warmUp"); + MVEL.executeTbExpression(script, new ExecutionContext(parserConfig), Collections.emptyMap()); + } catch (Exception e) { + // do nothing + } + compiledScriptsCache = Caffeine.newBuilder() + .maximumSize(compiledScriptsCacheSize) + .build(); + } + + @PreDestroy + public void destroy() { + if (executor != null) { + executor.shutdownNow(); + } + } + + @Override + protected String getStatsName() { + return "TBEL Scripts Stats"; + } + + @Override + protected Executor getCallbackExecutor() { + return MoreExecutors.directExecutor(); + } + + @Override + protected boolean isScriptPresent(UUID scriptId) { + return scriptIdToHash.containsKey(scriptId); + } + + @Override + protected ListenableFuture doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames) { + return executor.submit(() -> { + try { + String scriptHash = hash(scriptBody, argNames); + compiledScriptsCache.get(scriptHash, k -> compileScript(scriptBody)); + lock.lock(); + try { + scriptIdToHash.put(scriptId, scriptHash); + scriptMap.computeIfAbsent(scriptHash, k -> new TbelScript(scriptBody, argNames)); + } finally { + lock.unlock(); + } + return scriptId; + } catch (Exception e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.COMPILATION, scriptBody, e); + } + }); + } + + @Override + protected TbelScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args) { + ExecutionContext executionContext = new ExecutionContext(this.parserConfig, maxMemoryLimitMb * 1024 * 1024); + return new TbelScriptExecutionTask(executionContext, executor.submit(() -> { + String scriptHash = scriptIdToHash.get(scriptId); + if (scriptHash == null) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException("Script not found!")); + } + TbelScript script = scriptMap.get(scriptHash); + Serializable compiledScript = compiledScriptsCache.get(scriptHash, k -> compileScript(script.getScriptBody())); + try { + return MVEL.executeTbExpression(compiledScript, executionContext, script.createVars(args)); + } catch (ScriptMemoryOverflowException e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, script.getScriptBody(), new RuntimeException("Script memory overflow!")); + } catch (Exception e) { + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.RUNTIME, script.getScriptBody(), e); + } + })); + } + + @Override + protected void doRelease(UUID scriptId) { + String scriptHash = scriptIdToHash.remove(scriptId); + if (scriptHash != null) { + lock.lock(); + try { + if (!scriptIdToHash.containsValue(scriptHash)) { + scriptMap.remove(scriptHash); + compiledScriptsCache.invalidate(scriptHash); + } + } finally { + lock.unlock(); + } + } + } + + private Serializable compileScript(String scriptBody) { + return MVEL.compileExpression(scriptBody, new ParserContext()); + } + + @SuppressWarnings("UnstableApiUsage") + protected String hash(String scriptBody, String[] argNames) { + Hasher hasher = Hashing.murmur3_128().newHasher(); + hasher.putUnencodedChars(scriptBody); + for (String argName : argNames) { + hasher.putString(argName, StandardCharsets.UTF_8); + } + return hasher.hash().toString(); + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java new file mode 100644 index 0000000000..9c360e5c7e --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbDate.java @@ -0,0 +1,125 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAccessor; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +public class TbDate extends Date { + + private static final DateTimeFormatter isoDateFormatter = DateTimeFormatter.ofPattern( + "yyyy-MM-dd[[ ]['T']HH:mm[:ss[.SSS]][ ][XXX][Z][z][VV][O]]").withZone(ZoneId.systemDefault()); + + private static final DateFormat isoDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); + + public TbDate() { + super(); + } + + public TbDate(String s) { + super(parse(s)); + } + + public TbDate(long date) { + super(date); + } + + public TbDate(int year, int month, int date) { + this(year, month, date, 0, 0, 0); + } + + public TbDate(int year, int month, int date, int hrs, int min) { + this(year, month, date, hrs, min, 0); + } + + public TbDate(int year, int month, int date, + int hrs, int min, int second) { + super(new GregorianCalendar(year, month, date, hrs, min, second).getTimeInMillis()); + } + + public String toDateString() { + DateFormat formatter = DateFormat.getDateInstance(); + return formatter.format(this); + } + + public String toTimeString() { + DateFormat formatter = DateFormat.getTimeInstance(DateFormat.LONG); + return formatter.format(this); + } + + public String toISOString() { + return isoDateFormat.format(this); + } + + public String toLocaleString(String locale) { + DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.forLanguageTag(locale)); + return formatter.format(this); + } + + public String toLocaleString(String locale, String tz) { + DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, Locale.forLanguageTag(locale)); + formatter.setTimeZone(TimeZone.getTimeZone(tz)); + return formatter.format(this); + } + + public static long now() { + return System.currentTimeMillis(); + } + + public static long parse(String value, String format) { + try { + DateFormat dateFormat = new SimpleDateFormat(format); + return dateFormat.parse(value).getTime(); + } catch (Exception e) { + return -1; + } + } + + public static long parse(String value) { + try { + TemporalAccessor accessor = isoDateFormatter.parseBest(value, + ZonedDateTime::from, + LocalDateTime::from, + LocalDate::from); + Instant instant = Instant.from(accessor); + return Instant.EPOCH.until(instant, ChronoUnit.MILLIS); + } catch (Exception e) { + try { + return Date.parse(value); + } catch (IllegalArgumentException e2) { + return -1; + } + } + } + + public static long UTC(int year, int month, int date, + int hrs, int min, int sec) { + return Date.UTC(year - 1900, month, date, hrs, min, sec); + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbJson.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbJson.java new file mode 100644 index 0000000000..9c6de1422b --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbJson.java @@ -0,0 +1,61 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import com.fasterxml.jackson.databind.JsonNode; +import org.mvel2.ExecutionContext; +import org.mvel2.util.ArgsRepackUtil; +import org.thingsboard.common.util.JacksonUtil; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class TbJson { + + public static String stringify(Object value) { + return value != null ? JacksonUtil.toString(value) : "null"; + } + + public static Object parse(ExecutionContext ctx, String value) throws IOException { + if (value != null) { + JsonNode node = JacksonUtil.toJsonNode(value); + if (node.isObject()) { + return ArgsRepackUtil.repack(ctx, JacksonUtil.convertValue(node, Map.class)); + } else if (node.isArray()) { + return ArgsRepackUtil.repack(ctx, JacksonUtil.convertValue(node, List.class)); + } else if (node.isDouble()) { + return node.doubleValue(); + } else if (node.isLong()) { + return node.longValue(); + } else if (node.isInt()) { + return node.intValue(); + } else if (node.isBoolean()) { + return node.booleanValue(); + } else if (node.isTextual()) { + return node.asText(); + } else if (node.isBinary()) { + return node.binaryValue(); + } else if (node.isNull()) { + return null; + } else { + return node.asText(); + } + } else { + return null; + } + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java new file mode 100644 index 0000000000..fa75709d83 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -0,0 +1,319 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import org.mvel2.ExecutionContext; +import org.mvel2.ParserConfiguration; +import org.mvel2.execution.ExecutionArrayList; +import org.mvel2.util.MethodStub; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.List; + +public class TbUtils { + + private static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII); + + public static void register(ParserConfiguration parserConfig) throws Exception { + parserConfig.addImport("btoa", new MethodStub(TbUtils.class.getMethod("btoa", + String.class))); + parserConfig.addImport("atob", new MethodStub(TbUtils.class.getMethod("atob", + String.class))); + parserConfig.addImport("bytesToString", new MethodStub(TbUtils.class.getMethod("bytesToString", + List.class))); + parserConfig.addImport("bytesToString", new MethodStub(TbUtils.class.getMethod("bytesToString", + List.class, String.class))); + parserConfig.addImport("decodeToString", new MethodStub(TbUtils.class.getMethod("bytesToString", + List.class))); + parserConfig.addImport("decodeToJson", new MethodStub(TbUtils.class.getMethod("decodeToJson", + ExecutionContext.class, List.class))); + parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", + ExecutionContext.class, String.class))); + parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", + ExecutionContext.class, String.class, String.class))); + parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt", + String.class))); + parserConfig.addImport("parseInt", new MethodStub(TbUtils.class.getMethod("parseInt", + String.class, int.class))); + parserConfig.addImport("parseFloat", new MethodStub(TbUtils.class.getMethod("parseFloat", + String.class))); + parserConfig.addImport("parseDouble", new MethodStub(TbUtils.class.getMethod("parseDouble", + String.class))); + parserConfig.addImport("parseLittleEndianHexToInt", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToInt", + String.class))); + parserConfig.addImport("parseBigEndianHexToInt", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToInt", + String.class))); + parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", + String.class))); + parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", + String.class, boolean.class))); + parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", + List.class, int.class, int.class))); + parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", + List.class, int.class, int.class, boolean.class))); + parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", + byte[].class, int.class, int.class))); + parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt", + byte[].class, int.class, int.class, boolean.class))); + parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", + double.class, int.class))); + parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", + ExecutionContext.class, String.class))); + parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex", + String.class))); + parserConfig.addImport("base64ToBytes", new MethodStub(TbUtils.class.getMethod("base64ToBytes", + String.class))); + parserConfig.addImport("bytesToBase64", new MethodStub(TbUtils.class.getMethod("bytesToBase64", + byte[].class))); + parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex", + byte[].class))); + parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex", + ExecutionArrayList.class))); + } + + public static String btoa(String input) { + return new String(Base64.getEncoder().encode(input.getBytes())); + } + + public static String atob(String encoded) { + return new String(Base64.getDecoder().decode(encoded)); + } + + public static Object decodeToJson(ExecutionContext ctx, List bytesList) throws IOException { + return TbJson.parse(ctx, bytesToString(bytesList)); + } + + public static String bytesToString(List bytesList) { + byte[] bytes = bytesFromList(bytesList); + return new String(bytes); + } + + public static String bytesToString(List bytesList, String charsetName) throws UnsupportedEncodingException { + byte[] bytes = bytesFromList(bytesList); + return new String(bytes, charsetName); + } + + public static List stringToBytes(ExecutionContext ctx, String str) { + byte[] bytes = str.getBytes(); + return bytesToList(ctx, bytes); + } + + public static List stringToBytes(ExecutionContext ctx, String str, String charsetName) throws UnsupportedEncodingException { + byte[] bytes = str.getBytes(charsetName); + return bytesToList(ctx, bytes); + } + + private static byte[] bytesFromList(List bytesList) { + byte[] bytes = new byte[bytesList.size()]; + for (int i = 0; i < bytesList.size(); i++) { + bytes[i] = bytesList.get(i); + } + return bytes; + } + + private static List bytesToList(ExecutionContext ctx, byte[] bytes) { + List list = new ExecutionArrayList<>(ctx); + for (byte aByte : bytes) { + list.add(aByte); + } + return list; + } + + public static Integer parseInt(String value) { + if (value != null) { + try { + int radix = 10; + if (isHexadecimal(value)) { + radix = 16; + } + return Integer.parseInt(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Float f = parseFloat(value); + if (f != null) { + return f.intValue(); + } + } + } + return null; + } + + public static Integer parseInt(String value, int radix) { + if (value != null) { + try { + return Integer.parseInt(prepareNumberString(value), radix); + } catch (NumberFormatException e) { + Float f = parseFloat(value); + if (f != null) { + return f.intValue(); + } + } + } + return null; + } + + public static Float parseFloat(String value) { + if (value != null) { + try { + return Float.parseFloat(prepareNumberString(value)); + } catch (NumberFormatException e) { + } + } + return null; + } + + public static Double parseDouble(String value) { + if (value != null) { + try { + return Double.parseDouble(prepareNumberString(value)); + } catch (NumberFormatException e) { + } + } + return null; + } + + public static int parseLittleEndianHexToInt(String hex) { + return parseHexToInt(hex, false); + } + + public static int parseBigEndianHexToInt(String hex) { + return parseHexToInt(hex, true); + } + + public static int parseHexToInt(String hex) { + return parseHexToInt(hex, true); + } + + public static int parseHexToInt(String hex, boolean bigEndian) { + int length = hex.length(); + if (length > 8) { + throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); + } + if (length % 2 > 0) { + throw new IllegalArgumentException("Hex string must be even-length."); + } + byte[] data = new byte[length / 2]; + for (int i = 0; i < length; i += 2) { + data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16)); + } + return parseBytesToInt(data, 0, data.length, bigEndian); + } + + public static ExecutionArrayList hexToBytes(ExecutionContext ctx, String hex) { + int len = hex.length(); + if (len % 2 > 0) { + throw new IllegalArgumentException("Hex string must be even-length."); + } + ExecutionArrayList data = new ExecutionArrayList<>(ctx); + for (int i = 0; i < len; i += 2) { + data.add((byte)((Character.digit(hex.charAt(i), 16) << 4) + + Character.digit(hex.charAt(i + 1), 16))); + } + return data; + } + + public static String base64ToHex(String base64) { + return bytesToHex(Base64.getDecoder().decode(base64)); + } + + public static String bytesToBase64(byte[] bytes) { + return Base64.getEncoder().encodeToString(bytes); + } + + public static byte[] base64ToBytes(String input) { + return Base64.getDecoder().decode(input); + } + + public static int parseBytesToInt(List data, int offset, int length) { + return parseBytesToInt(data, offset, length, true); + } + + public static int parseBytesToInt(List data, int offset, int length, boolean bigEndian) { + final byte[] bytes = new byte[data.size()]; + for (int i = 0; i < bytes.length; i++) { + bytes[i] = data.get(i); + } + return parseBytesToInt(bytes, offset, length, bigEndian); + } + + public static int parseBytesToInt(byte[] data, int offset, int length) { + return parseBytesToInt(data, offset, length, true); + } + + public static int parseBytesToInt(byte[] data, int offset, int length, boolean bigEndian) { + if (offset > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!"); + } + if (length > 4) { + throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!"); + } + if (offset + length > data.length) { + throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!"); + } + var bb = ByteBuffer.allocate(4); + if (!bigEndian) { + bb.order(ByteOrder.LITTLE_ENDIAN); + } + bb.position(bigEndian ? 4 - length : 0); + bb.put(data, offset, length); + bb.position(0); + return bb.getInt(); + } + + public static String bytesToHex(ExecutionArrayList bytesList) { + byte[] bytes = new byte[bytesList.size()]; + for (int i = 0; i < bytesList.size(); i++) { + bytes[i] = Byte.parseByte(bytesList.get(i).toString()); + } + return bytesToHex(bytes); + } + + public static String bytesToHex(byte[] bytes) { + byte[] hexChars = new byte[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars, StandardCharsets.UTF_8); + } + + public static double toFixed(double value, int precision) { + return BigDecimal.valueOf(value).setScale(precision, RoundingMode.HALF_UP).doubleValue(); + } + + private static boolean isHexadecimal(String value) { + return value != null && (value.contains("0x") || value.contains("0X")); + } + + private static String prepareNumberString(String value) { + if (value != null) { + value = value.trim(); + if (isHexadecimal(value)) { + value = value.replace("0x", ""); + value = value.replace("0X", ""); + } + value = value.replace(",", "."); + } + return value; + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelInvokeService.java new file mode 100644 index 0000000000..c0a26f71db --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelInvokeService.java @@ -0,0 +1,28 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import org.thingsboard.script.api.ScriptInvokeService; +import org.thingsboard.server.common.data.script.ScriptLanguage; + +public interface TbelInvokeService extends ScriptInvokeService { + + @Override + default ScriptLanguage getLanguage() { + return ScriptLanguage.TBEL; + } + +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScript.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScript.java new file mode 100644 index 0000000000..3bd58b6a9b --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScript.java @@ -0,0 +1,39 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import lombok.Data; + +import java.util.HashMap; +import java.util.Map; + +@Data +public class TbelScript { + + private final String scriptBody; + private final String[] argNames; + + public Map createVars(Object[] args) { + if (args == null || args.length != argNames.length) { + throw new IllegalArgumentException("Invalid number of argument values"); + } + var result = new HashMap<>(); + for (int i = 0; i < argNames.length; i++) { + result.put(argNames[i], args[i]); + } + return result; + } +} diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScriptExecutionTask.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScriptExecutionTask.java new file mode 100644 index 0000000000..5138610050 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbelScriptExecutionTask.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import com.google.common.util.concurrent.ListenableFuture; +import org.mvel2.ExecutionContext; +import org.thingsboard.script.api.TbScriptExecutionTask; + + +public class TbelScriptExecutionTask extends TbScriptExecutionTask { + + private final ExecutionContext context; + + public TbelScriptExecutionTask(ExecutionContext context, ListenableFuture resultFuture) { + super(resultFuture); + this.context = context; + } + + @Override + public void stop(){ + context.stop(); + } +} diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java new file mode 100644 index 0000000000..f4cd610b72 --- /dev/null +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -0,0 +1,98 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.script.api.tbel; + +import org.junit.Assert; +import org.junit.Test; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +public class TbUtilsTest { + + @Test + public void parseHexToInt() { + Assert.assertEquals(0xAB, TbUtils.parseHexToInt("AB")); + Assert.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true)); + Assert.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false)); + Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true)); + Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("CCBBAA", false)); + Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("AABBCCDD", true)); + Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("DDCCBBAA", false)); + Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("DDCCBBAA", true)); + Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("AABBCCDD", false)); + } + + @Test + public void parseBytesToInt_checkPrimitives() { + int expected = 257; + byte[] data = ByteBuffer.allocate(4).putInt(expected).array(); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4)); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true)); + Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true)); + + expected = Integer.MAX_VALUE; + data = ByteBuffer.allocate(4).putInt(expected).array(); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true)); + + expected = 0xAABBCCDD; + data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}; + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true)); + data = new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA}; + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false)); + + expected = 0xAABBCC; + data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC}; + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true)); + data = new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA}; + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false)); + } + + @Test + public void parseBytesToInt_checkLists() { + int expected = 257; + List data = toList(ByteBuffer.allocate(4).putInt(expected).array()); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4)); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true)); + Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true)); + + expected = Integer.MAX_VALUE; + data = toList(ByteBuffer.allocate(4).putInt(expected).array()); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true)); + + expected = 0xAABBCCDD; + data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true)); + data = toList(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA}); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false)); + + expected = 0xAABBCC; + data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC}); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true)); + data = toList(new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA}); + Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false)); + } + + private static List toList(byte[] data) { + List result = new ArrayList<>(data.length); + for (Byte b : data) { + result.add(b); + } + return result; + } + +} diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 7648eb911a..58c949e4a4 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/allure.properties b/msa/black-box-tests/src/test/resources/allure.properties new file mode 100644 index 0000000000..f0525ba437 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/allure.properties @@ -0,0 +1,2 @@ +allure.results.directory=target/allure-results +allure.output.directory=target/allure-results \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/assetProfileForImport.json b/msa/black-box-tests/src/test/resources/assetProfileForImport.json new file mode 100644 index 0000000000..b42d77f998 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/assetProfileForImport.json @@ -0,0 +1,10 @@ +{ + "name": "Asset Profile For Import", + "description": null, + "image": null, + "defaultRuleChainId": null, + "defaultDashboardId": null, + "defaultQueueName": null, + "externalId": null, + "default": false +} \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/config.properties b/msa/black-box-tests/src/test/resources/config.properties new file mode 100644 index 0000000000..4d8a0880a9 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/config.properties @@ -0,0 +1,3 @@ +tb.baseUrl=http://localhost:8080 +tb.baseUiUrl=http://localhost:8080 +tb.wsUrl=ws://localhost:8080 \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/connectivity.xml b/msa/black-box-tests/src/test/resources/connectivity.xml new file mode 100644 index 0000000000..0db3c01577 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/connectivity.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/deviceProfileForImport.json b/msa/black-box-tests/src/test/resources/deviceProfileForImport.json new file mode 100644 index 0000000000..b2e1107945 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/deviceProfileForImport.json @@ -0,0 +1,29 @@ +{ + "name": "Device Profile For Import", + "description": "", + "image": null, + "type": "DEFAULT", + "transportType": "DEFAULT", + "provisionType": "DISABLED", + "defaultRuleChainId": null, + "defaultDashboardId": null, + "defaultQueueName": null, + "profileData": { + "configuration": { + "type": "DEFAULT" + }, + "transportConfiguration": { + "type": "DEFAULT" + }, + "provisionConfiguration": { + "type": "DISABLED", + "provisionDeviceSecret": null + }, + "alarms": null + }, + "provisionDeviceKey": null, + "firmwareId": null, + "softwareId": null, + "externalId": null, + "default": false +} \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/docker-compose.rabbitmq-server.yml b/msa/black-box-tests/src/test/resources/docker-compose.rabbitmq-server.yml index 21aba7061a..414aef5568 100644 --- a/msa/black-box-tests/src/test/resources/docker-compose.rabbitmq-server.yml +++ b/msa/black-box-tests/src/test/resources/docker-compose.rabbitmq-server.yml @@ -1,5 +1,5 @@ # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/msa/black-box-tests/src/test/resources/docker-selenium.yml b/msa/black-box-tests/src/test/resources/docker-selenium.yml new file mode 100644 index 0000000000..38a3b74bfe --- /dev/null +++ b/msa/black-box-tests/src/test/resources/docker-selenium.yml @@ -0,0 +1,37 @@ +# +# Copyright © 2016-2023 The Thingsboard Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +version: '3' +services: + selenium-chrome: + restart: always + image: selenium/standalone-chrome + ports: + - '4444:4444' + - '7900:7900' + shm_size: 2gb + environment: + SE_NODE_MAX_SESSIONS: 8 + SE_NODE_OVERRIDE_MAX_SESSIONS: 'true' + SE_NODE_SESSION_TIMEOUT: 5000 + SE_SCREEN_WIDTH: 1920 + SE_SCREEN_HEIGHT: 1080 + SE_SCREEN_DEPTH: 24 + SE_SCREEN_DPI: 74 + extra_hosts: + - "host.docker.internal:172.17.0.1" + + diff --git a/msa/black-box-tests/src/test/resources/forImport.txt b/msa/black-box-tests/src/test/resources/forImport.txt new file mode 100644 index 0000000000..2c5593320e --- /dev/null +++ b/msa/black-box-tests/src/test/resources/forImport.txt @@ -0,0 +1,16 @@ +==== + Copyright © 2016-2023 The Thingsboard Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==== + diff --git a/msa/black-box-tests/src/test/resources/logback.xml b/msa/black-box-tests/src/test/resources/logback.xml index cdf87aab92..0df6c199f4 100644 --- a/msa/black-box-tests/src/test/resources/logback.xml +++ b/msa/black-box-tests/src/test/resources/logback.xml @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/smokesProfiles.xml b/msa/black-box-tests/src/test/resources/smokesProfiles.xml new file mode 100644 index 0000000000..8173d116a4 --- /dev/null +++ b/msa/black-box-tests/src/test/resources/smokesProfiles.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/smokesRuleChain.xml b/msa/black-box-tests/src/test/resources/smokesRuleChain.xml new file mode 100644 index 0000000000..dbb22782ca --- /dev/null +++ b/msa/black-box-tests/src/test/resources/smokesRuleChain.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msa/black-box-tests/src/test/resources/uiTests.xml b/msa/black-box-tests/src/test/resources/uiTests.xml new file mode 100644 index 0000000000..f460c4398d --- /dev/null +++ b/msa/black-box-tests/src/test/resources/uiTests.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/msa/js-executor/api/httpServer.ts b/msa/js-executor/api/httpServer.ts index e1c294fdff..62372f6edd 100644 --- a/msa/js-executor/api/httpServer.ts +++ b/msa/js-executor/api/httpServer.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/msa/js-executor/api/jsExecutor.models.ts b/msa/js-executor/api/jsExecutor.models.ts index db2ced52c4..5d54fd2bc6 100644 --- a/msa/js-executor/api/jsExecutor.models.ts +++ b/msa/js-executor/api/jsExecutor.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -16,8 +16,9 @@ export interface TbMessage { - scriptIdMSB: string; - scriptIdLSB: string; + scriptIdMSB: string; // deprecated + scriptIdLSB: string; // deprecated + scriptHash: string; } export interface RemoteJsRequest { @@ -55,7 +56,7 @@ export interface JsCompileResponse extends TbMessage { export interface JsInvokeResponse { success: boolean; - result: string; + result?: string; errorCode?: number; errorDetails?: string; } diff --git a/msa/js-executor/api/jsExecutor.ts b/msa/js-executor/api/jsExecutor.ts index f22f14281b..8f38d8aabf 100644 --- a/msa/js-executor/api/jsExecutor.ts +++ b/msa/js-executor/api/jsExecutor.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/msa/js-executor/api/jsInvokeMessageProcessor.ts b/msa/js-executor/api/jsInvokeMessageProcessor.ts index 0a101775e4..836deb7d0e 100644 --- a/msa/js-executor/api/jsInvokeMessageProcessor.ts +++ b/msa/js-executor/api/jsInvokeMessageProcessor.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -18,7 +18,7 @@ import config from 'config'; import { _logger } from '../config/logger'; import { JsExecutor, TbScript } from './jsExecutor'; import { performance } from 'perf_hooks'; -import { isString, parseJsErrorDetails, toUUIDString, UUIDFromBuffer, UUIDToBits } from './utils'; +import { isString, parseJsErrorDetails, toUUIDString, UUIDFromBuffer, UUIDToBits, isNotUUID } from './utils'; import { IQueue } from '../queue/queue.models'; import { JsCompileRequest, @@ -36,13 +36,16 @@ import Long from 'long'; const COMPILATION_ERROR = 0; const RUNTIME_ERROR = 1; const TIMEOUT_ERROR = 2; +const NOT_FOUND_ERROR = 3; const statFrequency = Number(config.get('script.stat_print_frequency')); +const memoryUsageTraceFrequency = Number(config.get('script.memory_usage_trace_frequency')); const scriptBodyTraceFrequency = Number(config.get('script.script_body_trace_frequency')); const useSandbox = config.get('script.use_sandbox') === 'true'; const maxActiveScripts = Number(config.get('script.max_active_scripts')); const slowQueryLogMs = Number(config.get('script.slow_query_log_ms')); const slowQueryLogBody = config.get('script.slow_query_log_body') === 'true'; +const maxResultSize = Number(config.get('js.max_result_size')); export class JsInvokeMessageProcessor { @@ -128,7 +131,12 @@ export class JsInvokeMessageProcessor { processCompileRequest(requestId: string, responseTopic: string, headers: any, compileRequest: JsCompileRequest) { const scriptId = JsInvokeMessageProcessor.getScriptId(compileRequest); this.logger.debug('[%s] Processing compile request, scriptId: [%s]', requestId, scriptId); - + if (this.scriptMap.has(scriptId)) { + const compileResponse = JsInvokeMessageProcessor.createCompileResponse(scriptId, true); + this.logger.debug('[%s] Script was already compiled, scriptId: [%s]', requestId, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, compileResponse); + return; + } this.executor.compileScript(compileRequest.scriptBody).then( (script) => { this.cacheScript(scriptId, script); @@ -160,13 +168,27 @@ export class JsInvokeMessageProcessor { if (this.executedScriptsCounter % scriptBodyTraceFrequency == 0) { this.logger.info('[%s] Executing script body: [%s]', scriptId, invokeRequest.scriptBody); } + if (this.executedScriptsCounter % memoryUsageTraceFrequency == 0) { + this.logger.info('Current memory usage: [%s]', process.memoryUsage()); + } + this.getOrCompileScript(scriptId, invokeRequest.scriptBody).then( (script) => { this.executor.executeScript(script, invokeRequest.args, invokeRequest.timeout).then( - (result) => { - const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse(result, true); - this.logger.debug('[%s] Sending success invoke response, scriptId: [%s]', requestId, scriptId); - this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + (result: string | undefined) => { + if (!result || result.length <= maxResultSize) { + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse(result, true); + this.logger.debug('[%s] Sending success invoke response, scriptId: [%s]', requestId, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + } else { + const err = { + name: 'Error', + message: 'script invocation result exceeds maximum allowed size of ' + maxResultSize + ' symbols' + } + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, RUNTIME_ERROR, err); + this.logger.debug('[%s] Script invocation result exceeds maximum allowed size of %s symbols, scriptId: [%s]', requestId, maxResultSize, scriptId); + this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); + } }, (err: any) => { let errorCode; @@ -182,8 +204,12 @@ export class JsInvokeMessageProcessor { ) }, (err: any) => { - const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, COMPILATION_ERROR, err); - this.logger.debug('[%s] Sending failed invoke response, scriptId: [%s], errorCode: [%s]', requestId, scriptId, COMPILATION_ERROR); + let errorCode = COMPILATION_ERROR; + if (err?.name === 'script body not found') { + errorCode = NOT_FOUND_ERROR; + } + const invokeResponse = JsInvokeMessageProcessor.createInvokeResponse("", false, errorCode, err); + this.logger.debug('[%s] Sending failed invoke response, scriptId: [%s], errorCode: [%s]', requestId, scriptId, errorCode); this.sendResponse(requestId, responseTopic, headers, scriptId, undefined, invokeResponse); } ); @@ -211,7 +237,7 @@ export class JsInvokeMessageProcessor { const remoteResponse = JsInvokeMessageProcessor.createRemoteResponse(requestId, compileResponse, invokeResponse, releaseResponse); const rawResponse = Buffer.from(JSON.stringify(remoteResponse), 'utf8'); this.logger.debug('[%s] Sending response to queue, scriptId: [%s]', requestId, scriptId); - this.producer.send(responseTopic, scriptId, rawResponse, headers).then( + this.producer.send(responseTopic, requestId, rawResponse, headers).then( () => { this.logger.debug('[%s] Response sent to queue, took [%s]ms, scriptId: [%s]', requestId, (performance.now() - tStartSending), scriptId); }, @@ -231,7 +257,7 @@ export class JsInvokeMessageProcessor { if (script) { self.incrementUseScriptId(scriptId); resolve(script); - } else { + } else if (scriptBody) { const startTime = performance.now(); self.executor.compileScript(scriptBody).then( (compiledScript) => { @@ -244,6 +270,12 @@ export class JsInvokeMessageProcessor { reject(err); } ); + } else { + const err = { + name: 'script body not found', + message: '' + } + reject(err); } }); } @@ -274,17 +306,29 @@ export class JsInvokeMessageProcessor { } private static createCompileResponse(scriptId: string, success: boolean, errorCode?: number, err?: any): JsCompileResponse { - const scriptIdBits = UUIDToBits(scriptId); - return { - errorCode: errorCode, - success: success, - errorDetails: parseJsErrorDetails(err), - scriptIdMSB: scriptIdBits[0], - scriptIdLSB: scriptIdBits[1] - }; + if (isNotUUID(scriptId)) { + return { + errorCode: errorCode, + success: success, + errorDetails: parseJsErrorDetails(err), + scriptIdMSB: "0", + scriptIdLSB: "0", + scriptHash: scriptId + }; + } else { // this is for backward compatibility (to be able to work with tb-node of previous version) - todo: remove in the next release + let scriptIdBits = UUIDToBits(scriptId); + return { + errorCode: errorCode, + success: success, + errorDetails: parseJsErrorDetails(err), + scriptIdMSB: scriptIdBits[0], + scriptIdLSB: scriptIdBits[1], + scriptHash: "" + }; + } } - private static createInvokeResponse(result: string, success: boolean, errorCode?: number, err?: any): JsInvokeResponse { + private static createInvokeResponse(result: string | undefined, success: boolean, errorCode?: number, err?: any): JsInvokeResponse { return { errorCode: errorCode, success: success, @@ -294,16 +338,26 @@ export class JsInvokeMessageProcessor { } private static createReleaseResponse(scriptId: string, success: boolean): JsReleaseResponse { - const scriptIdBits = UUIDToBits(scriptId); - return { - success: success, - scriptIdMSB: scriptIdBits[0], - scriptIdLSB: scriptIdBits[1] - }; + if (isNotUUID(scriptId)) { + return { + success: success, + scriptIdMSB: "0", + scriptIdLSB: "0", + scriptHash: scriptId, + }; + } else { // todo: remove in the next release + let scriptIdBits = UUIDToBits(scriptId); + return { + success: success, + scriptIdMSB: scriptIdBits[0], + scriptIdLSB: scriptIdBits[1], + scriptHash: "" + } + } } private static getScriptId(request: TbMessage): string { - return toUUIDString(request.scriptIdMSB, request.scriptIdLSB); + return request.scriptHash ? request.scriptHash : toUUIDString(request.scriptIdMSB, request.scriptIdLSB); } private incrementUseScriptId(scriptId: string) { diff --git a/msa/js-executor/api/utils.ts b/msa/js-executor/api/utils.ts index 361025f806..468dd50e7e 100644 --- a/msa/js-executor/api/utils.ts +++ b/msa/js-executor/api/utils.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -58,3 +58,7 @@ export function parseJsErrorDetails(err: any): string | undefined { } return details; } + +export function isNotUUID(candidate: string) { + return candidate.length != 36 || !candidate.includes('-'); +} diff --git a/msa/js-executor/config/custom-environment-variables.yml b/msa/js-executor/config/custom-environment-variables.yml index d408b14136..1c8ee5972c 100644 --- a/msa/js-executor/config/custom-environment-variables.yml +++ b/msa/js-executor/config/custom-environment-variables.yml @@ -1,5 +1,5 @@ # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ http_port: "HTTP_PORT" # /livenessProbe js: response_poll_interval: "REMOTE_JS_RESPONSE_POLL_INTERVAL_MS" + max_result_size: "JS_MAX_RESULT_SIZE" kafka: bootstrap: @@ -74,6 +75,7 @@ logger: script: use_sandbox: "SCRIPT_USE_SANDBOX" + memory_usage_trace_frequency: "MEMORY_USAGE_TRACE_FREQUENCY" stat_print_frequency: "SCRIPT_STAT_PRINT_FREQUENCY" script_body_trace_frequency: "SCRIPT_BODY_TRACE_FREQUENCY" max_active_scripts: "MAX_ACTIVE_SCRIPTS" diff --git a/msa/js-executor/config/default.yml b/msa/js-executor/config/default.yml index 32163ea01e..8a2ad6b240 100644 --- a/msa/js-executor/config/default.yml +++ b/msa/js-executor/config/default.yml @@ -1,5 +1,5 @@ # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ http_port: "8888" # /livenessProbe js: response_poll_interval: "25" + max_result_size: "300000" kafka: bootstrap: @@ -63,6 +64,7 @@ logger: script: use_sandbox: "true" + memory_usage_trace_frequency: "1000" script_body_trace_frequency: "10000" stat_print_frequency: "10000" max_active_scripts: "1000" diff --git a/msa/js-executor/config/logger.ts b/msa/js-executor/config/logger.ts index cecad0b487..8a2e8a6305 100644 --- a/msa/js-executor/config/logger.ts +++ b/msa/js-executor/config/logger.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/msa/js-executor/config/tb-js-executor.conf b/msa/js-executor/config/tb-js-executor.conf index fbdcc163f5..b3d4e05629 100644 --- a/msa/js-executor/config/tb-js-executor.conf +++ b/msa/js-executor/config/tb-js-executor.conf @@ -1,5 +1,5 @@ # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/msa/js-executor/docker/Dockerfile b/msa/js-executor/docker/Dockerfile index 8746e1db54..f934628a96 100644 --- a/msa/js-executor/docker/Dockerfile +++ b/msa/js-executor/docker/Dockerfile @@ -1,5 +1,5 @@ # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ # limitations under the License. # -FROM thingsboard/node:16.15.1-bullseye-slim +FROM thingsboard/node:16.17.0-bullseye-slim ENV NODE_ENV production ENV DOCKER_MODE true diff --git a/msa/js-executor/docker/start-js-executor.sh b/msa/js-executor/docker/start-js-executor.sh index 575f93c389..2272f9f20a 100755 --- a/msa/js-executor/docker/start-js-executor.sh +++ b/msa/js-executor/docker/start-js-executor.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright © 2016-2022 The Thingsboard Authors +# Copyright © 2016-2023 The Thingsboard Authors # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,4 +27,4 @@ source "${CONF_FOLDER}/${configfile}" cd ${pkg.installFolder} # This will forward this PID 1 to the node.js and forward SIGTERM for graceful shutdown as well -exec node server.js +exec node --no-compilation-cache server.js diff --git a/msa/js-executor/install.js b/msa/js-executor/install.js index a20142a4a0..71cf8d33a3 100644 --- a/msa/js-executor/install.js +++ b/msa/js-executor/install.js @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index f220fd4ff5..f9fde3328d 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "3.4.1", + "version": "3.4.4", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.ts", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index b13be7048e..96ca0247c7 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -1,6 +1,6 @@ 1.2.7 - 1.16.0 + 7.6.1 + 3.23.1 + 5.2.0 + 1.3 + 1.17.3 1.12 3.0.0 6.1.0.202203080745-r + 0.4.8 1.0.0 + 4.6.0 + 5.2.0 + 2.19.0 + 2.8 @@ -968,6 +978,16 @@ coap-server ${project.version} + + org.thingsboard.common.script + script-api + ${project.version} + + + org.thingsboard.common.script + remote-js-client + ${project.version} + org.thingsboard tools @@ -1213,7 +1233,6 @@ com.jayway.jsonpath json-path ${json-path.version} - test com.jayway.jsonpath @@ -1318,11 +1337,6 @@ java-driver-query-builder ${cassandra.version} - - com.datastax.cassandra - cassandra-driver-core - ${cassandra-driver-core.version} - io.dropwizard.metrics metrics-jmx @@ -1371,7 +1385,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson.version} + ${jackson-databind.version} com.fasterxml.jackson.core @@ -1563,6 +1577,11 @@ grpc-api ${grpc.version} + + org.thingsboard + tbel + ${tbel.version} + org.springframework spring-test @@ -1606,6 +1625,11 @@ cassandra-all ${cassandra-all.version} + + org.apache.cassandra + cassandra-thrift + ${cassandra-all.version} + org.junit.vintage junit-vintage-engine @@ -1618,6 +1642,54 @@ + + org.testng + testng + ${testng.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + io.rest-assured + rest-assured + ${rest-assured.version} + test + + + org.seleniumhq.selenium + selenium-java + ${selenium.version} + test + + + io.github.bonigarcia + webdrivermanager + ${webdrivermanager.version} + test + + + io.qameta.allure + allure-testng + ${allure-testng.version} + test + + + io.qameta.allure + allure-maven + ${allure-maven.version} + test + + + org.hamcrest + hamcrest-all + ${hamcrest.version} + test + org.awaitility awaitility @@ -1911,6 +1983,11 @@ org.eclipse.jgit.ssh.apache ${jgit.version} + + net.objecthunter + exp4j + ${exp4j.version} + diff --git a/pull_request_template.md b/pull_request_template.md index 6e7c31967e..21362429dc 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -6,6 +6,7 @@ Put your PR description here instead of this sentence. - [ ] You have reviewed the guidelines [document](https://docs.google.com/document/d/1wqcOafLx5hth8SAg4dqV_LV3un3m5WYR8RdTJ4MbbUM/edit?usp=sharing). - [ ] PR name contains fix version. For example, "[3.3.4] Hotfix of some UI component" or "[3.4] New Super Feature". +- [ ] The [milestone](https://docs.github.com/en/issues/using-labels-and-milestones-to-track-work/about-milestones) is specified and corresponds to fix version. - [ ] Description references specific [issue](https://github.com/thingsboard/thingsboard/issues). - [ ] Description contains human-readable scope of changes. - [ ] Description contains brief notes about what needs to be added to the documentation. diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 8b1d4b9641..f4eaa91ba5 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -1,6 +1,6 @@
+ fxFlex tb-fullscreen [fullscreenElement]="elRef.nativeElement" [fullscreen]="widgetEditMode || iframeMode || forceFullscreen || isFullscreen">
settings - + [parentDashboard]="parentDashboard" + [popoverComponent]="popoverComponent"> + [ngStyle]="{width: mainLayoutSize.width, + height: mainLayoutSize.height}"> + [parentDashboard]="parentDashboard" + [popoverComponent]="popoverComponent"> diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss index abd5c9388b..c1d43c94ca 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts index 4ebaccb774..e422f2b29f 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -15,15 +15,21 @@ /// import { + AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, - Component, ElementRef, EventEmitter, HostBinding, + Component, + ElementRef, + EventEmitter, + HostBinding, Inject, Injector, Input, NgZone, OnDestroy, - OnInit, Optional, Renderer2, + OnInit, + Optional, + Renderer2, StaticProvider, ViewChild, ViewContainerRef, @@ -44,13 +50,15 @@ import { DashboardState, DashboardStateLayouts, GridSettings, + LayoutDimension, WidgetLayout } from '@app/shared/models/dashboard.models'; import { WINDOW } from '@core/services/window.service'; import { WindowMessage } from '@shared/models/window-message.model'; -import { deepClone, guid, hashCode, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; +import { deepClone, guid, isDefined, isDefinedAndNotNull, isNotEmptyStr } from '@app/core/utils'; import { DashboardContext, + DashboardPageInitData, DashboardPageLayout, DashboardPageLayoutContext, DashboardPageLayouts, @@ -129,7 +137,8 @@ import { MobileService } from '@core/services/mobile.service'; import { DashboardImageDialogComponent, - DashboardImageDialogData, DashboardImageDialogResult + DashboardImageDialogData, + DashboardImageDialogResult } from '@home/components/dashboard-page/dashboard-image-dialog.component'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; import cssjs from '@core/css/css'; @@ -139,6 +148,9 @@ import { MatButton } from '@angular/material/button'; import { VersionControlComponent } from '@home/components/vc/version-control.component'; import { TbPopoverService } from '@shared/components/popover.service'; import { tap } from 'rxjs/operators'; +import { LayoutFixedSize, LayoutWidthType } from '@home/components/dashboard-page/layout/layout.models'; +import { TbPopoverComponent } from '@shared/components/popover.component'; +import { ResizeObserver } from '@juggle/resize-observer'; // @dynamic @Component({ @@ -148,7 +160,7 @@ import { tap } from 'rxjs/operators'; encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush }) -export class DashboardPageComponent extends PageComponent implements IDashboardController, OnInit, OnDestroy { +export class DashboardPageComponent extends PageComponent implements IDashboardController, OnInit, AfterViewInit, OnDestroy { authState: AuthState = getCurrentAuthState(this.store); @@ -184,6 +196,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC @Input() parentDashboard?: IDashboardComponent = null; + @Input() + popoverComponent?: TbPopoverComponent = null; + @Input() parentAliasController?: IAliasController = null; @@ -232,9 +247,14 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC addingLayoutCtx: DashboardPageLayoutContext; + mainLayoutSize: {width: string; height: string} = {width: '100%', height: '100%'}; + rightLayoutSize: {width: string; height: string} = {width: '100%', height: '100%'}; + private dashboardLogoCache: SafeUrl; private defaultDashboardLogo = 'assets/logo_title_white.svg'; + private dashboardResize$: ResizeObserver; + dashboardCtx: DashboardContext = { instanceId: this.utils.guid(), getDashboard: () => this.dashboard, @@ -342,7 +362,8 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC private overlay: Overlay, private viewContainerRef: ViewContainerRef, private cd: ChangeDetectorRef, - private sanitizer: DomSanitizer) { + private sanitizer: DomSanitizer, + public elRef: ElementRef) { super(store); if (isDefinedAndNotNull(embeddedValue)) { this.embedded = embeddedValue; @@ -352,15 +373,23 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC ngOnInit() { this.rxSubscriptions.push(this.route.data.subscribe( (data) => { + let dashboardPageInitData: DashboardPageInitData; if (this.embedded) { - data.dashboard = this.dashboardUtils.validateAndUpdateDashboard(this.dashboard); - data.currentDashboardId = this.dashboard.id ? this.dashboard.id.id : null; - data.widgetEditMode = false; - data.singlePageMode = false; + dashboardPageInitData = { + dashboard: this.dashboardUtils.validateAndUpdateDashboard(this.dashboard), + currentDashboardId: this.dashboard.id ? this.dashboard.id.id : null, + widgetEditMode: false, + singlePageMode: false + }; } else { - data.currentDashboardId = this.route.snapshot.params.dashboardId; + dashboardPageInitData = { + dashboard: data.dashboard, + currentDashboardId: this.route.snapshot.params.dashboardId, + widgetEditMode: data.widgetEditMode, + singlePageMode: data.singlePageMode + }; } - this.init(data); + this.init(dashboardPageInitData); this.runChangeDetection(); } )); @@ -381,6 +410,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC .observe(MediaBreakpoints['gt-sm']) .subscribe((state: BreakpointState) => { this.isMobile = !state.matches; + this.updateLayoutSizes(); } )); if (this.isMobileApp && this.syncStateWithQueryParam) { @@ -393,7 +423,14 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC } } - private init(data: any) { + ngAfterViewInit() { + this.dashboardResize$ = new ResizeObserver(() => { + this.updateLayoutSizes(); + }); + this.dashboardResize$.observe(this.dashboardContainer.nativeElement); + } + + private init(data: DashboardPageInitData) { this.reset(); @@ -516,6 +553,9 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC subscription.unsubscribe(); }); this.rxSubscriptions.length = 0; + if (this.dashboardResize$) { + this.dashboardResize$.disconnect(); + } } public runChangeDetection() { @@ -658,35 +698,87 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.mobileService.onDashboardRightLayoutChanged(this.isRightLayoutOpened); } - public mainLayoutWidth(): string { - if (this.isEditingWidget && this.editingLayoutCtx.id === 'main') { - return '100%'; - } else { - return this.layouts.right.show && !this.isMobile ? '50%' : '100%'; + private updateLayoutSizes() { + let changeMainLayoutSize = false; + let changeRightLayoutSize = false; + if (this.dashboardCtx.state) { + changeMainLayoutSize = this.updateMainLayoutSize(); + changeRightLayoutSize = this.updateRightLayoutSize(); + } + if (changeMainLayoutSize || changeRightLayoutSize) { + this.cd.markForCheck(); } } - public mainLayoutHeight(): string { + private updateMainLayoutSize(): boolean { + const prevMainLayoutWidth = this.mainLayoutSize.width; + const prevMainLayoutHeight = this.mainLayoutSize.height; + if (this.isEditingWidget && this.editingLayoutCtx.id === 'main') { + this.mainLayoutSize.width = '100%'; + } else { + this.mainLayoutSize.width = this.layouts.right.show && !this.isMobile ? this.calculateWidth('main') : '100%'; + } if (!this.isEditingWidget || this.editingLayoutCtx.id === 'main') { - return '100%'; + this.mainLayoutSize.height = '100%'; } else { - return '0px'; + this.mainLayoutSize.height = '0px'; } + return prevMainLayoutWidth !== this.mainLayoutSize.width || prevMainLayoutHeight !== this.mainLayoutSize.height; } - public rightLayoutWidth(): string { + private updateRightLayoutSize(): boolean { + const prevRightLayoutWidth = this.rightLayoutSize.width; + const prevRightLayoutHeight = this.rightLayoutSize.height; if (this.isEditingWidget && this.editingLayoutCtx.id === 'right') { - return '100%'; + this.rightLayoutSize.width = '100%'; } else { - return this.isMobile ? '100%' : '50%'; + this.rightLayoutSize.width = this.isMobile ? '100%' : this.calculateWidth('right'); } + if (!this.isEditingWidget || this.editingLayoutCtx.id === 'right') { + this.rightLayoutSize.height = '100%'; + } else { + this.rightLayoutSize.height = '0px'; + } + return prevRightLayoutWidth !== this.rightLayoutSize.width || prevRightLayoutHeight !== this.rightLayoutSize.height; } - public rightLayoutHeight(): string { - if (!this.isEditingWidget || this.editingLayoutCtx.id === 'right') { - return '100%'; + private calculateWidth(layout: DashboardLayoutId): string { + let layoutDimension: LayoutDimension; + const mainLayout = this.dashboard.configuration.states[this.dashboardCtx.state].layouts.main; + const rightLayout = this.dashboard.configuration.states[this.dashboardCtx.state].layouts.right; + if (rightLayout) { + if (mainLayout.gridSettings.layoutDimension) { + layoutDimension = mainLayout.gridSettings.layoutDimension; + } else { + layoutDimension = rightLayout.gridSettings.layoutDimension; + } + } + if (layoutDimension) { + if (layoutDimension.type === LayoutWidthType.PERCENTAGE) { + if (layout === 'right') { + return (100 - layoutDimension.leftWidthPercentage) + '%'; + } else { + return layoutDimension.leftWidthPercentage + '%'; + } + } else { + const dashboardWidth = this.dashboardContainer.nativeElement.getBoundingClientRect().width; + const minAvailableWidth = dashboardWidth - LayoutFixedSize.MIN; + if (layoutDimension.fixedLayout === layout) { + if (minAvailableWidth <= layoutDimension.fixedWidth) { + return minAvailableWidth + 'px'; + } else { + return layoutDimension.fixedWidth + 'px'; + } + } else { + if (minAvailableWidth <= layoutDimension.fixedWidth) { + return LayoutFixedSize.MIN + 'px'; + } else { + return (dashboardWidth - layoutDimension.fixedWidth) + 'px'; + } + } + } } else { - return '0px'; + return '50%'; } } @@ -916,6 +1008,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC layout.layoutCtx.ctrl.reload(); } layout.layoutCtx.ignoreLoading = true; + this.updateLayoutSizes(); } private setEditMode(isEdit: boolean, revert: boolean) { @@ -1062,7 +1155,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC dataKeys: config.alarmSource.dataKeys || [] }; } - const newWidget: Widget = { + let newWidget: Widget = { isSystemType: widget.isSystemType, bundleAlias: widget.bundleAlias, typeAlias: widgetTypeInfo.alias, @@ -1076,6 +1169,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC row: 0, col: 0 }; + newWidget = this.dashboardUtils.validateAndUpdateWidget(newWidget); if (widgetTypeInfo.typeParameters.useCustomDatasources) { this.addWidgetToDashboard(newWidget); } else { @@ -1129,6 +1223,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.editingLayoutCtx = null; this.editingWidgetSubtitle = null; this.isEditingWidget = false; + this.updateLayoutSizes(); this.resetHighlight(); this.forceDashboardMobileMode = false; } @@ -1154,6 +1249,7 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.editingWidgetSubtitle = this.widgetComponentService.getInstantWidgetInfo(this.editingWidget).widgetName; this.forceDashboardMobileMode = true; this.isEditingWidget = true; + this.updateLayoutSizes(); if (layoutCtx) { const delayOffset = transition ? 350 : 0; const delay = transition ? 400 : 300; @@ -1438,11 +1534,12 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC versionControlPopover.tbComponentRef.instance.versionRestored.subscribe(() => { this.dashboardService.getDashboard(this.currentDashboardId).subscribe((dashboard) => { dashboard = this.dashboardUtils.validateAndUpdateDashboard(dashboard); - const data = { + const data: DashboardPageInitData = { dashboard, - widgetEditMode: false, - currentDashboardId: this.currentDashboardId - } as any; + currentDashboardId: this.currentDashboardId, + widgetEditMode: this.widgetEditMode, + singlePageMode: this.singlePageMode + }; this.init(data); this.dashboardCtx.stateController.cleanupPreservedStates(); this.dashboardCtx.stateController.resetState(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts index 4fadc96039..63c4a555ac 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -24,6 +24,13 @@ import { Observable } from 'rxjs'; export declare type DashboardPageScope = 'tenant' | 'customer'; +export interface DashboardPageInitData { + dashboard: Dashboard; + currentDashboardId?: string; + widgetEditMode?: boolean; + singlePageMode?: boolean; +} + export interface DashboardContext { instanceId: string; state: string; diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html index 66ef1f8056..afa06e7127 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-settings-dialog.component.html @@ -1,6 +1,6 @@ + + + + {{ displayAssetProfileFn(selectAssetProfileFormGroup.get('assetProfile').value) }} + + + + + + + + +
+
+ asset-profile.no-asset-profiles-found +
+ + + {{ translate.get('asset-profile.no-asset-profiles-matching', + {entity: truncate.transform(searchText, true, 6, '...')}) | async }} + + + asset-profile.create-new-asset-profile + + +
+
+
+ + {{ 'asset-profile.asset-profile-required' | translate }} + + {{ hint | translate }} +
diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.scss b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.scss new file mode 100644 index 0000000000..2bf0b968ad --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.scss @@ -0,0 +1,21 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +:host{ + .mat-icon-button a { + border-bottom: none; + color: inherit; + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.ts b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.ts new file mode 100644 index 0000000000..42569472be --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile-autocomplete.component.ts @@ -0,0 +1,369 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + Component, + ElementRef, + EventEmitter, + forwardRef, + Input, + NgZone, + OnInit, + Output, + ViewChild +} from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Observable, of } from 'rxjs'; +import { PageLink } from '@shared/models/page/page-link'; +import { Direction } from '@shared/models/page/sort-order'; +import { catchError, debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; +import { Store } from '@ngrx/store'; +import { AppState } from '@app/core/core.state'; +import { TranslateService } from '@ngx-translate/core'; +import { coerceBooleanProperty } from '@angular/cdk/coercion'; +import { entityIdEquals } from '@shared/models/id/entity-id'; +import { TruncatePipe } from '@shared//pipe/truncate.pipe'; +import { ENTER } from '@angular/cdk/keycodes'; +import { MatDialog } from '@angular/material/dialog'; +import { MatAutocomplete } from '@angular/material/autocomplete'; +import { emptyPageData } from '@shared/models/page/page-data'; +import { getEntityDetailsPageURL } from '@core/utils'; +import { AssetProfileId } from '@shared/models/id/asset-profile-id'; +import { AssetProfile, AssetProfileInfo } from '@shared/models/asset.models'; +import { AssetProfileService } from '@core/http/asset-profile.service'; +import { AssetProfileDialogComponent, AssetProfileDialogData } from './asset-profile-dialog.component'; + +@Component({ + selector: 'tb-asset-profile-autocomplete', + templateUrl: './asset-profile-autocomplete.component.html', + styleUrls: ['./asset-profile-autocomplete.component.scss'], + providers: [{ + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => AssetProfileAutocompleteComponent), + multi: true + }] +}) +export class AssetProfileAutocompleteComponent implements ControlValueAccessor, OnInit { + + selectAssetProfileFormGroup: FormGroup; + + modelValue: AssetProfileId | null; + + @Input() + selectDefaultProfile = false; + + @Input() + selectFirstProfile = false; + + @Input() + displayAllOnEmpty = false; + + @Input() + editProfileEnabled = true; + + @Input() + addNewProfile = true; + + @Input() + showDetailsPageLink = false; + + private requiredValue: boolean; + get required(): boolean { + return this.requiredValue; + } + @Input() + set required(value: boolean) { + this.requiredValue = coerceBooleanProperty(value); + } + + @Input() + disabled: boolean; + + @Input() + hint: string; + + @Output() + assetProfileUpdated = new EventEmitter(); + + @Output() + assetProfileChanged = new EventEmitter(); + + @ViewChild('assetProfileInput', {static: true}) assetProfileInput: ElementRef; + + @ViewChild('assetProfileAutocomplete', {static: true}) assetProfileAutocomplete: MatAutocomplete; + + filteredAssetProfiles: Observable>; + + searchText = ''; + assetProfileURL: string; + + private dirty = false; + + private ignoreClosedPanel = false; + + private allAssetProfile: AssetProfileInfo = { + name: this.translate.instant('asset-profile.all-asset-profiles'), + id: null + }; + + private propagateChange = (v: any) => { }; + + constructor(private store: Store, + public translate: TranslateService, + public truncate: TruncatePipe, + private assetProfileService: AssetProfileService, + private fb: FormBuilder, + private zone: NgZone, + private dialog: MatDialog) { + this.selectAssetProfileFormGroup = this.fb.group({ + assetProfile: [null] + }); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + ngOnInit() { + this.filteredAssetProfiles = this.selectAssetProfileFormGroup.get('assetProfile').valueChanges + .pipe( + tap((value: AssetProfileInfo | string) => { + let modelValue: AssetProfileInfo | null; + if (typeof value === 'string' || !value) { + modelValue = null; + } else { + modelValue = value; + } + if (!this.displayAllOnEmpty || modelValue) { + this.updateView(modelValue); + } + }), + map(value => { + if (value) { + if (typeof value === 'string') { + return value; + } else { + if (this.displayAllOnEmpty && value === this.allAssetProfile) { + return ''; + } else { + return value.name; + } + } + } else { + return ''; + } + }), + debounceTime(150), + distinctUntilChanged(), + switchMap(name => this.fetchAssetProfiles(name)), + share() + ); + } + + selectDefaultAssetProfileIfNeeded(): void { + if (this.selectDefaultProfile && !this.modelValue) { + this.assetProfileService.getDefaultAssetProfileInfo().subscribe( + (profile) => { + if (profile) { + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(profile, {emitEvent: false}); + this.updateView(profile); + } else { + this.selectFirstAssetProfileIfNeeded(); + } + } + ); + } else { + this.selectFirstAssetProfileIfNeeded(); + } + } + + selectFirstAssetProfileIfNeeded(): void { + if (this.selectFirstProfile && !this.modelValue) { + const pageLink = new PageLink(1, 0, null, { + property: 'createdTime', + direction: Direction.DESC + }); + this.assetProfileService.getAssetProfileInfos(pageLink, {ignoreLoading: true}).subscribe( + (pageData => { + const data = pageData.data; + if (data.length) { + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(data[0], {emitEvent: false}); + this.updateView(data[0]); + } + }) + ); + } + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.selectAssetProfileFormGroup.disable({emitEvent: false}); + } else { + this.selectAssetProfileFormGroup.enable({emitEvent: false}); + } + } + + writeValue(value: AssetProfileId | null): void { + this.searchText = ''; + if (value != null) { + this.assetProfileService.getAssetProfileInfo(value.id).subscribe( + (profile) => { + this.modelValue = new AssetProfileId(profile.id.id); + this.assetProfileURL = getEntityDetailsPageURL(this.modelValue.id, this.modelValue.entityType); + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(profile, {emitEvent: false}); + this.assetProfileChanged.emit(profile); + } + ); + } else if (this.displayAllOnEmpty) { + this.modelValue = null; + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(this.allAssetProfile, {emitEvent: false}); + } else { + this.modelValue = null; + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(null, {emitEvent: false}); + this.selectDefaultAssetProfileIfNeeded(); + } + this.dirty = true; + } + + onFocus() { + if (this.dirty) { + this.selectAssetProfileFormGroup.get('assetProfile').updateValueAndValidity({onlySelf: true, emitEvent: true}); + this.dirty = false; + } + } + + onPanelClosed() { + if (this.ignoreClosedPanel) { + this.ignoreClosedPanel = false; + } else { + if (this.displayAllOnEmpty && !this.selectAssetProfileFormGroup.get('assetProfile').value) { + this.zone.run(() => { + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(this.allAssetProfile, {emitEvent: true}); + }, 0); + } + } + } + + updateView(assetProfile: AssetProfileInfo | null) { + const idValue = assetProfile && assetProfile.id ? new AssetProfileId(assetProfile.id.id) : null; + if (!entityIdEquals(this.modelValue, idValue)) { + this.modelValue = idValue; + this.propagateChange(this.modelValue); + this.assetProfileChanged.emit(assetProfile); + } + } + + displayAssetProfileFn(profile?: AssetProfileInfo): string | undefined { + return profile ? profile.name : undefined; + } + + fetchAssetProfiles(searchText?: string): Observable> { + this.searchText = searchText; + const pageLink = new PageLink(10, 0, searchText, { + property: 'name', + direction: Direction.ASC + }); + return this.assetProfileService.getAssetProfileInfos(pageLink, {ignoreLoading: true}).pipe( + catchError(() => of(emptyPageData())), + map(pageData => { + let data = pageData.data; + if (this.displayAllOnEmpty) { + data = [this.allAssetProfile, ...data]; + } + return data; + }) + ); + } + + clear() { + this.ignoreClosedPanel = true; + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(null, {emitEvent: true}); + setTimeout(() => { + this.assetProfileInput.nativeElement.blur(); + this.assetProfileInput.nativeElement.focus(); + }, 0); + } + + textIsNotEmpty(text: string): boolean { + return (text && text.length > 0); + } + + assetProfileEnter($event: KeyboardEvent) { + if (this.editProfileEnabled && $event.keyCode === ENTER) { + $event.preventDefault(); + if (!this.modelValue) { + this.createAssetProfile($event, this.searchText); + } + } + } + + createAssetProfile($event: Event, profileName: string) { + $event.preventDefault(); + const assetProfile: AssetProfile = { + name: profileName + } as AssetProfile; + if (this.addNewProfile) { + this.openAssetProfileDialog(assetProfile, true); + } + } + + editAssetProfile($event: Event) { + $event.preventDefault(); + this.assetProfileService.getAssetProfile(this.modelValue.id).subscribe( + (assetProfile) => { + this.openAssetProfileDialog(assetProfile, false); + } + ); + } + + openAssetProfileDialog(assetProfile: AssetProfile, isAdd: boolean) { + this.dialog.open(AssetProfileDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + isAdd, + assetProfile + } + }).afterClosed().subscribe( + (savedAssetProfile) => { + if (!savedAssetProfile) { + setTimeout(() => { + this.assetProfileInput.nativeElement.blur(); + this.assetProfileInput.nativeElement.focus(); + }, 0); + } else { + this.assetProfileService.getAssetProfileInfo(savedAssetProfile.id.id).subscribe( + (profile) => { + this.modelValue = new AssetProfileId(profile.id.id); + this.selectAssetProfileFormGroup.get('assetProfile').patchValue(profile, {emitEvent: true}); + if (isAdd) { + this.propagateChange(this.modelValue); + } else { + this.assetProfileUpdated.next(savedAssetProfile.id); + } + this.assetProfileChanged.emit(profile); + } + ); + } + } + ); + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.html new file mode 100644 index 0000000000..21c1e7dd87 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.html @@ -0,0 +1,53 @@ + +
+ +

{{ (isAdd ? 'asset-profile.add' : 'asset-profile.edit' ) | translate }}

+ + +
+ + +
+
+ + +
+
+ + +
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.ts new file mode 100644 index 0000000000..cd3f4fad17 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile-dialog.component.ts @@ -0,0 +1,100 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { + AfterViewInit, + Component, + ComponentFactoryResolver, + Inject, + Injector, + SkipSelf, + ViewChild +} from '@angular/core'; +import { ErrorStateMatcher } from '@angular/material/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { FormControl, FormGroupDirective, NgForm } from '@angular/forms'; +import { DialogComponent } from '@shared/components/dialog.component'; +import { Router } from '@angular/router'; +import { AssetProfile } from '@shared/models/asset.models'; +import { AssetProfileComponent } from '@home/components/profile/asset-profile.component'; +import { AssetProfileService } from '@core/http/asset-profile.service'; + +export interface AssetProfileDialogData { + assetProfile: AssetProfile; + isAdd: boolean; +} + +@Component({ + selector: 'tb-asset-profile-dialog', + templateUrl: './asset-profile-dialog.component.html', + providers: [{provide: ErrorStateMatcher, useExisting: AssetProfileDialogComponent}], + styleUrls: [] +}) +export class AssetProfileDialogComponent extends + DialogComponent implements ErrorStateMatcher, AfterViewInit { + + isAdd: boolean; + assetProfile: AssetProfile; + + submitted = false; + + @ViewChild('assetProfileComponent', {static: true}) assetProfileComponent: AssetProfileComponent; + + constructor(protected store: Store, + protected router: Router, + @Inject(MAT_DIALOG_DATA) public data: AssetProfileDialogData, + public dialogRef: MatDialogRef, + private componentFactoryResolver: ComponentFactoryResolver, + private injector: Injector, + @SkipSelf() private errorStateMatcher: ErrorStateMatcher, + private assetProfileService: AssetProfileService) { + super(store, router, dialogRef); + this.isAdd = this.data.isAdd; + this.assetProfile = this.data.assetProfile; + } + + ngAfterViewInit(): void { + if (this.isAdd) { + setTimeout(() => { + this.assetProfileComponent.entityForm.markAsDirty(); + }, 0); + } + } + + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const originalErrorState = this.errorStateMatcher.isErrorState(control, form); + const customErrorState = !!(control && control.invalid && this.submitted); + return originalErrorState || customErrorState; + } + + cancel(): void { + this.dialogRef.close(null); + } + + save(): void { + this.submitted = true; + if (this.assetProfileComponent.entityForm.valid) { + this.assetProfile = {...this.assetProfile, ...this.assetProfileComponent.entityFormValue()}; + this.assetProfileService.saveAssetProfile(this.assetProfile).subscribe( + (assetProfile) => { + this.dialogRef.close(assetProfile); + } + ); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.html new file mode 100644 index 0000000000..fbc3d59696 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.html @@ -0,0 +1,91 @@ + +
+ + + + +
+ +
+
+
+
+
+ + asset-profile.name + + + {{ 'asset-profile.name-required' | translate }} + + + {{ 'asset-profile.name-max-length' | translate }} + + + + + +
{{'asset-profile.mobile-dashboard-hint' | translate}}
+
+ + + + + + asset-profile.description + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.ts new file mode 100644 index 0000000000..74e3830bf8 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/asset-profile.component.ts @@ -0,0 +1,113 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { ChangeDetectorRef, Component, Inject, Input, Optional } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ActionNotificationShow } from '@app/core/notification/notification.actions'; +import { TranslateService } from '@ngx-translate/core'; +import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; +import { EntityComponent } from '../entity/entity.component'; +import { EntityType } from '@shared/models/entity-type.models'; +import { RuleChainId } from '@shared/models/id/rule-chain-id'; +import { ServiceType } from '@shared/models/queue.models'; +import { EntityId } from '@shared/models/id/entity-id'; +import { DashboardId } from '@shared/models/id/dashboard-id'; +import { AssetProfile, TB_SERVICE_QUEUE } from '@shared/models/asset.models'; + +@Component({ + selector: 'tb-asset-profile', + templateUrl: './asset-profile.component.html', + styleUrls: [] +}) +export class AssetProfileComponent extends EntityComponent { + + @Input() + standalone = false; + + entityType = EntityType; + + serviceType = ServiceType.TB_RULE_ENGINE; + + TB_SERVICE_QUEUE = TB_SERVICE_QUEUE; + + assetProfileId: EntityId; + + constructor(protected store: Store, + protected translate: TranslateService, + @Optional() @Inject('entity') protected entityValue: AssetProfile, + @Optional() @Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig, + protected fb: FormBuilder, + protected cd: ChangeDetectorRef) { + super(store, fb, entityValue, entitiesTableConfigValue, cd); + } + + hideDelete() { + if (this.entitiesTableConfig) { + return !this.entitiesTableConfig.deleteEnabled(this.entity); + } else { + return false; + } + } + + buildForm(entity: AssetProfile): FormGroup { + this.assetProfileId = entity?.id ? entity.id : null; + const form = this.fb.group( + { + name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], + image: [entity ? entity.image : null], + defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], + defaultDashboardId: [entity && entity.defaultDashboardId ? entity.defaultDashboardId.id : null, []], + defaultQueueName: [entity ? entity.defaultQueueName : null, []], + description: [entity ? entity.description : '', []], + } + ); + return form; + } + + updateForm(entity: AssetProfile) { + this.assetProfileId = entity.id; + this.entityForm.patchValue({name: entity.name}); + this.entityForm.patchValue({image: entity.image}, {emitEvent: false}); + this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); + this.entityForm.patchValue({defaultDashboardId: entity.defaultDashboardId ? entity.defaultDashboardId.id : null}, {emitEvent: false}); + this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); + this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); + } + + prepareFormValue(formValue: any): any { + if (formValue.defaultRuleChainId) { + formValue.defaultRuleChainId = new RuleChainId(formValue.defaultRuleChainId); + } + if (formValue.defaultDashboardId) { + formValue.defaultDashboardId = new DashboardId(formValue.defaultDashboardId); + } + return super.prepareFormValue(formValue); + } + + onAssetProfileIdCopied(event) { + this.store.dispatch(new ActionNotificationShow( + { + message: this.translate.instant('asset-profile.idCopiedMessage'), + type: 'success', + duration: 750, + verticalPosition: 'bottom', + horizontalPosition: 'right' + })); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html index 1b9ba6c6b4..c22cbd739f 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile-autocomplete.component.html @@ -1,6 +1,6 @@ -
admin.queue-name diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss index 874660cbdf..660293581f 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts index 3268c5b2f9..601969f52e 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.html b/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.html index 9ae32f6fd8..0af8805a50 100644 --- a/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/relation/relation-dialog.component.html @@ -1,6 +1,6 @@ -

{{ 'version-control.create-entities-version' | translate }}

diff --git a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.ts index 8b53bdaeac..c1260ee2a8 100644 --- a/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/complex-version-create.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -121,12 +121,18 @@ export class ComplexVersionCreateComponent extends PageComponent implements OnIn } this.versionCreateResultSubscription = this.versionCreateResult$.subscribe((result) => { - if (result.done && !result.added && !result.modified && !result.removed) { - this.resultMessage = this.sanitizer.bypassSecurityTrustHtml(this.translate.instant('version-control.nothing-to-commit')); + let message: string; + if (!result.error) { + if (result.done && !result.added && !result.modified && !result.removed) { + message = this.translate.instant('version-control.nothing-to-commit'); + } else { + message = this.translate.instant('version-control.version-create-result', + {added: result.added, modified: result.modified, removed: result.removed}); + } } else { - this.resultMessage = this.sanitizer.bypassSecurityTrustHtml(result.error ? result.error : this.translate.instant('version-control.version-create-result', - {added: result.added, modified: result.modified, removed: result.removed})); + message = result.error; } + this.resultMessage = this.sanitizer.bypassSecurityTrustHtml(message); this.versionCreateResult = result; this.versionCreateBranch = request.branch; this.cd.detectChanges(); diff --git a/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.html b/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.html index 86e756b7f1..f9904c700f 100644 --- a/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.html @@ -1,6 +1,6 @@ -

{{ 'version-control.restore-entities-from-version' | translate: {versionName} }}

diff --git a/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts b/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts index dda0f6b39d..bf2812ffc6 100644 --- a/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/complex-version-load.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.html index 14c98613fc..a3fee96758 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-types-version-create.component.html @@ -1,6 +1,6 @@ -

{{ 'version-control.create-entity-version' | translate }}

diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts index 0b8812f94d..30fd4ead95 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html index aa0c9284a9..62686847af 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-diff.component.html @@ -1,6 +1,6 @@ -

{{ 'version-control.restore-entity-from-version' | translate: {versionName} }}

diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts index 44f86129d8..0ed691a272 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-restore.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html index 772cb5ecd9..68a7f06bcd 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html +++ b/ui-ngx/src/app/modules/home/components/vc/entity-versions-table.component.html @@ -1,6 +1,6 @@
+ + widgets.table.custom-title + + widgets.table.column-width diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.ts index 9f9cbbf5e1..1909cde7c7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-key-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ export class AlarmsTableKeySettingsComponent extends WidgetSettingsComponent { protected defaultSettings(): WidgetSettings { return { + customTitle: '', columnWidth: '0px', useCellStyleFunction: false, cellStyleFunction: '', @@ -52,6 +53,7 @@ export class AlarmsTableKeySettingsComponent extends WidgetSettingsComponent { protected onSettingsSet(settings: WidgetSettings) { this.alarmsTableKeySettingsForm = this.fb.group({ + customTitle: [settings.customTitle, []], columnWidth: [settings.columnWidth, []], useCellStyleFunction: [settings.useCellStyleFunction, []], cellStyleFunction: [settings.cellStyleFunction, [Validators.required]], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html index 5fc8104a80..8bf3e5a176 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.html @@ -1,6 +1,6 @@
+ + widgets.table.custom-title + + widgets.table.column-width @@ -79,6 +83,9 @@ {{ 'widgets.table.column-visibility-hidden' | translate }} + + {{ 'widgets.table.column-visibility-hidden-mobile' | translate }} + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts index 738e99223c..e4b82b9ad1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -40,6 +40,7 @@ export class EntitiesTableKeySettingsComponent extends WidgetSettingsComponent { protected defaultSettings(): WidgetSettings { return { + customTitle: '', columnWidth: '0px', useCellStyleFunction: false, cellStyleFunction: '', @@ -52,6 +53,7 @@ export class EntitiesTableKeySettingsComponent extends WidgetSettingsComponent { protected onSettingsSet(settings: WidgetSettings) { this.entitiesTableKeySettingsForm = this.fb.group({ + customTitle: [settings.customTitle, []], columnWidth: [settings.columnWidth, []], useCellStyleFunction: [settings.useCellStyleFunction, []], cellStyleFunction: [settings.cellStyleFunction, [Validators.required]], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html index c84a87deac..35c53eca6f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html @@ -1,6 +1,6 @@ -
-
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts index 285c339edf..5b0ba381ec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-bar-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index 05879cb124..54dc2f6f15 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -1,6 +1,6 @@ -
-
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts index d2b0e76ca6..82795cffc5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-line-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-key-settings.component.html index 8649e5e97d..6b2779ac58 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-pie-key-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/knob-control-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/knob-control-widget-settings.component.ts index dae3045110..6e5e80474c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/knob-control-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/knob-control-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.html index c4e934eabe..9944d3173a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.ts index 8ee8ebe127..203bf54325 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/led-indicator-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html index 47b3ef545d..8e2078e881 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/persistent-table-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts index cf7ee3bbb9..9fbd0f1ced 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/round-switch-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html index a8153c68fe..3e330e78ac 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-button-style.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.rpc-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-shell-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-shell-widget-settings.component.ts index d901ad2636..d28dc575be 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-shell-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-shell-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.html index 79c34bfdea..445e69394f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.rpc-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.ts index 906c0c71b3..ecfb54f57f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/rpc-terminal-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.html index c36a21c349..1e1ee3cd03 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.ts index 051b780ca9..cc62e065b2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/send-rpc-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html index 37a15b90f4..927bcf65c7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts index f95473dbb9..c458b94ba9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/slide-toggle-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html index da0b4237db..5556540f4d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts index 65f09f2dd8..3a96932613 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-control-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html index ec2228cc78..0e9911508b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/switch-rpc-settings.component.html @@ -1,6 +1,6 @@ -
widgets.rpc.common-settings diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/update-device-attribute-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/update-device-attribute-widget-settings.component.ts index 6689112bf7..58ebe6dc44 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/update-device-attribute-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/control/update-device-attribute-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/date/date-range-navigator-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/date/date-range-navigator-widget-settings.component.html index 519ef6bafa..2a666ef1f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/date/date-range-navigator-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/date/date-range-navigator-widget-settings.component.html @@ -1,6 +1,6 @@ -
-
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.ts index ef71992aef..29453d6341 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-double-attribute-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-image-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-image-attribute-widget-settings.component.html index ee86c62870..1e570ae27e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-image-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-image-attribute-widget-settings.component.html @@ -1,6 +1,6 @@ -
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.ts index d06601b468..2a2e95b435 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-integer-attribute-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html index fd76c980ac..5834916d67 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-json-attribute-widget-settings.component.html @@ -1,6 +1,6 @@ -
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.ts index 13dd1ec453..2489e32b0b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/input/update-string-attribute-widget-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.html index 827fb44129..06162001a2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/map/circle-settings.component.html @@ -1,6 +1,6 @@ -
- - -
- admin.security-settings - -
-
-
- - -
- - -
-
- - - - -
admin.general-policy
-
-
- - admin.max-failed-login-attempts - - - {{ 'admin.minimum-max-failed-login-attempts-range' | translate }} - - - - admin.user-lockout-notification-email - - -
- - - -
admin.password-policy
-
-
-
- - admin.minimum-password-length - - - {{ 'admin.minimum-password-length-required' | translate }} - - - {{ 'admin.minimum-password-length-range' | translate }} - - - {{ 'admin.minimum-password-length-range' | translate }} - - - - admin.minimum-uppercase-letters - - - {{ 'admin.minimum-uppercase-letters-range' | translate }} - - - - admin.minimum-lowercase-letters - - - {{ 'admin.minimum-lowercase-letters-range' | translate }} - - - - admin.minimum-digits - - - {{ 'admin.minimum-digits-range' | translate }} - - - - admin.minimum-special-characters - - - {{ 'admin.minimum-special-characters-range' | translate }} - - - - admin.password-expiration-period-days - - - {{ 'admin.password-expiration-period-days-range' | translate }} - - - - admin.password-reuse-frequency-days - - - {{ 'admin.password-reuse-frequency-days-range' | translate }} - - - - admin.allow-whitespace - -
-
-
-
-
- -
+ + +
+ admin.security-settings + +
+
+
+ + +
+ + +
+
+ admin.general-policy + + admin.max-failed-login-attempts + + + {{ 'admin.minimum-max-failed-login-attempts-range' | translate }} + + + + admin.user-lockout-notification-email + + +
+ +
+ admin.password-policy +
+ + admin.minimum-password-length + + + {{ 'admin.minimum-password-length-required' | translate }} + + + {{ 'admin.minimum-password-length-range' | translate }} + + + {{ 'admin.minimum-password-length-range' | translate }} + + +
+ + admin.minimum-uppercase-letters + + + {{ 'admin.minimum-uppercase-letters-range' | translate }} + + + + admin.minimum-lowercase-letters + + + {{ 'admin.minimum-lowercase-letters-range' | translate }} + + +
+
+ + admin.minimum-digits + + + {{ 'admin.minimum-digits-range' | translate }} + + + + admin.minimum-special-characters + + + {{ 'admin.minimum-special-characters-range' | translate }} + + +
+
+ + admin.password-expiration-period-days + + + {{ 'admin.password-expiration-period-days-range' | translate }} + + + + admin.password-reuse-frequency-days + + + {{ 'admin.password-reuse-frequency-days-range' | translate }} + + +
+ + admin.allow-whitespace + +
- - - -
+
+ + +
+
+ + + + + +
+ admin.jwt.security-settings +
+
+ +
+
+
+ + admin.jwt.issuer-name + + + {{ 'admin.jwt.issuer-name-required' | translate }} + + + + admin.jwt.signings-key + + + admin.jwt.signings-key-hint + + {{ 'admin.jwt.signings-key-required' | translate }} + + + {{ 'admin.jwt.signings-key-base64' | translate }} + + + {{ 'admin.jwt.signings-key-min-length' | translate }} + + +
+
+ + admin.jwt.expiration-time + + + {{ 'admin.jwt.expiration-time-required' | translate }} + + + {{ 'admin.jwt.expiration-time-pattern' | translate }} + + + {{ 'admin.jwt.expiration-time-min' | translate }} + + + + admin.jwt.refresh-expiration-time + + + {{ 'admin.jwt.refresh-expiration-time-required' | translate }} + + + {{ 'admin.jwt.refresh-expiration-time-pattern' | translate }} + + + {{ 'admin.jwt.refresh-expiration-time-min' | translate }} + + + {{ 'admin.jwt.refresh-expiration-time-less-token' | translate }} + + +
+
+ + +
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.scss b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.scss index 32e514e010..89f25bfc5e 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,26 @@ * limitations under the License. */ :host { - .mat-accordion-container { - margin-bottom: 16px; + .mat-headline { + margin-bottom: 8px; + } + + .mat-card-title { + margin: 0; + } + + .mat-card-content { + padding: 0 !important; + } + + .fields-group { + padding: 8px 16px 0; + margin: 10px 0; + border: 1px groove rgba(0, 0, 0, .25); + border-radius: 4px; + + legend { + color: rgba(0, 0, 0, .7); + } } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts index 6dc070b278..22e765a6ce 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/security-settings.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -14,40 +14,50 @@ /// limitations under the License. /// -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { PageComponent } from '@shared/components/page.component'; import { Router } from '@angular/router'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { SecuritySettings } from '@shared/models/settings.models'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { JwtSettings, SecuritySettings } from '@shared/models/settings.models'; import { AdminService } from '@core/http/admin.service'; import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard'; +import { mergeMap, tap } from 'rxjs/operators'; +import { randomAlphanumeric } from '@core/utils'; +import { AuthService } from '@core/auth/auth.service'; +import { DialogService } from '@core/services/dialog.service'; +import { TranslateService } from '@ngx-translate/core'; +import { Observable, of } from 'rxjs'; @Component({ selector: 'tb-security-settings', templateUrl: './security-settings.component.html', styleUrls: ['./security-settings.component.scss', './settings-card.scss'] }) -export class SecuritySettingsComponent extends PageComponent implements OnInit, HasConfirmForm { +export class SecuritySettingsComponent extends PageComponent implements HasConfirmForm { securitySettingsFormGroup: FormGroup; - securitySettings: SecuritySettings; + jwtSecuritySettingsFormGroup: FormGroup; + + private securitySettings: SecuritySettings; + private jwtSettings: JwtSettings; constructor(protected store: Store, private router: Router, private adminService: AdminService, - public fb: FormBuilder) { + private authService: AuthService, + private dialogService: DialogService, + private translate: TranslateService, + private fb: FormBuilder) { super(store); - } - - ngOnInit() { this.buildSecuritySettingsForm(); + this.buildJwtSecuritySettingsForm(); this.adminService.getSecuritySettings().subscribe( - (securitySettings) => { - this.securitySettings = securitySettings; - this.securitySettingsFormGroup.reset(this.securitySettings); - } + securitySettings => this.processSecuritySettings(securitySettings) + ); + this.adminService.getJwtSettings().subscribe( + jwtSettings => this.processJwtSettings(jwtSettings) ); } @@ -70,18 +80,114 @@ export class SecuritySettingsComponent extends PageComponent implements OnInit, }); } + buildJwtSecuritySettingsForm() { + this.jwtSecuritySettingsFormGroup = this.fb.group({ + tokenIssuer: ['', Validators.required], + tokenSigningKey: ['', [Validators.required, this.base64Format]], + tokenExpirationTime: [0, [Validators.required, Validators.pattern('[0-9]*'), Validators.min(60)]], + refreshTokenExpTime: [0, [Validators.required, Validators.pattern('[0-9]*'), Validators.min(900)]] + }, {validators: this.refreshTokenTimeGreatTokenTime.bind(this)}); + this.jwtSecuritySettingsFormGroup.get('tokenExpirationTime').valueChanges.subscribe( + () => this.jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').updateValueAndValidity({onlySelf: true}) + ); + } + save(): void { this.securitySettings = {...this.securitySettings, ...this.securitySettingsFormGroup.value}; this.adminService.saveSecuritySettings(this.securitySettings).subscribe( - (securitySettings) => { - this.securitySettings = securitySettings; - this.securitySettingsFormGroup.reset(this.securitySettings); - } + securitySettings => this.processSecuritySettings(securitySettings) ); } + saveJwtSettings() { + const jwtFormSettings = this.jwtSecuritySettingsFormGroup.value; + this.confirmChangeJWTSettings().pipe(mergeMap(value => { + if (value) { + return this.adminService.saveJwtSettings(jwtFormSettings).pipe( + tap((data) => this.authService.setUserFromJwtToken(data.token, data.refreshToken, false)), + mergeMap(() => this.adminService.getJwtSettings()), + tap(jwtSettings => this.processJwtSettings(jwtSettings)) + ); + } + return of(null); + })).subscribe(() => {}); + } + + discardSetting() { + this.securitySettingsFormGroup.reset(this.securitySettings); + } + + discardJwtSetting() { + this.jwtSecuritySettingsFormGroup.reset(this.jwtSettings); + } + + markAsTouched() { + this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').markAsTouched(); + } + + private confirmChangeJWTSettings(): Observable { + if (this.jwtSecuritySettingsFormGroup.get('tokenIssuer').value !== (this.jwtSettings?.tokenIssuer || '') || + this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').value !== (this.jwtSettings?.tokenSigningKey || '')) { + return this.dialogService.confirm( + this.translate.instant('admin.jwt.info-header'), + `
${this.translate.instant('admin.jwt.info-message')}
`, + this.translate.instant('action.discard-changes'), + this.translate.instant('action.confirm') + ); + } + return of(true); + } + + generateSigningKey() { + this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').setValue(btoa(randomAlphanumeric(64))); + if (this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').pristine) { + this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').markAsDirty(); + this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').markAsTouched(); + } + } + + private processSecuritySettings(securitySettings: SecuritySettings) { + this.securitySettings = securitySettings; + this.securitySettingsFormGroup.reset(this.securitySettings); + } + + private processJwtSettings(jwtSettings: JwtSettings) { + this.jwtSettings = jwtSettings; + this.jwtSecuritySettingsFormGroup.reset(jwtSettings); + } + + private refreshTokenTimeGreatTokenTime(formGroup: FormGroup): { [key: string]: boolean } | null { + if (formGroup) { + const tokenTime = formGroup.value.tokenExpirationTime; + const refreshTokenTime = formGroup.value.refreshTokenExpTime; + if (tokenTime >= refreshTokenTime ) { + if (formGroup.get('refreshTokenExpTime').untouched) { + formGroup.get('refreshTokenExpTime').markAsTouched(); + } + formGroup.get('refreshTokenExpTime').setErrors({lessToken: true}); + return {lessToken: true}; + } + } + return null; + } + + private base64Format(control: FormControl): { [key: string]: boolean } | null { + if (control.value === '' || control.value === 'thingsboardDefaultSigningKey') { + return null; + } + try { + const value = atob(control.value); + if (value.length < 32) { + return {minLength: true}; + } + return null; + } catch (e) { + return {base64: true}; + } + } + confirmForm(): FormGroup { - return this.securitySettingsFormGroup; + return this.securitySettingsFormGroup.dirty ? this.securitySettingsFormGroup : this.jwtSecuritySettingsFormGroup; } } diff --git a/ui-ngx/src/app/modules/home/pages/admin/send-test-sms-dialog.component.html b/ui-ngx/src/app/modules/home/pages/admin/send-test-sms-dialog.component.html index 40cc60f730..3441198d12 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/send-test-sms-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/admin/send-test-sms-dialog.component.html @@ -1,6 +1,6 @@ + + + + + + diff --git a/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile-tabs.component.ts b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile-tabs.component.ts new file mode 100644 index 0000000000..381ae1d509 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile-tabs.component.ts @@ -0,0 +1,38 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { EntityTabsComponent } from '../../components/entity/entity-tabs.component'; +import { AssetProfile } from '@shared/models/asset.models'; + +@Component({ + selector: 'tb-asset-profile-tabs', + templateUrl: './asset-profile-tabs.component.html', + styleUrls: [] +}) +export class AssetProfileTabsComponent extends EntityTabsComponent { + + constructor(protected store: Store) { + super(store); + } + + ngOnInit() { + super.ngOnInit(); + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile.module.ts b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile.module.ts new file mode 100644 index 0000000000..09f2c53d05 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profile.module.ts @@ -0,0 +1,35 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { HomeComponentsModule } from '@modules/home/components/home-components.module'; +import { AssetProfileTabsComponent } from './asset-profile-tabs.component'; +import { AssetProfileRoutingModule } from './asset-profile-routing.module'; + +@NgModule({ + declarations: [ + AssetProfileTabsComponent + ], + imports: [ + CommonModule, + SharedModule, + HomeComponentsModule, + AssetProfileRoutingModule + ] +}) +export class AssetProfileModule { } diff --git a/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profiles-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profiles-table-config.resolver.ts new file mode 100644 index 0000000000..f33eccf090 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/asset-profile/asset-profiles-table-config.resolver.ts @@ -0,0 +1,190 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable } from '@angular/core'; +import { Resolve, Router } from '@angular/router'; +import { + checkBoxCell, + DateEntityTableColumn, + EntityTableColumn, + EntityTableConfig, + HeaderActionDescriptor +} from '@home/models/entity/entities-table-config.models'; +import { TranslateService } from '@ngx-translate/core'; +import { DatePipe } from '@angular/common'; +import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; +import { EntityAction } from '@home/models/entity/entity-component.models'; +import { DialogService } from '@core/services/dialog.service'; +import { MatDialog } from '@angular/material/dialog'; +import { ImportExportService } from '@home/components/import-export/import-export.service'; +import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; +import { AssetProfile, TB_SERVICE_QUEUE } from '@shared/models/asset.models'; +import { AssetProfileService } from '@core/http/asset-profile.service'; +import { AssetProfileComponent } from '@home/components/profile/asset-profile.component'; +import { AssetProfileTabsComponent } from './asset-profile-tabs.component'; + +@Injectable() +export class AssetProfilesTableConfigResolver implements Resolve> { + + private readonly config: EntityTableConfig = new EntityTableConfig(); + + constructor(private assetProfileService: AssetProfileService, + private importExport: ImportExportService, + private homeDialogs: HomeDialogsService, + private translate: TranslateService, + private datePipe: DatePipe, + private dialogService: DialogService, + private router: Router, + private dialog: MatDialog) { + + this.config.entityType = EntityType.ASSET_PROFILE; + this.config.entityComponent = AssetProfileComponent; + this.config.entityTabsComponent = AssetProfileTabsComponent; + this.config.entityTranslations = entityTypeTranslations.get(EntityType.ASSET_PROFILE); + this.config.entityResources = entityTypeResources.get(EntityType.ASSET_PROFILE); + + this.config.hideDetailsTabsOnEdit = false; + + this.config.columns.push( + new DateEntityTableColumn('createdTime', 'common.created-time', this.datePipe, '150px'), + new EntityTableColumn('name', 'asset-profile.name', '50%'), + new EntityTableColumn('description', 'asset-profile.description', '50%'), + new EntityTableColumn('isDefault', 'asset-profile.default', '60px', + entity => { + return checkBoxCell(entity.default); + }) + ); + + this.config.cellActionDescriptors.push( + { + name: this.translate.instant('asset-profile.export'), + icon: 'file_download', + isEnabled: () => true, + onAction: ($event, entity) => this.exportAssetProfile($event, entity) + }, + { + name: this.translate.instant('asset-profile.set-default'), + icon: 'flag', + isEnabled: (assetProfile) => !assetProfile.default && TB_SERVICE_QUEUE !== assetProfile.name, + onAction: ($event, entity) => this.setDefaultAssetProfile($event, entity) + } + ); + + this.config.deleteEntityTitle = assetProfile => this.translate.instant('asset-profile.delete-asset-profile-title', + { assetProfileName: assetProfile.name }); + this.config.deleteEntityContent = () => this.translate.instant('asset-profile.delete-asset-profile-text'); + this.config.deleteEntitiesTitle = count => this.translate.instant('asset-profile.delete-asset-profiles-title', {count}); + this.config.deleteEntitiesContent = () => this.translate.instant('asset-profile.delete-asset-profiles-text'); + + this.config.entitiesFetchFunction = pageLink => this.assetProfileService.getAssetProfiles(pageLink); + this.config.loadEntity = id => this.assetProfileService.getAssetProfile(id.id); + this.config.saveEntity = assetProfile => this.assetProfileService.saveAssetProfile(assetProfile); + this.config.deleteEntity = id => this.assetProfileService.deleteAssetProfile(id.id); + this.config.onEntityAction = action => this.onAssetProfileAction(action); + this.config.deleteEnabled = (assetProfile) => assetProfile && !assetProfile.default && TB_SERVICE_QUEUE !== assetProfile.name; + this.config.entitySelectionEnabled = (assetProfile) => assetProfile && !assetProfile.default && TB_SERVICE_QUEUE !== assetProfile.name; + this.config.detailsReadonly = (assetProfile) => assetProfile && TB_SERVICE_QUEUE === assetProfile.name; + this.config.addActionDescriptors = this.configureAddActions(); + } + + resolve(): EntityTableConfig { + this.config.tableTitle = this.translate.instant('asset-profile.asset-profiles'); + + return this.config; + } + + configureAddActions(): Array { + const actions: Array = []; + actions.push( + { + name: this.translate.instant('asset-profile.create-asset-profile'), + icon: 'insert_drive_file', + isEnabled: () => true, + onAction: ($event) => this.config.getTable().addEntity($event) + }, + { + name: this.translate.instant('asset-profile.import'), + icon: 'file_upload', + isEnabled: () => true, + onAction: ($event) => this.importAssetProfile($event) + } + ); + return actions; + } + + setDefaultAssetProfile($event: Event, assetProfile: AssetProfile) { + if ($event) { + $event.stopPropagation(); + } + this.dialogService.confirm( + this.translate.instant('asset-profile.set-default-asset-profile-title', {assetProfileName: assetProfile.name}), + this.translate.instant('asset-profile.set-default-asset-profile-text'), + this.translate.instant('action.no'), + this.translate.instant('action.yes'), + true + ).subscribe((res) => { + if (res) { + this.assetProfileService.setDefaultAssetProfile(assetProfile.id.id).subscribe( + () => { + this.config.updateData(); + } + ); + } + } + ); + } + + private openAssetProfile($event: Event, assetProfile: AssetProfile) { + if ($event) { + $event.stopPropagation(); + } + const url = this.router.createUrlTree(['profiles', 'assetProfiles', assetProfile.id.id]); + this.router.navigateByUrl(url); + } + + importAssetProfile($event: Event) { + this.importExport.importAssetProfile().subscribe( + (assetProfile) => { + if (assetProfile) { + this.config.updateData(); + } + } + ); + } + + exportAssetProfile($event: Event, assetProfile: AssetProfile) { + if ($event) { + $event.stopPropagation(); + } + this.importExport.exportAssetProfile(assetProfile.id.id); + } + + onAssetProfileAction(action: EntityAction): boolean { + switch (action.action) { + case 'open': + this.openAssetProfile(action.event, action.entity); + return true; + case 'setDefault': + this.setDefaultAssetProfile(action.event, action.entity); + return true; + case 'export': + this.exportAssetProfile(action.event, action.entity); + return true; + } + return false; + } + +} diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts b/ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts index c4dac29437..b93125758a 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/asset-routing.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.html b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.html index 93bad9b274..1678e34eb3 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.html +++ b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.html @@ -1,6 +1,6 @@ - - + + diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.scss b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.scss index 813272928c..488e5b4c27 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.scss +++ b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ } :host ::ng-deep { - tb-entity-subtype-select { + tb-asset-profile-autocomplete { width: 100%; mat-form-field { diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.ts b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.ts index bd09efb8d5..874f1193cb 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/asset-table-header.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import { AppState } from '@core/core.state'; import { EntityTableHeaderComponent } from '../../components/entity/entity-table-header.component'; import { EntityType } from '@shared/models/entity-type.models'; import { AssetInfo } from '@shared/models/asset.models'; +import { AssetProfileId } from '@shared/models/id/asset-profile-id'; @Component({ selector: 'tb-asset-table-header', @@ -34,8 +35,8 @@ export class AssetTableHeaderComponent extends EntityTableHeaderComponent - - + + asset.label diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset.component.scss b/ui-ngx/src/app/modules/home/pages/asset/asset.component.scss index da8df4b469..66df772d2d 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset.component.scss +++ b/ui-ngx/src/app/modules/home/pages/asset/asset.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts b/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts index a38c1af980..14ca4b4cb0 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/asset.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -67,7 +67,7 @@ export class AssetComponent extends EntityComponent { return this.fb.group( { name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], - type: [entity ? entity.type : null, [Validators.required, Validators.maxLength(255)]], + assetProfileId: [entity ? entity.assetProfileId : null, [Validators.required]], label: [entity ? entity.label : '', Validators.maxLength(255)], additionalInfo: this.fb.group( { @@ -80,7 +80,7 @@ export class AssetComponent extends EntityComponent { updateForm(entity: AssetInfo) { this.entityForm.patchValue({name: entity.name}); - this.entityForm.patchValue({type: entity.type}); + this.entityForm.patchValue({assetProfileId: entity.assetProfileId}); this.entityForm.patchValue({label: entity.label}); this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); } @@ -96,4 +96,8 @@ export class AssetComponent extends EntityComponent { horizontalPosition: 'right' })); } + + onAssetProfileUpdated() { + this.entitiesTableConfig.updateData(false); + } } diff --git a/ui-ngx/src/app/modules/home/pages/asset/asset.module.ts b/ui-ngx/src/app/modules/home/pages/asset/asset.module.ts index 1e94066f82..e2c7465d2c 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/asset.module.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/asset.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts index 46f2bafa87..1e24e75d5e 100644 --- a/ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/asset/assets-table-config.resolver.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -115,6 +115,7 @@ export class AssetsTableConfigResolver implements Resolve> = [ new DateEntityTableColumn('createdTime', 'common.created-time', this.datePipe, '150px'), new EntityTableColumn('name', 'asset.name', '25%'), - new EntityTableColumn('type', 'asset.asset-type', '25%'), - new EntityTableColumn('label', 'asset.label', '25%'), + new EntityTableColumn('assetProfileName', 'asset-profile.asset-profile', '25%'), + new EntityTableColumn('label', 'asset.label', '25%'), ]; if (assetScope === 'tenant') { columns.push( @@ -182,14 +183,16 @@ export class AssetsTableConfigResolver implements Resolve - this.assetService.getTenantAssetInfos(pageLink, this.config.componentsData.assetType); + this.assetService.getTenantAssetInfosByAssetProfileId(pageLink, this.config.componentsData.assetProfileId !== null ? + this.config.componentsData.assetProfileId.id : ''); this.config.deleteEntity = id => this.assetService.deleteAsset(id.id); } else if (assetScope === 'edge' || assetScope === 'edge_customer_user') { this.config.entitiesFetchFunction = pageLink => this.assetService.getEdgeAssets(this.config.componentsData.edgeId, pageLink, this.config.componentsData.assetType); } else { this.config.entitiesFetchFunction = pageLink => - this.assetService.getCustomerAssetInfos(this.customerId, pageLink, this.config.componentsData.assetType); + this.assetService.getCustomerAssetInfosByAssetProfileId(this.customerId, pageLink, + this.config.componentsData.assetProfileId !== null ? this.config.componentsData.assetProfileId.id : ''); this.config.deleteEntity = id => this.assetService.unassignAssetFromCustomer(id.id); } } diff --git a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts index 31d1038a2e..17e5b8c84f 100644 --- a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log-routing.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log.module.ts b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log.module.ts index 6bad9db050..adf7645d9e 100644 --- a/ui-ngx/src/app/modules/home/pages/audit-log/audit-log.module.ts +++ b/ui-ngx/src/app/modules/home/pages/audit-log/audit-log.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts index 36899a657a..d2c02955c2 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/customer/customer-routing.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html b/ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html index 942ea2a73b..e6b374b506 100644 --- a/ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html +++ b/ui-ngx/src/app/modules/home/pages/customer/customer-tabs.component.html @@ -1,6 +1,6 @@

{{data.title}}

-
+
diff --git a/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.scss b/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.scss index 346ec8ad1d..f9550e5497 100644 --- a/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.scss +++ b/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.ts index b83cbda977..f4f4f7dd94 100644 --- a/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/confirm-dialog.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html index b7949d59b7..482c1dd4b1 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html @@ -1,6 +1,6 @@ - + 0) { - if (!this.workFromFileObj) { + if (reader.readyState === reader.DONE) { + if (!this.workFromFileObj) { + fileContent = reader.result; + if (fileContent && fileContent.length > 0) { if (this.contentConvertFunction) { fileContent = this.contentConvertFunction(fileContent); } - if (fileContent) { - fileName = file.name; - } - } else { - files = file.file; - fileName = file.name; + fileName = fileContent ? file.name : null; } + } else if (file.name || file.file){ + files = file.file; + fileName = file.name; } } resolve({fileContent, fileName, files}); diff --git a/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html b/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html index 1eae602456..20820ac320 100644 --- a/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html +++ b/ui-ngx/src/app/shared/components/footer-fab-buttons.component.html @@ -1,6 +1,6 @@
-
+
+ + + +
+
+
+ +
+
-
- - - -
diff --git a/ui-ngx/src/app/shared/components/markdown-editor.component.scss b/ui-ngx/src/app/shared/components/markdown-editor.component.scss index a4149c54d7..1191c97306 100644 --- a/ui-ngx/src/app/shared/components/markdown-editor.component.scss +++ b/ui-ngx/src/app/shared/components/markdown-editor.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,20 +58,15 @@ overflow: auto; height: 100%; } - .buttons-panel { - position: absolute; - top: 5px; - right: 24px; - z-index: 1; - button.edit-toggle { - min-width: 32px; - min-height: 15px; - padding: 4px; - margin: 0; - font-size: .8rem; - line-height: 15px; - color: #7b7b7b; - background: rgba(220, 220, 220, .35); - } + button.panel-button { + background: rgba(220, 220, 220, .35); + align-items: center; + vertical-align: middle; + min-width: 32px; + min-height: 15px; + padding: 4px; + font-size: .8rem; + line-height: 15px; + color: #7b7b7b; } } diff --git a/ui-ngx/src/app/shared/components/markdown-editor.component.ts b/ui-ngx/src/app/shared/components/markdown-editor.component.ts index 7c1c9c7c02..4747254011 100644 --- a/ui-ngx/src/app/shared/components/markdown-editor.component.ts +++ b/ui-ngx/src/app/shared/components/markdown-editor.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, ElementRef, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; +import { Component, ElementRef, forwardRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { Ace } from 'ace-builds'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; @@ -32,7 +32,7 @@ import { getAce } from '@shared/models/ace/ace.models'; } ] }) -export class MarkdownEditorComponent implements OnInit, ControlValueAccessor { +export class MarkdownEditorComponent implements OnInit, ControlValueAccessor, OnDestroy { @Input() label: string; @@ -40,6 +40,8 @@ export class MarkdownEditorComponent implements OnInit, ControlValueAccessor { @Input() readonly: boolean; + @Input() helpId: string; + @ViewChild('markdownEditor', {static: true}) markdownEditorElmRef: ElementRef; @@ -104,6 +106,12 @@ export class MarkdownEditorComponent implements OnInit, ControlValueAccessor { } } + ngOnDestroy(): void { + if (this.markdownEditor) { + this.markdownEditor.destroy(); + } + } + registerOnChange(fn: any): void { this.propagateChange = fn; } diff --git a/ui-ngx/src/app/shared/components/markdown.component.html b/ui-ngx/src/app/shared/components/markdown.component.html index 1b1eb7b8f9..5b8b9f8af0 100644 --- a/ui-ngx/src/app/shared/components/markdown.component.html +++ b/ui-ngx/src/app/shared/components/markdown.component.html @@ -1,6 +1,6 @@ -
@@ -29,12 +28,12 @@
- {{ label | translate }} + {{ label }} diff --git a/ui-ngx/src/app/shared/components/phone-input.component.scss b/ui-ngx/src/app/shared/components/phone-input.component.scss index 432c9d21f2..c9413827cf 100644 --- a/ui-ngx/src/app/shared/components/phone-input.component.scss +++ b/ui-ngx/src/app/shared/components/phone-input.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/components/phone-input.component.ts b/ui-ngx/src/app/shared/components/phone-input.component.ts index 238f3c7134..83d0fb18e8 100644 --- a/ui-ngx/src/app/shared/components/phone-input.component.ts +++ b/ui-ngx/src/app/shared/components/phone-input.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -75,7 +75,7 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida placeholder; @Input() - label = 'phone-input.phone-input-label'; + label = this.translate.instant('phone-input.phone-input-label'); get showFlagSelect(): boolean { return this.enableFlagsSelect && !this.isLegacy; @@ -94,8 +94,12 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida set isLoad(value) { if (this.isLoading) { this.isLoading = value; - if (this.phoneFormGroup) { - this.defineCountryFromNumber(this.phoneFormGroup.get('phoneNumber').value); + if (this.defaultCountry) { + this.getFlagAndPhoneNumberData(this.defaultCountry); + } + if (this.phoneFormGroup && this.phoneFormGroup.get('phoneNumber').value) { + const parsedPhoneNumber = this.parsePhoneNumberFromString(this.phoneFormGroup.get('phoneNumber').value); + this.defineCountryFromNumber(parsedPhoneNumber); } } } @@ -107,7 +111,7 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida private countryCallingCode = '+'; private modelValue: string; private changeSubscriptions: Subscription[] = []; - private validators: ValidatorFn[] = [(c: FormControl) => Validators.pattern(this.getPhoneNumberPattern())(c), this.validatePhoneNumber()]; + private validators: ValidatorFn[] = [this.validatePhoneNumber()]; private propagateChange = (v: any) => { }; @@ -125,15 +129,17 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida this.validators.push(Validators.required); } this.phoneFormGroup = this.fb.group({ - country: [this.defaultCountry, []], + country: [null, []], phoneNumber: [null, this.validators] }); - this.flagIcon = this.getFlagIcon(this.phoneFormGroup.get('country').value); - this.changeSubscriptions.push(this.phoneFormGroup.get('phoneNumber').valueChanges.subscribe(value => { - this.updateModel(); - this.defineCountryFromNumber(value); + let parsedPhoneNumber = null; + if (value && this.parsePhoneNumberFromString) { + parsedPhoneNumber = this.parsePhoneNumberFromString(value); + this.defineCountryFromNumber(parsedPhoneNumber); + } + this.updateModel(parsedPhoneNumber); })); this.changeSubscriptions.push(this.phoneFormGroup.get('country').valueChanges.subscribe(value => { @@ -142,7 +148,7 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida this.getFlagAndPhoneNumberData(value); let phoneNumber = this.phoneFormGroup.get('phoneNumber').value; if (phoneNumber) { - if (code !== this.countryCallingCode && phoneNumber.includes(code)) { + if (code !== '+' && code !== this.countryCallingCode && phoneNumber.includes(code)) { phoneNumber = phoneNumber.replace(code, this.countryCallingCode); this.phoneFormGroup.get('phoneNumber').patchValue(phoneNumber); } @@ -183,6 +189,10 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida return String.fromCodePoint(...countryCode.split('').map(country => this.baseCode + country.charCodeAt(0))); } + private updateModelValueInFormat(parsedPhoneNumber: any) { + this.modelValue = parsedPhoneNumber.format('E.164'); + } + validatePhoneNumber(): ValidatorFn { return (c: FormControl) => { const phoneNumber = c.value; @@ -200,20 +210,13 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida }; } - private defineCountryFromNumber(phoneNumber) { - if (phoneNumber && this.parsePhoneNumberFromString) { - const parsedPhoneNumber = this.parsePhoneNumberFromString(phoneNumber); - const country = this.phoneFormGroup.get('country').value; - if (parsedPhoneNumber?.country && parsedPhoneNumber?.country !== country) { - this.phoneFormGroup.get('country').patchValue(parsedPhoneNumber.country, {emitEvent: true}); - } + private defineCountryFromNumber(parsedPhoneNumber) { + const country = this.phoneFormGroup.get('country').value; + if (parsedPhoneNumber?.country && parsedPhoneNumber?.country !== country) { + this.phoneFormGroup.get('country').patchValue(parsedPhoneNumber.country, {emitEvent: true}); } } - private getPhoneNumberPattern(): RegExp { - return new RegExp(`^${this.countryCallingCode.replace('+', '\\+')}$|^\\+[1-9]\\d{1,14}$`); - } - validate(): ValidationErrors | null { const phoneNumber = this.phoneFormGroup.get('phoneNumber'); return phoneNumber.valid || this.countryCallingCode === phoneNumber.value ? null : { @@ -246,6 +249,8 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida if (phoneNumber) { const parsedPhoneNumber = this.parsePhoneNumberFromString(phoneNumber); if (parsedPhoneNumber?.isValid() && parsedPhoneNumber?.isPossible()) { + country = parsedPhoneNumber?.country || this.defaultCountry; + this.updateModelValueInFormat(parsedPhoneNumber); this.isLegacy = false; } else { const validators = [Validators.maxLength(255)]; @@ -259,18 +264,20 @@ export class PhoneInputComponent implements OnInit, ControlValueAccessor, Valida this.isLegacy = false; } this.phoneFormGroup.updateValueAndValidity({emitEvent: false}); - country = phoneNumber ? this.parsePhoneNumberFromString(phoneNumber)?.country || this.defaultCountry : this.defaultCountry; this.getFlagAndPhoneNumberData(country); } this.phoneFormGroup.reset({phoneNumber, country}, {emitEvent: false}); } - private updateModel() { + private updateModel(parsedPhoneNumber?) { const phoneNumber = this.phoneFormGroup.get('phoneNumber'); if (phoneNumber.value === '+' || phoneNumber.value === this.countryCallingCode) { this.propagateChange(null); } else if (phoneNumber.valid) { this.modelValue = phoneNumber.value; + if (parsedPhoneNumber) { + this.updateModelValueInFormat(parsedPhoneNumber); + } this.propagateChange(this.modelValue); } else { this.propagateChange(null); diff --git a/ui-ngx/src/app/shared/components/popover.component.scss b/ui-ngx/src/app/shared/components/popover.component.scss index 2ef8e8bb34..bc06c50e6e 100644 --- a/ui-ngx/src/app/shared/components/popover.component.scss +++ b/ui-ngx/src/app/shared/components/popover.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/components/popover.component.ts b/ui-ngx/src/app/shared/components/popover.component.ts index 99321974af..e2eb71a5d3 100644 --- a/ui-ngx/src/app/shared/components/popover.component.ts +++ b/ui-ngx/src/app/shared/components/popover.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -57,6 +57,7 @@ import { } from '@shared/components/popover.models'; import { distinctUntilChanged, take, takeUntil } from 'rxjs/operators'; import { isNotEmptyStr, onParentScrollOrWindowResize } from '@core/utils'; +import { animate, AnimationBuilder, AnimationMetadata, style } from '@angular/animations'; export type TbPopoverTrigger = 'click' | 'focus' | 'hover' | null; @@ -304,6 +305,7 @@ export class TbPopoverDirective implements OnChanges, OnDestroy, AfterViewInit {
; + @ViewChild('popover', { static: false }) popover!: ElementRef; tbContent: string | TemplateRef | null = null; tbComponentFactory: ComponentFactory | null = null; @@ -442,6 +445,7 @@ export class TbPopoverComponent implements OnDestroy, OnInit { constructor( public cdr: ChangeDetectorRef, private renderer: Renderer2, + private animationBuilder: AnimationBuilder, @Optional() private directionality: Directionality ) {} @@ -532,6 +536,35 @@ export class TbPopoverComponent implements OnDestroy, OnInit { }); } + resize(width: string, height: string, animationDurationMs?: number) { + if (animationDurationMs && animationDurationMs > 0) { + const prevWidth = this.popover.nativeElement.offsetWidth; + const prevHeight = this.popover.nativeElement.offsetHeight; + const animationMetadata: AnimationMetadata[] = [style({width: prevWidth + 'px', height: prevHeight + 'px'}), + animate(animationDurationMs + 'ms', style({width, height}))]; + const factory = this.animationBuilder.build(animationMetadata); + const player = factory.create(this.popover.nativeElement); + player.play(); + const resize$ = new ResizeObserver(() => { + this.updatePosition(); + }); + resize$.observe(this.popover.nativeElement); + player.onDone(() => { + player.destroy(); + resize$.disconnect(); + this.setSize(width, height); + }); + } else { + this.setSize(width, height); + } + } + + private setSize(width: string, height: string) { + this.renderer.setStyle(this.popover.nativeElement, 'width', width); + this.renderer.setStyle(this.popover.nativeElement, 'height', height); + this.updatePosition(); + } + updatePosition(): void { if (this.origin && this.overlay && this.overlay.overlayRef) { this.overlay.overlayRef.updatePosition(); diff --git a/ui-ngx/src/app/shared/components/popover.models.ts b/ui-ngx/src/app/shared/components/popover.models.ts index 20f0125a98..b9ca5e9d59 100644 --- a/ui-ngx/src/app/shared/components/popover.models.ts +++ b/ui-ngx/src/app/shared/components/popover.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/components/popover.service.ts b/ui-ngx/src/app/shared/components/popover.service.ts index 713e8d337b..5b5de8630f 100644 --- a/ui-ngx/src/app/shared/components/popover.service.ts +++ b/ui-ngx/src/app/shared/components/popover.service.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -16,8 +16,12 @@ import { ComponentFactory, - ComponentFactoryResolver, ElementRef, Inject, - Injectable, Injector, + ComponentFactoryResolver, + ComponentRef, + ElementRef, + Inject, + Injectable, + Injector, Renderer2, Type, ViewContainerRef @@ -53,11 +57,23 @@ export class TbPopoverService { } } + createPopoverRef(hostView: ViewContainerRef): ComponentRef { + return hostView.createComponent(this.componentFactory); + } + displayPopover(trigger: Element, renderer: Renderer2, hostView: ViewContainerRef, componentType: Type, preferredPlacement: PopoverPlacement = 'top', hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { - const componentRef = hostView.createComponent(this.componentFactory); + const componentRef = this.createPopoverRef(hostView); + return this.displayPopoverWithComponentRef(componentRef, trigger, renderer, componentType, preferredPlacement, hideOnClickOutside, + injector, context, overlayStyle, popoverStyle, style, showCloseButton); + } + + displayPopoverWithComponentRef(componentRef: ComponentRef, trigger: Element, renderer: Renderer2, + componentType: Type, preferredPlacement: PopoverPlacement = 'top', + hideOnClickOutside = true, injector?: Injector, context?: any, overlayStyle: any = {}, + popoverStyle: any = {}, style?: any, showCloseButton = true): TbPopoverComponent { const component = componentRef.instance; this.popoverWithTriggers.push({ trigger, diff --git a/ui-ngx/src/app/shared/components/protobuf-content.component.html b/ui-ngx/src/app/shared/components/protobuf-content.component.html index 1e7403182f..20c504d4e4 100644 --- a/ui-ngx/src/app/shared/components/protobuf-content.component.html +++ b/ui-ngx/src/app/shared/components/protobuf-content.component.html @@ -1,6 +1,6 @@ - + + {{ autocompleteHint | translate }} {{ 'queue.queue-required' | translate }} diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.scss b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.scss index 45a4ab9808..30f2d26466 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.scss +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.scss @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - ::ng-deep { .queue-option { .mat-option-text { display: inline; } + .queue-option-description { display: block; overflow: hidden; @@ -27,3 +27,27 @@ } } } + +:host ::ng-deep { + .mat-form-field { + .mat-form-field-wrapper { + padding-bottom: 0px; + + .mat-form-field-underline { + position: initial !important; + display: block; + margin-top: -1px; + } + + .mat-form-field-subscript-wrapper, + .mat-form-field-ripple { + position: initial !important; + display: table; + } + + .mat-form-field-subscript-wrapper { + min-height: calc(1em + 1px); + } + } + } +} diff --git a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts index 4b445b5175..5a863b3aa7 100644 --- a/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/queue/queue-autocomplete.component.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -54,6 +54,9 @@ export class QueueAutocompleteComponent implements ControlValueAccessor, OnInit @Input() requiredText: string; + @Input() + autocompleteHint: string; + private requiredValue: boolean; get required(): boolean { return this.requiredValue; diff --git a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html index 096d06c1ee..0dc0d8189e 100644 --- a/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/relation/relation-type-autocomplete.component.html @@ -1,6 +1,6 @@ +
+ + {{ 'rulenode.script-lang-tbel' | translate }} + {{ 'rulenode.script-lang-java-script' | translate }} + +
diff --git a/ui-ngx/src/app/shared/components/script-lang.component.scss b/ui-ngx/src/app/shared/components/script-lang.component.scss new file mode 100644 index 0000000000..74bdf826ae --- /dev/null +++ b/ui-ngx/src/app/shared/components/script-lang.component.scss @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2023 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +.mat-button-toggle-group.tb-script-lang-toggle-group { + &.mat-button-toggle-group-appearance-standard { + border: none; + border-radius: 18px; + .mat-button-toggle+.mat-button-toggle { + border-left: none; + } + } + .mat-button-toggle { + background: rgba(0, 0, 0, 0.06); + height: 36px; + align-items: center; + display: flex; + + .mat-button-toggle-ripple { + top: 2px; + left: 2px; + right: 2px; + bottom: 2px; + border-radius: 16px; + } + } + .mat-button-toggle-button { + color: #959595; + } + .mat-button-toggle-focus-overlay { + border-radius: 16px; + margin: 2px; + } + .mat-button-toggle-checked .mat-button-toggle-button { + background-color: #305680; + color: #fff; + border-radius: 16px; + margin-left: 2px; + margin-right: 2px; + } + .mat-button-toggle-appearance-standard .mat-button-toggle-label-content { + line-height: 32px; + font-size: 16px; + font-weight: 500; + } + .mat-button-toggle-checked.mat-button-toggle-appearance-standard:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay { + opacity: .01; + } +} diff --git a/ui-ngx/src/app/shared/components/script-lang.component.ts b/ui-ngx/src/app/shared/components/script-lang.component.ts new file mode 100644 index 0000000000..56aad1d145 --- /dev/null +++ b/ui-ngx/src/app/shared/components/script-lang.component.ts @@ -0,0 +1,87 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Component, forwardRef, Input, OnInit, ViewEncapsulation } from '@angular/core'; +import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { PageComponent } from '@shared/components/page.component'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { ScriptLanguage } from '@shared/models/rule-node.models'; + +@Component({ + selector: 'tb-script-lang', + templateUrl: './script-lang.component.html', + styleUrls: ['./script-lang.component.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => TbScriptLangComponent), + multi: true + } + ], + encapsulation: ViewEncapsulation.None +}) +export class TbScriptLangComponent extends PageComponent implements ControlValueAccessor, OnInit { + + scriptLangFormGroup: FormGroup; + + scriptLanguage = ScriptLanguage; + + @Input() + disabled: boolean; + + private propagateChange = null; + + constructor(protected store: Store, + private fb: FormBuilder) { + super(store); + this.scriptLangFormGroup = this.fb.group({ + scriptLang: [null] + }); + } + + ngOnInit() { + this.scriptLangFormGroup.get('scriptLang').valueChanges.subscribe( + (scriptLang) => { + this.updateView(scriptLang); + } + ); + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (this.disabled) { + this.scriptLangFormGroup.disable({emitEvent: false}); + } else { + this.scriptLangFormGroup.enable({emitEvent: false}); + } + } + + writeValue(scriptLang: ScriptLanguage): void { + this.scriptLangFormGroup.get('scriptLang').patchValue(scriptLang, {emitEvent: false}); + } + + updateView(scriptLang: ScriptLanguage) { + this.propagateChange(scriptLang); + } +} diff --git a/ui-ngx/src/app/shared/components/snack-bar-component.html b/ui-ngx/src/app/shared/components/snack-bar-component.html index dfa0ddffa1..090388c24a 100644 --- a/ui-ngx/src/app/shared/components/snack-bar-component.html +++ b/ui-ngx/src/app/shared/components/snack-bar-component.html @@ -1,6 +1,6 @@ - + timezone.timezone , ExportableEntity { + tenantId?: TenantId; + name: string; + description?: string; + default?: boolean; + image?: string; + defaultRuleChainId?: RuleChainId; + defaultDashboardId?: DashboardId; + defaultQueueName?: string; +} + +export interface AssetProfileInfo extends EntityInfoData { + image?: string; + defaultDashboardId?: DashboardId; +} export interface Asset extends BaseData, ExportableEntity { tenantId?: TenantId; @@ -26,12 +48,14 @@ export interface Asset extends BaseData, ExportableEntity { name: string; type: string; label: string; + assetProfileId?: AssetProfileId; additionalInfo?: any; } export interface AssetInfo extends Asset { customerTitle: string; customerIsPublic: boolean; + assetProfileName: string; } export interface AssetSearchQuery extends EntitySearchQuery { diff --git a/ui-ngx/src/app/shared/models/audit-log.models.ts b/ui-ngx/src/app/shared/models/audit-log.models.ts index 056c6aa569..3d9d2322d2 100644 --- a/ui-ngx/src/app/shared/models/audit-log.models.ts +++ b/ui-ngx/src/app/shared/models/audit-log.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/authority.enum.ts b/ui-ngx/src/app/shared/models/authority.enum.ts index 683c153b07..c736fe9cb6 100644 --- a/ui-ngx/src/app/shared/models/authority.enum.ts +++ b/ui-ngx/src/app/shared/models/authority.enum.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/base-data.ts b/ui-ngx/src/app/shared/models/base-data.ts index 7b3ea9a642..ff638a3b95 100644 --- a/ui-ngx/src/app/shared/models/base-data.ts +++ b/ui-ngx/src/app/shared/models/base-data.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/beautify.models.ts b/ui-ngx/src/app/shared/models/beautify.models.ts index 6e2affc6fe..ad7c6427c0 100644 --- a/ui-ngx/src/app/shared/models/beautify.models.ts +++ b/ui-ngx/src/app/shared/models/beautify.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/component-descriptor.models.ts b/ui-ngx/src/app/shared/models/component-descriptor.models.ts index 47e7d5af42..56dd29cb4e 100644 --- a/ui-ngx/src/app/shared/models/component-descriptor.models.ts +++ b/ui-ngx/src/app/shared/models/component-descriptor.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index d793d8082b..bee7ebacc0 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -85,6 +85,9 @@ export const HelpLinks = { ruleNodeGpsGeofencingFilter: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#gps-geofencing-filter-node', ruleNodeJsFilter: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#script-filter-node', ruleNodeJsSwitch: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#switch-node', + ruleNodeAssetProfileSwitch: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#asset-profile-switch', + ruleNodeDeviceProfileSwitch: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#device-profile-switch', + ruleNodeCheckAlarmStatus: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#check-alarm-status', ruleNodeMessageTypeFilter: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#message-type-filter-node', ruleNodeMessageTypeSwitch: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#message-type-switch-node', ruleNodeOriginatorTypeFilter: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/filter-nodes/#originator-type-filter-node', @@ -127,12 +130,14 @@ export const HelpLinks = { ruleNodeRestApiCall: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node', ruleNodeSendEmail: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node', ruleNodeSendSms: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/external-nodes/#send-sms-node', + ruleNodeMath: helpBaseUrl + '/docs/user-guide/rule-engine-2-0/action-nodes/#math-function-node', tenants: helpBaseUrl + '/docs/user-guide/ui/tenants', tenantProfiles: helpBaseUrl + '/docs/user-guide/ui/tenant-profiles', customers: helpBaseUrl + '/docs/user-guide/ui/customers', users: helpBaseUrl + '/docs/user-guide/ui/users', devices: helpBaseUrl + '/docs/user-guide/ui/devices', deviceProfiles: helpBaseUrl + '/docs/user-guide/ui/device-profiles', + assetProfiles: helpBaseUrl + '/docs/user-guide/ui/asset-profiles', edges: helpBaseUrl + '/docs/user-guide/ui/edges', assets: helpBaseUrl + '/docs/user-guide/ui/assets', entityViews: helpBaseUrl + '/docs/user-guide/ui/entity-views', diff --git a/ui-ngx/src/app/shared/models/contact-based.model.ts b/ui-ngx/src/app/shared/models/contact-based.model.ts index f39f1fa290..d7da687098 100644 --- a/ui-ngx/src/app/shared/models/contact-based.model.ts +++ b/ui-ngx/src/app/shared/models/contact-based.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/country.models.ts b/ui-ngx/src/app/shared/models/country.models.ts index afba058c6d..f243ba3a5c 100644 --- a/ui-ngx/src/app/shared/models/country.models.ts +++ b/ui-ngx/src/app/shared/models/country.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/customer.model.ts b/ui-ngx/src/app/shared/models/customer.model.ts index 67c1429189..d26725814f 100644 --- a/ui-ngx/src/app/shared/models/customer.model.ts +++ b/ui-ngx/src/app/shared/models/customer.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/dashboard.models.ts b/ui-ngx/src/app/shared/models/dashboard.models.ts index 12e1c83ada..8548bc73d2 100644 --- a/ui-ngx/src/app/shared/models/dashboard.models.ts +++ b/ui-ngx/src/app/shared/models/dashboard.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import { Widget } from './widget.models'; import { Timewindow } from '@shared/models/time/time.models'; import { EntityAliases } from './alias.models'; import { Filters } from '@shared/models/query/query.models'; +import { MatDialogRef } from '@angular/material/dialog'; export interface DashboardInfo extends BaseData, ExportableEntity { tenantId?: TenantId; @@ -35,6 +36,7 @@ export interface DashboardInfo extends BaseData, ExportableEntity; } export interface HomeDashboard extends Dashboard { diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index d06963544e..5f052d378d 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/edge.models.ts b/ui-ngx/src/app/shared/models/edge.models.ts index 7ffe7270f3..c9caa37ce8 100644 --- a/ui-ngx/src/app/shared/models/edge.models.ts +++ b/ui-ngx/src/app/shared/models/edge.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -45,49 +45,50 @@ export interface EdgeSearchQuery extends EntitySearchQuery { } export enum EdgeEventType { - DASHBOARD = "DASHBOARD", - ASSET = "ASSET", - DEVICE = "DEVICE", - DEVICE_PROFILE = "DEVICE_PROFILE", - ENTITY_VIEW = "ENTITY_VIEW", - ALARM = "ALARM", - RULE_CHAIN = "RULE_CHAIN", - RULE_CHAIN_METADATA = "RULE_CHAIN_METADATA", - EDGE = "EDGE", - USER = "USER", - CUSTOMER = "CUSTOMER", - RELATION = "RELATION", - TENANT = "TENANT", - WIDGETS_BUNDLE = "WIDGETS_BUNDLE", - WIDGET_TYPE = "WIDGET_TYPE", - ADMIN_SETTINGS = "ADMIN_SETTINGS" + DASHBOARD = 'DASHBOARD', + ASSET = 'ASSET', + DEVICE = 'DEVICE', + DEVICE_PROFILE = 'DEVICE_PROFILE', + ASSET_PROFILE = 'ASSET_PROFILE', + ENTITY_VIEW = 'ENTITY_VIEW', + ALARM = 'ALARM', + RULE_CHAIN = 'RULE_CHAIN', + RULE_CHAIN_METADATA = 'RULE_CHAIN_METADATA', + EDGE = 'EDGE', + USER = 'USER', + CUSTOMER = 'CUSTOMER', + RELATION = 'RELATION', + TENANT = 'TENANT', + WIDGETS_BUNDLE = 'WIDGETS_BUNDLE', + WIDGET_TYPE = 'WIDGET_TYPE', + ADMIN_SETTINGS = 'ADMIN_SETTINGS' } export enum EdgeEventActionType { - ADDED = "ADDED", - DELETED = "DELETED", - UPDATED = "UPDATED", - POST_ATTRIBUTES = "POST_ATTRIBUTES", - ATTRIBUTES_UPDATED = "ATTRIBUTES_UPDATED", - ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED", - TIMESERIES_UPDATED = "TIMESERIES_UPDATED", - CREDENTIALS_UPDATED = "CREDENTIALS_UPDATED", - ASSIGNED_TO_CUSTOMER = "ASSIGNED_TO_CUSTOMER", - UNASSIGNED_FROM_CUSTOMER = "UNASSIGNED_FROM_CUSTOMER", - RELATION_ADD_OR_UPDATE = "RELATION_ADD_OR_UPDATE", - RELATION_DELETED = "RELATION_DELETED", - RPC_CALL = "RPC_CALL", - ALARM_ACK = "ALARM_ACK", - ALARM_CLEAR = "ALARM_CLEAR", - ASSIGNED_TO_EDGE = "ASSIGNED_TO_EDGE", - UNASSIGNED_FROM_EDGE = "UNASSIGNED_FROM_EDGE", - CREDENTIALS_REQUEST = "CREDENTIALS_REQUEST", - ENTITY_MERGE_REQUEST = "ENTITY_MERGE_REQUEST" + ADDED = 'ADDED', + DELETED = 'DELETED', + UPDATED = 'UPDATED', + POST_ATTRIBUTES = 'POST_ATTRIBUTES', + ATTRIBUTES_UPDATED = 'ATTRIBUTES_UPDATED', + ATTRIBUTES_DELETED = 'ATTRIBUTES_DELETED', + TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', + CREDENTIALS_UPDATED = 'CREDENTIALS_UPDATED', + ASSIGNED_TO_CUSTOMER = 'ASSIGNED_TO_CUSTOMER', + UNASSIGNED_FROM_CUSTOMER = 'UNASSIGNED_FROM_CUSTOMER', + RELATION_ADD_OR_UPDATE = 'RELATION_ADD_OR_UPDATE', + RELATION_DELETED = 'RELATION_DELETED', + RPC_CALL = 'RPC_CALL', + ALARM_ACK = 'ALARM_ACK', + ALARM_CLEAR = 'ALARM_CLEAR', + ASSIGNED_TO_EDGE = 'ASSIGNED_TO_EDGE', + UNASSIGNED_FROM_EDGE = 'UNASSIGNED_FROM_EDGE', + CREDENTIALS_REQUEST = 'CREDENTIALS_REQUEST', + ENTITY_MERGE_REQUEST = 'ENTITY_MERGE_REQUEST' } export enum EdgeEventStatus { - DEPLOYED = "DEPLOYED", - PENDING = "PENDING" + DEPLOYED = 'DEPLOYED', + PENDING = 'PENDING' } export const edgeEventTypeTranslations = new Map( @@ -96,6 +97,7 @@ export const edgeEventTypeTranslations = new Map( [EdgeEventType.ASSET, 'edge-event.type-asset'], [EdgeEventType.DEVICE, 'edge-event.type-device'], [EdgeEventType.DEVICE_PROFILE, 'edge-event.type-device-profile'], + [EdgeEventType.ASSET_PROFILE, 'edge-event.type-asset-profile'], [EdgeEventType.ENTITY_VIEW, 'edge-event.type-entity-view'], [EdgeEventType.ALARM, 'edge-event.type-alarm'], [EdgeEventType.RULE_CHAIN, 'edge-event.type-rule-chain'], diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index 65753f3962..48d2671ada 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ export enum EntityType { ASSET = 'ASSET', DEVICE = 'DEVICE', DEVICE_PROFILE = 'DEVICE_PROFILE', + ASSET_PROFILE = 'ASSET_PROFILE', ALARM = 'ALARM', RULE_CHAIN = 'RULE_CHAIN', RULE_NODE = 'RULE_NODE', @@ -150,6 +151,20 @@ export const entityTypeTranslations = new Map([ [EntityType.DASHBOARD, '/dashboards'], [EntityType.ASSET, '/assets'], [EntityType.DEVICE, '/devices'], - [EntityType.DEVICE_PROFILE, '/deviceProfiles'], + [EntityType.DEVICE_PROFILE, '/profiles/deviceProfiles'], + [EntityType.ASSET_PROFILE, '/profiles/assetProfiles'], [EntityType.RULE_CHAIN, '/ruleChains'], [EntityType.EDGE, '/edgeInstances'], [EntityType.ENTITY_VIEW, '/entityViews'], diff --git a/ui-ngx/src/app/shared/models/entity-view.models.ts b/ui-ngx/src/app/shared/models/entity-view.models.ts index 9605edfc85..dd16914bc1 100644 --- a/ui-ngx/src/app/shared/models/entity-view.models.ts +++ b/ui-ngx/src/app/shared/models/entity-view.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 8bcfa6c34a..548b912b04 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/error.models.ts b/ui-ngx/src/app/shared/models/error.models.ts index ddc0b676ce..794d8f6891 100644 --- a/ui-ngx/src/app/shared/models/error.models.ts +++ b/ui-ngx/src/app/shared/models/error.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/event.models.ts b/ui-ngx/src/app/shared/models/event.models.ts index 89e93d4fa1..9664c88fcf 100644 --- a/ui-ngx/src/app/shared/models/event.models.ts +++ b/ui-ngx/src/app/shared/models/event.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/alarm-id.ts b/ui-ngx/src/app/shared/models/id/alarm-id.ts index 95d0deb18f..3cd21f1157 100644 --- a/ui-ngx/src/app/shared/models/id/alarm-id.ts +++ b/ui-ngx/src/app/shared/models/id/alarm-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/asset-id.ts b/ui-ngx/src/app/shared/models/id/asset-id.ts index 2a8a911428..9adf209128 100644 --- a/ui-ngx/src/app/shared/models/id/asset-id.ts +++ b/ui-ngx/src/app/shared/models/id/asset-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/asset-profile-id.ts b/ui-ngx/src/app/shared/models/id/asset-profile-id.ts new file mode 100644 index 0000000000..55d36db2fa --- /dev/null +++ b/ui-ngx/src/app/shared/models/id/asset-profile-id.ts @@ -0,0 +1,26 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { EntityId } from './entity-id'; +import { EntityType } from '@shared/models/entity-type.models'; + +export class AssetProfileId implements EntityId { + entityType = EntityType.ASSET_PROFILE; + id: string; + constructor(id: string) { + this.id = id; + } +} diff --git a/ui-ngx/src/app/shared/models/id/audit-log-id.ts b/ui-ngx/src/app/shared/models/id/audit-log-id.ts index ba5e022dbf..bccaa6ed17 100644 --- a/ui-ngx/src/app/shared/models/id/audit-log-id.ts +++ b/ui-ngx/src/app/shared/models/id/audit-log-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/customer-id.ts b/ui-ngx/src/app/shared/models/id/customer-id.ts index e5a6a49601..8e55155c53 100644 --- a/ui-ngx/src/app/shared/models/id/customer-id.ts +++ b/ui-ngx/src/app/shared/models/id/customer-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/dashboard-id.ts b/ui-ngx/src/app/shared/models/id/dashboard-id.ts index 54ae24c2d5..a83900193d 100644 --- a/ui-ngx/src/app/shared/models/id/dashboard-id.ts +++ b/ui-ngx/src/app/shared/models/id/dashboard-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/device-credentials-id.ts b/ui-ngx/src/app/shared/models/id/device-credentials-id.ts index 1f428c0be8..21b73659a6 100644 --- a/ui-ngx/src/app/shared/models/id/device-credentials-id.ts +++ b/ui-ngx/src/app/shared/models/id/device-credentials-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/device-id.ts b/ui-ngx/src/app/shared/models/id/device-id.ts index 2432215133..71cc69de5a 100644 --- a/ui-ngx/src/app/shared/models/id/device-id.ts +++ b/ui-ngx/src/app/shared/models/id/device-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/device-profile-id.ts b/ui-ngx/src/app/shared/models/id/device-profile-id.ts index a50def52ad..a9596461eb 100644 --- a/ui-ngx/src/app/shared/models/id/device-profile-id.ts +++ b/ui-ngx/src/app/shared/models/id/device-profile-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/edge-id.ts b/ui-ngx/src/app/shared/models/id/edge-id.ts index ef21c384e7..5d26c14fee 100644 --- a/ui-ngx/src/app/shared/models/id/edge-id.ts +++ b/ui-ngx/src/app/shared/models/id/edge-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/entity-id.ts b/ui-ngx/src/app/shared/models/id/entity-id.ts index b208de441b..dc71119cbc 100644 --- a/ui-ngx/src/app/shared/models/id/entity-id.ts +++ b/ui-ngx/src/app/shared/models/id/entity-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/entity-view-id.ts b/ui-ngx/src/app/shared/models/id/entity-view-id.ts index d48f29955f..4ee80a8790 100644 --- a/ui-ngx/src/app/shared/models/id/entity-view-id.ts +++ b/ui-ngx/src/app/shared/models/id/entity-view-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/event-id.ts b/ui-ngx/src/app/shared/models/id/event-id.ts index 9d84b95a91..af15972856 100644 --- a/ui-ngx/src/app/shared/models/id/event-id.ts +++ b/ui-ngx/src/app/shared/models/id/event-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/has-uuid.ts b/ui-ngx/src/app/shared/models/id/has-uuid.ts index 2c6cb83715..e53f008c1f 100644 --- a/ui-ngx/src/app/shared/models/id/has-uuid.ts +++ b/ui-ngx/src/app/shared/models/id/has-uuid.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/ota-package-id.ts b/ui-ngx/src/app/shared/models/id/ota-package-id.ts index 41b3f9b7bb..1bf241ee9a 100644 --- a/ui-ngx/src/app/shared/models/id/ota-package-id.ts +++ b/ui-ngx/src/app/shared/models/id/ota-package-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/public-api.ts b/ui-ngx/src/app/shared/models/id/public-api.ts index a737fb6fec..73bb920200 100644 --- a/ui-ngx/src/app/shared/models/id/public-api.ts +++ b/ui-ngx/src/app/shared/models/id/public-api.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -36,3 +36,4 @@ export * from './user-id'; export * from './widget-type-id'; export * from './widgets-bundle-id'; export * from './edge-id'; +export * from './asset-id'; diff --git a/ui-ngx/src/app/shared/models/id/queue-id.ts b/ui-ngx/src/app/shared/models/id/queue-id.ts index b36a12547b..743583e32e 100644 --- a/ui-ngx/src/app/shared/models/id/queue-id.ts +++ b/ui-ngx/src/app/shared/models/id/queue-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/rpc-id.ts b/ui-ngx/src/app/shared/models/id/rpc-id.ts index a3b9cfec91..7173237ac0 100644 --- a/ui-ngx/src/app/shared/models/id/rpc-id.ts +++ b/ui-ngx/src/app/shared/models/id/rpc-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/rule-chain-id.ts b/ui-ngx/src/app/shared/models/id/rule-chain-id.ts index ebcc47d415..27623bd15a 100644 --- a/ui-ngx/src/app/shared/models/id/rule-chain-id.ts +++ b/ui-ngx/src/app/shared/models/id/rule-chain-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/rule-node-id.ts b/ui-ngx/src/app/shared/models/id/rule-node-id.ts index 68ebfc2925..73d57f68f2 100644 --- a/ui-ngx/src/app/shared/models/id/rule-node-id.ts +++ b/ui-ngx/src/app/shared/models/id/rule-node-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/tb-resource-id.ts b/ui-ngx/src/app/shared/models/id/tb-resource-id.ts index f36aa36890..57376181e0 100644 --- a/ui-ngx/src/app/shared/models/id/tb-resource-id.ts +++ b/ui-ngx/src/app/shared/models/id/tb-resource-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/tenant-id.ts b/ui-ngx/src/app/shared/models/id/tenant-id.ts index 078dd0b399..59864eb9d9 100644 --- a/ui-ngx/src/app/shared/models/id/tenant-id.ts +++ b/ui-ngx/src/app/shared/models/id/tenant-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/tenant-profile-id.ts b/ui-ngx/src/app/shared/models/id/tenant-profile-id.ts index 0cef7d7d13..a829b4e82c 100644 --- a/ui-ngx/src/app/shared/models/id/tenant-profile-id.ts +++ b/ui-ngx/src/app/shared/models/id/tenant-profile-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/user-id.ts b/ui-ngx/src/app/shared/models/id/user-id.ts index 392378cd66..59c46be97f 100644 --- a/ui-ngx/src/app/shared/models/id/user-id.ts +++ b/ui-ngx/src/app/shared/models/id/user-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/widget-type-id.ts b/ui-ngx/src/app/shared/models/id/widget-type-id.ts index 38575843be..298ef70ae1 100644 --- a/ui-ngx/src/app/shared/models/id/widget-type-id.ts +++ b/ui-ngx/src/app/shared/models/id/widget-type-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts b/ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts index 9b6f7cee44..fc16726820 100644 --- a/ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts +++ b/ui-ngx/src/app/shared/models/id/widgets-bundle-id.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/login.models.ts b/ui-ngx/src/app/shared/models/login.models.ts index d3f1598fc5..0da429f239 100644 --- a/ui-ngx/src/app/shared/models/login.models.ts +++ b/ui-ngx/src/app/shared/models/login.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts index 9c6b5cce6a..26cff38c28 100644 --- a/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts +++ b/ui-ngx/src/app/shared/models/lwm2m-security-config.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/material.models.ts b/ui-ngx/src/app/shared/models/material.models.ts index 5defa7d044..ea75978f26 100644 --- a/ui-ngx/src/app/shared/models/material.models.ts +++ b/ui-ngx/src/app/shared/models/material.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/oauth2.models.ts b/ui-ngx/src/app/shared/models/oauth2.models.ts index b774546547..483a9553ab 100644 --- a/ui-ngx/src/app/shared/models/oauth2.models.ts +++ b/ui-ngx/src/app/shared/models/oauth2.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/ota-package.models.ts b/ui-ngx/src/app/shared/models/ota-package.models.ts index 34963be66b..3af7b9ae30 100644 --- a/ui-ngx/src/app/shared/models/ota-package.models.ts +++ b/ui-ngx/src/app/shared/models/ota-package.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/page/page-data.ts b/ui-ngx/src/app/shared/models/page/page-data.ts index bc42f93d79..6c144325ee 100644 --- a/ui-ngx/src/app/shared/models/page/page-data.ts +++ b/ui-ngx/src/app/shared/models/page/page-data.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/page/page-link.ts b/ui-ngx/src/app/shared/models/page/page-link.ts index 683b83298c..e55ac494e0 100644 --- a/ui-ngx/src/app/shared/models/page/page-link.ts +++ b/ui-ngx/src/app/shared/models/page/page-link.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/page/public-api.ts b/ui-ngx/src/app/shared/models/page/public-api.ts index eefdd67f71..3bf44ef8e7 100644 --- a/ui-ngx/src/app/shared/models/page/public-api.ts +++ b/ui-ngx/src/app/shared/models/page/public-api.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/page/sort-order.ts b/ui-ngx/src/app/shared/models/page/sort-order.ts index 253d3b313b..f21840c6eb 100644 --- a/ui-ngx/src/app/shared/models/page/sort-order.ts +++ b/ui-ngx/src/app/shared/models/page/sort-order.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/public-api.ts b/ui-ngx/src/app/shared/models/public-api.ts index 8c97669481..b21ad86d59 100644 --- a/ui-ngx/src/app/shared/models/public-api.ts +++ b/ui-ngx/src/app/shared/models/public-api.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/query/query.models.ts b/ui-ngx/src/app/shared/models/query/query.models.ts index 81ab569a88..9c50afecf4 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -738,7 +738,6 @@ export function createDefaultEntityDataPageLink(pageSize: number): EntityDataPag } export const singleEntityDataPageLink: EntityDataPageLink = createDefaultEntityDataPageLink(1); -export const defaultEntityDataPageLink: EntityDataPageLink = createDefaultEntityDataPageLink(1024); export interface EntityCountQuery { entityFilter: EntityFilter; @@ -761,12 +760,19 @@ export interface AlarmDataQuery extends AbstractDataQuery { export interface TsValue { ts: number; value: string; + count?: number; +} + +export interface ComparisonTsValue { + current?: TsValue; + previous?: TsValue; } export interface EntityData { entityId: EntityId; latest: {[entityKeyType: string]: {[key: string]: TsValue}}; timeseries: {[key: string]: Array}; + aggLatest?: {[id: number]: ComparisonTsValue}; } export interface AlarmData extends AlarmInfo { diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index 5814a6eeb9..76ee0bf022 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/relation.models.ts b/ui-ngx/src/app/shared/models/relation.models.ts index e42b915e9e..c51c60664c 100644 --- a/ui-ngx/src/app/shared/models/relation.models.ts +++ b/ui-ngx/src/app/shared/models/relation.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/resource.models.ts b/ui-ngx/src/app/shared/models/resource.models.ts index 778cfb57a4..871bf147ea 100644 --- a/ui-ngx/src/app/shared/models/resource.models.ts +++ b/ui-ngx/src/app/shared/models/resource.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/rpc.models.ts b/ui-ngx/src/app/shared/models/rpc.models.ts index b0c97062ae..cbdda5902a 100644 --- a/ui-ngx/src/app/shared/models/rpc.models.ts +++ b/ui-ngx/src/app/shared/models/rpc.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/rule-chain.models.ts b/ui-ngx/src/app/shared/models/rule-chain.models.ts index 01f9d268c3..20086ca21b 100644 --- a/ui-ngx/src/app/shared/models/rule-chain.models.ts +++ b/ui-ngx/src/app/shared/models/rule-chain.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/rule-node.models.ts b/ui-ngx/src/app/shared/models/rule-node.models.ts index d4273c9911..f6d8ca5af8 100644 --- a/ui-ngx/src/app/shared/models/rule-node.models.ts +++ b/ui-ngx/src/app/shared/models/rule-node.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -328,6 +328,11 @@ export interface FcRuleEdge extends FcEdge { labels?: string[]; } +export enum ScriptLanguage { + JS = 'JS', + TBEL = 'TBEL' +} + export interface TestScriptInputParams { script: string; scriptType: string; @@ -347,6 +352,14 @@ export enum MessageType { POST_TELEMETRY_REQUEST = 'POST_TELEMETRY_REQUEST', TO_SERVER_RPC_REQUEST = 'TO_SERVER_RPC_REQUEST', RPC_CALL_FROM_SERVER_TO_DEVICE = 'RPC_CALL_FROM_SERVER_TO_DEVICE', + RPC_QUEUED = 'RPC_QUEUED', + RPC_SENT = 'RPC_SENT', + RPC_DELIVERED = 'RPC_DELIVERED', + RPC_SUCCESSFUL = 'RPC_SUCCESSFUL', + RPC_TIMEOUT = 'RPC_TIMEOUT', + RPC_EXPIRED = 'RPC_EXPIRED', + RPC_FAILED = 'RPC_FAILED', + RPC_DELETED = 'RPC_DELETED', ACTIVITY_EVENT = 'ACTIVITY_EVENT', INACTIVITY_EVENT = 'INACTIVITY_EVENT', CONNECT_EVENT = 'CONNECT_EVENT', @@ -358,13 +371,12 @@ export enum MessageType { ENTITY_UNASSIGNED = 'ENTITY_UNASSIGNED', ATTRIBUTES_UPDATED = 'ATTRIBUTES_UPDATED', ATTRIBUTES_DELETED = 'ATTRIBUTES_DELETED', + ALARM_ACKNOWLEDGED = 'ALARM_ACKNOWLEDGED', + ALARM_CLEARED = 'ALARM_CLEARED', + ENTITY_ASSIGNED_FROM_TENANT = 'ENTITY_ASSIGNED_FROM_TENANT', + ENTITY_ASSIGNED_TO_TENANT = 'ENTITY_ASSIGNED_TO_TENANT', TIMESERIES_UPDATED = 'TIMESERIES_UPDATED', - TIMESERIES_DELETED = 'TIMESERIES_DELETED', - RPC_QUEUED = 'RPC_QUEUED', - RPC_DELIVERED = 'RPC_DELIVERED', - RPC_SUCCESSFUL = 'RPC_SUCCESSFUL', - RPC_TIMEOUT = 'RPC_TIMEOUT', - RPC_FAILED = 'RPC_FAILED' + TIMESERIES_DELETED = 'TIMESERIES_DELETED' } export const messageTypeNames = new Map( @@ -373,6 +385,14 @@ export const messageTypeNames = new Map( [MessageType.POST_TELEMETRY_REQUEST, 'Post telemetry'], [MessageType.TO_SERVER_RPC_REQUEST, 'RPC Request from Device'], [MessageType.RPC_CALL_FROM_SERVER_TO_DEVICE, 'RPC Request to Device'], + [MessageType.RPC_QUEUED, 'RPC Queued'], + [MessageType.RPC_SENT, 'RPC Sent'], + [MessageType.RPC_DELIVERED, 'RPC Delivered'], + [MessageType.RPC_SUCCESSFUL, 'RPC Successful'], + [MessageType.RPC_TIMEOUT, 'RPC Timeout'], + [MessageType.RPC_EXPIRED, 'RPC Expired'], + [MessageType.RPC_FAILED, 'RPC Failed'], + [MessageType.RPC_DELETED, 'RPC Deleted'], [MessageType.ACTIVITY_EVENT, 'Activity Event'], [MessageType.INACTIVITY_EVENT, 'Inactivity Event'], [MessageType.CONNECT_EVENT, 'Connect Event'], @@ -384,13 +404,12 @@ export const messageTypeNames = new Map( [MessageType.ENTITY_UNASSIGNED, 'Entity Unassigned'], [MessageType.ATTRIBUTES_UPDATED, 'Attributes Updated'], [MessageType.ATTRIBUTES_DELETED, 'Attributes Deleted'], + [MessageType.ALARM_ACKNOWLEDGED, 'Alarm Acknowledged'], + [MessageType.ALARM_CLEARED, 'Alarm Cleared'], + [MessageType.ENTITY_ASSIGNED_FROM_TENANT, 'Entity Assigned From Tenant'], + [MessageType.ENTITY_ASSIGNED_TO_TENANT, 'Entity Assigned To Tenant'], [MessageType.TIMESERIES_UPDATED, 'Timeseries Updated'], - [MessageType.TIMESERIES_DELETED, 'Timeseries Deleted'], - [MessageType.RPC_QUEUED, 'RPC Queued'], - [MessageType.RPC_DELIVERED, 'RPC Delivered'], - [MessageType.RPC_SUCCESSFUL, 'RPC Successful'], - [MessageType.RPC_TIMEOUT, 'RPC Timeout'], - [MessageType.RPC_FAILED, 'RPC Failed'] + [MessageType.TIMESERIES_DELETED, 'Timeseries Deleted'] ] ); @@ -403,6 +422,9 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.geo.TbGpsGeofencingFilterNode': 'ruleNodeGpsGeofencingFilter', 'org.thingsboard.rule.engine.filter.TbJsFilterNode': 'ruleNodeJsFilter', 'org.thingsboard.rule.engine.filter.TbJsSwitchNode': 'ruleNodeJsSwitch', + 'org.thingsboard.rule.engine.filter.TbAssetTypeSwitchNode': 'ruleNodeAssetProfileSwitch', + 'org.thingsboard.rule.engine.filter.TbDeviceTypeSwitchNode': 'ruleNodeDeviceProfileSwitch', + 'org.thingsboard.rule.engine.filter.TbCheckAlarmStatusNode': 'ruleNodeCheckAlarmStatus', 'org.thingsboard.rule.engine.filter.TbMsgTypeFilterNode': 'ruleNodeMessageTypeFilter', 'org.thingsboard.rule.engine.filter.TbMsgTypeSwitchNode': 'ruleNodeMessageTypeSwitch', 'org.thingsboard.rule.engine.filter.TbOriginatorTypeFilterNode': 'ruleNodeOriginatorTypeFilter', @@ -447,6 +469,7 @@ const ruleNodeClazzHelpLinkMap = { 'org.thingsboard.rule.engine.edge.TbMsgPushToEdgeNode': 'ruleNodePushToEdge', 'org.thingsboard.rule.engine.flow.TbRuleChainInputNode': 'ruleNodeRuleChain', 'org.thingsboard.rule.engine.flow.TbRuleChainOutputNode': 'ruleNodeOutputNode', + 'org.thingsboard.rule.engine.math.TbMathNode': 'ruleNodeMath', }; export function getRuleNodeHelpLink(component: RuleNodeComponentDescriptor): string { diff --git a/ui-ngx/src/app/shared/models/settings.models.ts b/ui-ngx/src/app/shared/models/settings.models.ts index c1a7cae87a..a673e0cacc 100644 --- a/ui-ngx/src/app/shared/models/settings.models.ts +++ b/ui-ngx/src/app/shared/models/settings.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -63,6 +63,13 @@ export interface SecuritySettings { passwordPolicy: UserPasswordPolicy; } +export interface JwtSettings { + tokenIssuer: string; + tokenSigningKey: string; + tokenExpirationTime: number; + refreshTokenExpTime: number; +} + export interface UpdateMessage { message: string; updateAvailable: boolean; @@ -411,6 +418,7 @@ export const repositoryAuthMethodTranslationMap = new Map; + startTs: number; + endTs: number; +} + +export interface AggTimeSeriesCmd { + keys: Array; + startTs: number; + timeWindow: number; +} + export class EntityDataCmd implements WebsocketCmd { cmdId: number; query?: EntityDataQuery; historyCmd?: EntityHistoryCmd; latestCmd?: LatestValueCmd; tsCmd?: TimeSeriesCmd; + aggHistoryCmd?: AggEntityHistoryCmd; + aggTsCmd?: AggTimeSeriesCmd; public isEmpty(): boolean { - return !this.query && !this.historyCmd && !this.latestCmd && !this.tsCmd; + return !this.query && !this.historyCmd && !this.latestCmd && !this.tsCmd && !this.aggTsCmd && !this.aggHistoryCmd; } } @@ -212,15 +235,6 @@ export class AlarmDataUnsubscribeCmd implements WebsocketCmd { } export class TelemetryPluginCmdsWrapper { - attrSubCmds: Array; - tsSubCmds: Array; - historyCmds: Array; - entityDataCmds: Array; - entityDataUnsubscribeCmds: Array; - alarmDataCmds: Array; - alarmDataUnsubscribeCmds: Array; - entityCountCmds: Array; - entityCountUnsubscribeCmds: Array; constructor() { this.attrSubCmds = []; @@ -233,6 +247,24 @@ export class TelemetryPluginCmdsWrapper { this.entityCountCmds = []; this.entityCountUnsubscribeCmds = []; } + attrSubCmds: Array; + tsSubCmds: Array; + historyCmds: Array; + entityDataCmds: Array; + entityDataUnsubscribeCmds: Array; + alarmDataCmds: Array; + alarmDataUnsubscribeCmds: Array; + entityCountCmds: Array; + entityCountUnsubscribeCmds: Array; + + private static popCmds(cmds: Array, leftCount: number): Array { + const toPublish = Math.min(cmds.length, leftCount); + if (toPublish > 0) { + return cmds.splice(0, toPublish); + } else { + return []; + } + } public hasCommands(): boolean { return this.tsSubCmds.length > 0 || @@ -261,38 +293,33 @@ export class TelemetryPluginCmdsWrapper { public preparePublishCommands(maxCommands: number): TelemetryPluginCmdsWrapper { const preparedWrapper = new TelemetryPluginCmdsWrapper(); let leftCount = maxCommands; - preparedWrapper.tsSubCmds = this.popCmds(this.tsSubCmds, leftCount); + preparedWrapper.tsSubCmds = TelemetryPluginCmdsWrapper.popCmds(this.tsSubCmds, leftCount); leftCount -= preparedWrapper.tsSubCmds.length; - preparedWrapper.historyCmds = this.popCmds(this.historyCmds, leftCount); + preparedWrapper.historyCmds = TelemetryPluginCmdsWrapper.popCmds(this.historyCmds, leftCount); leftCount -= preparedWrapper.historyCmds.length; - preparedWrapper.attrSubCmds = this.popCmds(this.attrSubCmds, leftCount); + preparedWrapper.attrSubCmds = TelemetryPluginCmdsWrapper.popCmds(this.attrSubCmds, leftCount); leftCount -= preparedWrapper.attrSubCmds.length; - preparedWrapper.entityDataCmds = this.popCmds(this.entityDataCmds, leftCount); + preparedWrapper.entityDataCmds = TelemetryPluginCmdsWrapper.popCmds(this.entityDataCmds, leftCount); leftCount -= preparedWrapper.entityDataCmds.length; - preparedWrapper.entityDataUnsubscribeCmds = this.popCmds(this.entityDataUnsubscribeCmds, leftCount); + preparedWrapper.entityDataUnsubscribeCmds = TelemetryPluginCmdsWrapper.popCmds(this.entityDataUnsubscribeCmds, leftCount); leftCount -= preparedWrapper.entityDataUnsubscribeCmds.length; - preparedWrapper.alarmDataCmds = this.popCmds(this.alarmDataCmds, leftCount); + preparedWrapper.alarmDataCmds = TelemetryPluginCmdsWrapper.popCmds(this.alarmDataCmds, leftCount); leftCount -= preparedWrapper.alarmDataCmds.length; - preparedWrapper.alarmDataUnsubscribeCmds = this.popCmds(this.alarmDataUnsubscribeCmds, leftCount); + preparedWrapper.alarmDataUnsubscribeCmds = TelemetryPluginCmdsWrapper.popCmds(this.alarmDataUnsubscribeCmds, leftCount); leftCount -= preparedWrapper.alarmDataUnsubscribeCmds.length; - preparedWrapper.entityCountCmds = this.popCmds(this.entityCountCmds, leftCount); + preparedWrapper.entityCountCmds = TelemetryPluginCmdsWrapper.popCmds(this.entityCountCmds, leftCount); leftCount -= preparedWrapper.entityCountCmds.length; - preparedWrapper.entityCountUnsubscribeCmds = this.popCmds(this.entityCountUnsubscribeCmds, leftCount); + preparedWrapper.entityCountUnsubscribeCmds = TelemetryPluginCmdsWrapper.popCmds(this.entityCountUnsubscribeCmds, leftCount); return preparedWrapper; } - - private popCmds(cmds: Array, leftCount: number): Array { - const toPublish = Math.min(cmds.length, leftCount); - if (toPublish > 0) { - return cmds.splice(0, toPublish); - } else { - return []; - } - } } export interface SubscriptionData { - [key: string]: [number, any][]; + [key: string]: [number, any, number?][]; +} + +export interface IndexedSubscriptionData { + [id: number]: [number, any, number?][]; } export interface SubscriptionDataHolder { @@ -434,16 +461,7 @@ export class EntityDataUpdate extends DataUpdate { super(msg); } - public prepareData(tsOffset: number) { - if (this.data) { - this.processEntityData(this.data.data, tsOffset); - } - if (this.update) { - this.processEntityData(this.update, tsOffset); - } - } - - private processEntityData(data: Array, tsOffset: number) { + private static processEntityData(data: Array, tsOffset: number) { for (const entityData of data) { if (entityData.timeseries) { for (const key of Object.keys(entityData.timeseries)) { @@ -471,28 +489,28 @@ export class EntityDataUpdate extends DataUpdate { } } } + + public prepareData(tsOffset: number) { + if (this.data) { + EntityDataUpdate.processEntityData(this.data.data, tsOffset); + } + if (this.update) { + EntityDataUpdate.processEntityData(this.update, tsOffset); + } + } } export class AlarmDataUpdate extends DataUpdate { - allowedEntities: number; - totalEntities: number; constructor(msg: AlarmDataUpdateMsg) { super(msg); this.allowedEntities = msg.allowedEntities; this.totalEntities = msg.totalEntities; } + allowedEntities: number; + totalEntities: number; - public prepareData(tsOffset: number) { - if (this.data) { - this.processAlarmData(this.data.data, tsOffset); - } - if (this.update) { - this.processAlarmData(this.update, tsOffset); - } - } - - private processAlarmData(data: Array, tsOffset: number) { + private static processAlarmData(data: Array, tsOffset: number) { for (const alarmData of data) { alarmData.createdTime += tsOffset; if (alarmData.ackTs) { @@ -524,6 +542,15 @@ export class AlarmDataUpdate extends DataUpdate { } } } + + public prepareData(tsOffset: number) { + if (this.data) { + AlarmDataUpdate.processAlarmData(this.data.data, tsOffset); + } + if (this.update) { + AlarmDataUpdate.processAlarmData(this.update, tsOffset); + } + } } export class EntityCountUpdate extends CmdUpdate { diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 27b86583ea..990852ed8c 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/time/time.models.ts b/ui-ngx/src/app/shared/models/time/time.models.ts index 2f90d39ca1..6c04aef946 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -96,6 +96,8 @@ export interface Timewindow { displayValue?: string; displayTimezoneAbbr?: string; hideInterval?: boolean; + hideQuickInterval?: boolean; + hideLastInterval?: boolean; hideAggregation?: boolean; hideAggInterval?: boolean; hideTimezone?: boolean; @@ -188,6 +190,8 @@ export function defaultTimewindow(timeService: TimeService): Timewindow { return { displayValue: '', hideInterval: false, + hideLastInterval: false, + hideQuickInterval: false, hideAggregation: false, hideAggInterval: false, hideTimezone: false, @@ -223,10 +227,12 @@ function getTimewindowType(timewindow: Timewindow): TimewindowType { } } -export function initModelFromDefaultTimewindow(value: Timewindow, timeService: TimeService): Timewindow { +export function initModelFromDefaultTimewindow(value: Timewindow, quickIntervalOnly: boolean, timeService: TimeService): Timewindow { const model = defaultTimewindow(timeService); if (value) { model.hideInterval = value.hideInterval; + model.hideLastInterval = value.hideLastInterval; + model.hideQuickInterval = value.hideQuickInterval; model.hideAggregation = value.hideAggregation; model.hideAggInterval = value.hideAggInterval; model.hideTimezone = value.hideTimezone; @@ -281,6 +287,9 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T } model.timezone = value.timezone; } + if (quickIntervalOnly) { + model.realtime.realtimeType = RealtimeWindowType.INTERVAL; + } return model; } @@ -304,6 +313,8 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number, } return { hideInterval: timewindow.hideInterval || false, + hideLastInterval: timewindow.hideLastInterval || false, + hideQuickInterval: timewindow.hideQuickInterval || false, hideAggregation: timewindow.hideAggregation || false, hideAggInterval: timewindow.hideAggInterval || false, hideTimezone: timewindow.hideTimezone || false, @@ -694,6 +705,8 @@ export function createTimewindowForComparison(subscriptionTimewindow: Subscripti export function cloneSelectedTimewindow(timewindow: Timewindow): Timewindow { const cloned: Timewindow = {}; cloned.hideInterval = timewindow.hideInterval || false; + cloned.hideLastInterval = timewindow.hideLastInterval || false; + cloned.hideQuickInterval = timewindow.hideQuickInterval || false; cloned.hideAggregation = timewindow.hideAggregation || false; cloned.hideAggInterval = timewindow.hideAggInterval || false; cloned.hideTimezone = timewindow.hideTimezone || false; diff --git a/ui-ngx/src/app/shared/models/two-factor-auth.models.ts b/ui-ngx/src/app/shared/models/two-factor-auth.models.ts index d3b2a74fbd..3969845f83 100644 --- a/ui-ngx/src/app/shared/models/two-factor-auth.models.ts +++ b/ui-ngx/src/app/shared/models/two-factor-auth.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/user.model.ts b/ui-ngx/src/app/shared/models/user.model.ts index 42e6407c12..73fe32f1c9 100644 --- a/ui-ngx/src/app/shared/models/user.model.ts +++ b/ui-ngx/src/app/shared/models/user.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/vc.models.ts b/ui-ngx/src/app/shared/models/vc.models.ts index 432332fcee..155a9c8633 100644 --- a/ui-ngx/src/app/shared/models/vc.models.ts +++ b/ui-ngx/src/app/shared/models/vc.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ export const exportableEntityTypes: Array = [ EntityType.DASHBOARD, EntityType.CUSTOMER, EntityType.DEVICE_PROFILE, + EntityType.ASSET_PROFILE, EntityType.RULE_CHAIN, EntityType.WIDGETS_BUNDLE ]; diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 35b3b0fc21..20b5757108 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -17,7 +17,7 @@ import { BaseData } from '@shared/models/base-data'; import { TenantId } from '@shared/models/id/tenant-id'; import { WidgetTypeId } from '@shared/models/id/widget-type-id'; -import { Timewindow } from '@shared/models/time/time.models'; +import { AggregationType, ComparisonDuration, Timewindow } from '@shared/models/time/time.models'; import { EntityType } from '@shared/models/entity-type.models'; import { AlarmSearchStatus, AlarmSeverity } from '@shared/models/alarm.models'; import { DataKeyType } from './telemetry/telemetry.models'; @@ -173,7 +173,7 @@ export interface WidgetTypeParameters { hasAdditionalLatestDataKeys?: boolean; warnOnPageDataOverflow?: boolean; ignoreDataUpdateOnIntervalTick?: boolean; - + processNoDataByWidget?: boolean; } export interface WidgetControllerDescriptor { @@ -259,8 +259,27 @@ export function defaultLegendConfig(wType: widgetType): LegendConfig { }; } +export enum ComparisonResultType { + PREVIOUS_VALUE = 'PREVIOUS_VALUE', + DELTA_ABSOLUTE = 'DELTA_ABSOLUTE', + DELTA_PERCENT = 'DELTA_PERCENT' +} + +export const comparisonResultTypeTranslationMap = new Map( + [ + [ComparisonResultType.PREVIOUS_VALUE, 'datakey.delta-calculation-result-previous-value'], + [ComparisonResultType.DELTA_ABSOLUTE, 'datakey.delta-calculation-result-delta-absolute'], + [ComparisonResultType.DELTA_PERCENT, 'datakey.delta-calculation-result-delta-percent'] + ] +); + export interface KeyInfo { name: string; + aggregationType?: AggregationType; + comparisonEnabled?: boolean; + timeForComparison?: ComparisonDuration; + comparisonCustomIntervalValue?: number; + comparisonResultType?: ComparisonResultType; label?: string; color?: string; funcBody?: string; @@ -269,6 +288,18 @@ export interface KeyInfo { decimals?: number; } +export const dataKeyAggregationTypeHintTranslationMap = new Map( + [ + [AggregationType.MIN, 'datakey.aggregation-type-min-hint'], + [AggregationType.MAX, 'datakey.aggregation-type-max-hint'], + [AggregationType.AVG, 'datakey.aggregation-type-avg-hint'], + [AggregationType.SUM, 'datakey.aggregation-type-sum-hint'], + [AggregationType.COUNT, 'datakey.aggregation-type-count-hint'], + [AggregationType.NONE, 'datakey.aggregation-type-none-hint'], + ] +); + + export interface DataKey extends KeyInfo { type: DataKeyType; pattern?: string; @@ -322,6 +353,37 @@ export interface Datasource { [key: string]: any; } +export function datasourcesHasAggregation(datasources?: Array): boolean { + if (datasources) { + const foundDatasource = datasources.find(datasource => { + const found = datasource.dataKeys && datasource.dataKeys.find(key => key.type === DataKeyType.timeseries && + key.aggregationType && key.aggregationType !== AggregationType.NONE); + return !!found; + }); + if (foundDatasource) { + return true; + } + } + return false; +} + +export function datasourcesHasOnlyComparisonAggregation(datasources?: Array): boolean { + if (!datasourcesHasAggregation(datasources)) { + return false; + } + if (datasources) { + const foundDatasource = datasources.find(datasource => { + const found = datasource.dataKeys && datasource.dataKeys.find(key => key.type === DataKeyType.timeseries && + key.aggregationType && key.aggregationType !== AggregationType.NONE && !key.comparisonEnabled); + return !!found; + }); + if (foundDatasource) { + return false; + } + } + return true; +} + export interface FormattedData { $datasource: Datasource; entityName: string; @@ -544,6 +606,7 @@ export interface WidgetConfig { showLegend?: boolean; legendConfig?: LegendConfig; timewindow?: Timewindow; + desktopHide?: boolean; mobileHide?: boolean; mobileHeight?: number; mobileOrder?: number; diff --git a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts index 235190ead2..c7eb999221 100644 --- a/ui-ngx/src/app/shared/models/widgets-bundle.model.ts +++ b/ui-ngx/src/app/shared/models/widgets-bundle.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/models/window-message.model.ts b/ui-ngx/src/app/shared/models/window-message.model.ts index dff6898958..f720f2692f 100644 --- a/ui-ngx/src/app/shared/models/window-message.model.ts +++ b/ui-ngx/src/app/shared/models/window-message.model.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/enum-to-array.pipe.ts b/ui-ngx/src/app/shared/pipe/enum-to-array.pipe.ts index e879727dd5..befd9a7b56 100644 --- a/ui-ngx/src/app/shared/pipe/enum-to-array.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/enum-to-array.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/file-size.pipe.ts b/ui-ngx/src/app/shared/pipe/file-size.pipe.ts index bfab9ee5c3..dc67cd216d 100644 --- a/ui-ngx/src/app/shared/pipe/file-size.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/file-size.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts index 5a676cc96b..0f8595fc3b 100644 --- a/ui-ngx/src/app/shared/pipe/highlight.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/highlight.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts b/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts index b11c518d40..12104356d0 100644 --- a/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/keyboard-shortcut.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts b/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts index 6722f2f72e..df185fe8d0 100644 --- a/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/milliseconds-to-time-string.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -25,33 +25,51 @@ export class MillisecondsToTimeStringPipe implements PipeTransform { constructor(private translate: TranslateService) { } - transform(millseconds: number, args?: any): string { + transform(millseconds: number, shortFormat = false): string { let seconds = Math.floor(millseconds / 1000); const days = Math.floor(seconds / 86400); let hours = Math.floor((seconds % 86400) / 3600); let minutes = Math.floor(((seconds % 86400) % 3600) / 60); seconds = seconds % 60; let timeString = ''; - if (days > 0) { - timeString += this.translate.instant('timewindow.days', {days}); - } - if (hours > 0) { - if (timeString.length === 0 && hours === 1) { - hours = 0; + if (shortFormat) { + if (days > 0) { + timeString += this.translate.instant('timewindow.short.days', {days}); } - timeString += this.translate.instant('timewindow.hours', {hours}); - } - if (minutes > 0) { - if (timeString.length === 0 && minutes === 1) { - minutes = 0; + if (hours > 0) { + timeString += this.translate.instant('timewindow.short.hours', {hours}); } - timeString += this.translate.instant('timewindow.minutes', {minutes}); - } - if (seconds > 0) { - if (timeString.length === 0 && seconds === 1) { - seconds = 0; + if (minutes > 0) { + timeString += this.translate.instant('timewindow.short.minutes', {minutes}); + } + if (seconds > 0) { + timeString += this.translate.instant('timewindow.short.seconds', {seconds}); + } + if (!timeString.length) { + timeString += this.translate.instant('timewindow.short.seconds', {seconds: 0}); + } + } else { + if (days > 0) { + timeString += this.translate.instant('timewindow.days', {days}); + } + if (hours > 0) { + if (timeString.length === 0 && hours === 1) { + hours = 0; + } + timeString += this.translate.instant('timewindow.hours', {hours}); + } + if (minutes > 0) { + if (timeString.length === 0 && minutes === 1) { + minutes = 0; + } + timeString += this.translate.instant('timewindow.minutes', {minutes}); + } + if (seconds > 0) { + if (timeString.length === 0 && seconds === 1) { + seconds = 0; + } + timeString += this.translate.instant('timewindow.seconds', {seconds}); } - timeString += this.translate.instant('timewindow.seconds', {seconds}); } return timeString; } diff --git a/ui-ngx/src/app/shared/pipe/nospace.pipe.ts b/ui-ngx/src/app/shared/pipe/nospace.pipe.ts index d702464d3b..155f648ae0 100644 --- a/ui-ngx/src/app/shared/pipe/nospace.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/nospace.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/public-api.ts b/ui-ngx/src/app/shared/pipe/public-api.ts index dc810aaaf1..5e5e53b864 100644 --- a/ui-ngx/src/app/shared/pipe/public-api.ts +++ b/ui-ngx/src/app/shared/pipe/public-api.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/safe.pipe.ts b/ui-ngx/src/app/shared/pipe/safe.pipe.ts index 67243802f5..22cf9e4a50 100644 --- a/ui-ngx/src/app/shared/pipe/safe.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/safe.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/selectable-columns.pipe.ts b/ui-ngx/src/app/shared/pipe/selectable-columns.pipe.ts index 9ee424bd68..e71ba26787 100644 --- a/ui-ngx/src/app/shared/pipe/selectable-columns.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/selectable-columns.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/tbJson.pipe.ts b/ui-ngx/src/app/shared/pipe/tbJson.pipe.ts index 41385c2f1a..edf55e1f0c 100644 --- a/ui-ngx/src/app/shared/pipe/tbJson.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/tbJson.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/pipe/truncate.pipe.ts b/ui-ngx/src/app/shared/pipe/truncate.pipe.ts index 5e7c8d6f69..db2d0ccb09 100644 --- a/ui-ngx/src/app/shared/pipe/truncate.pipe.ts +++ b/ui-ngx/src/app/shared/pipe/truncate.pipe.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/public-api.ts b/ui-ngx/src/app/shared/public-api.ts index e289cc9339..f63b26e18c 100644 --- a/ui-ngx/src/app/shared/public-api.ts +++ b/ui-ngx/src/app/shared/public-api.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/app/shared/services/custom-paginator-intl.ts b/ui-ngx/src/app/shared/services/custom-paginator-intl.ts new file mode 100644 index 0000000000..fa52a99f3b --- /dev/null +++ b/ui-ngx/src/app/shared/services/custom-paginator-intl.ts @@ -0,0 +1,40 @@ +/// +/// Copyright © 2016-2023 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable } from '@angular/core'; +import { MatPaginatorIntl } from '@angular/material/paginator'; +import { Subject } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable() +export class CustomPaginatorIntl implements MatPaginatorIntl { + constructor(private translate: TranslateService) {} + changes = new Subject(); + + firstPageLabel = this.translate.instant('paginator.first-page-label'); + itemsPerPageLabel = this.translate.instant('paginator.items-per-page'); + lastPageLabel = this.translate.instant('paginator.last-page-label'); + + nextPageLabel = this.translate.instant('paginator.next-page-label'); + previousPageLabel = this.translate.instant('paginator.previous-page-label'); + separator = this.translate.instant('paginator.items-per-page-separator'); + + getRangeLabel(page: number, pageSize: number, length: number): string { + const startNumber = page * pageSize + 1; + const endNumber = pageSize * (page + 1); + return `${startNumber} – ${endNumber > length ? length : endNumber} ${this.separator} ${length}`; + } +} diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index aaa29f02c0..5c5d24fc55 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import Flow from '@flowjs/flow.js'; import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatButtonModule } from '@angular/material/button'; +import { MatButtonToggleModule } from '@angular/material/button-toggle'; import { MatCardModule } from '@angular/material/card'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatChipsModule } from '@angular/material/chips'; @@ -37,7 +38,7 @@ import { MatGridListModule } from '@angular/material/grid-list'; import { MatIconModule } from '@angular/material/icon'; import { MatInputModule } from '@angular/material/input'; import { MatMenuModule } from '@angular/material/menu'; -import { MatPaginatorModule } from '@angular/material/paginator'; +import { MatPaginatorIntl, MatPaginatorModule } from '@angular/material/paginator'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatRadioModule } from '@angular/material/radio'; @@ -53,7 +54,7 @@ import { MatTabsModule } from '@angular/material/tabs'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatListModule } from '@angular/material/list'; -import { MatDatetimepickerModule, MatNativeDatetimeModule } from '@mat-datetimepicker/core'; +import { DatetimeAdapter, MatDatetimepickerModule, MatNativeDatetimeModule } from '@mat-datetimepicker/core'; import { NgxDaterangepickerMd } from 'ngx-daterangepicker-material'; import { GridsterModule } from 'angular-gridster2'; import { FlexLayoutModule } from '@angular/flex-layout'; @@ -165,6 +166,9 @@ import { DragDropModule } from '@angular/cdk/drag-drop'; import { MultipleImageInputComponent } from '@shared/components/multiple-image-input.component'; import { BranchAutocompleteComponent } from '@shared/components/vc/branch-autocomplete.component'; import { PhoneInputComponent } from '@shared/components/phone-input.component'; +import { CustomDateAdapter } from '@shared/adapter/custom-datatime-adapter'; +import { CustomPaginatorIntl } from '@shared/services/custom-paginator-intl'; +import { TbScriptLangComponent } from '@shared/components/script-lang.component'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -188,8 +192,10 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) provide: MAT_DATE_LOCALE, useValue: 'en-GB' }, + { provide: DatetimeAdapter, useClass: CustomDateAdapter }, { provide: HELP_MARKDOWN_COMPONENT_TOKEN, useValue: HelpMarkdownComponent }, { provide: SHARED_MODULE_TOKEN, useValue: SharedModule }, + { provide: MatPaginatorIntl, useClass: CustomPaginatorIntl }, TbPopoverService ], declarations: [ @@ -288,13 +294,15 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) TogglePasswordComponent, ProtobufContentComponent, BranchAutocompleteComponent, - PhoneInputComponent + PhoneInputComponent, + TbScriptLangComponent ], imports: [ CommonModule, RouterModule, TranslateModule, MatButtonModule, + MatButtonToggleModule, MatCheckboxModule, MatIconModule, MatCardModule, @@ -406,6 +414,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) WidgetsBundleSelectComponent, ValueInputComponent, MatButtonModule, + MatButtonToggleModule, MatCheckboxModule, MatIconModule, MatCardModule, @@ -490,7 +499,8 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) TogglePasswordComponent, ProtobufContentComponent, BranchAutocompleteComponent, - PhoneInputComponent + PhoneInputComponent, + TbScriptLangComponent ] }) export class SharedModule { } diff --git a/ui-ngx/src/assets/fonts/material-icons.css b/ui-ngx/src/assets/fonts/material-icons.css index f790ddaf43..3809ea3696 100644 --- a/ui-ngx/src/assets/fonts/material-icons.css +++ b/ui-ngx/src/assets/fonts/material-icons.css @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2022 The Thingsboard Authors + * Copyright © 2016-2023 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md index 74e4c83828..eed5cb2f07 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/clear_alarm_node_script_fn.md @@ -22,9 +22,10 @@ Current Alarm Details can be accessed via `metadata.prevAlarmDetails`.
```javascript var details = {}; if (metadata.prevAlarmDetails) { + details = JSON.parse(metadata.prevAlarmDetails); // remove prevAlarmDetails from metadata delete metadata.prevAlarmDetails; - details = JSON.parse(metadata.prevAlarmDetails); + //now metadata is the same as it comes IN this rule node } {:copy-code} ``` diff --git a/ui-ngx/src/assets/help/en_US/rulenode/create_alarm_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/create_alarm_node_script_fn.md index c6c2fe2481..36bdd21d16 100644 --- a/ui-ngx/src/assets/help/en_US/rulenode/create_alarm_node_script_fn.md +++ b/ui-ngx/src/assets/help/en_US/rulenode/create_alarm_node_script_fn.md @@ -22,10 +22,11 @@ is a raw String field, and it needs to be converted into object using this const ```javascript var details = {}; -if (metadata.prevAlarmDetails) { - // remove prevAlarmDetails from metadata - delete metadata.prevAlarmDetails; +if (metadata.prevAlarmDetails != null) { details = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + metadata.remove('prevAlarmDetails'); + //now metadata is the same as it comes IN this rule node } {:copy-code} ``` @@ -44,11 +45,11 @@ Also put temperature attribute from inbound Message payload into Al ```javascript var details = {temperature: msg.temperature, count: 1}; -if (metadata.prevAlarmDetails) { +if (metadata.prevAlarmDetails != null) { var prevDetails = JSON.parse(metadata.prevAlarmDetails); // remove prevAlarmDetails from metadata - delete metadata.prevAlarmDetails; - if (prevDetails.count) { + metadata.remove('prevAlarmDetails'); + if (prevDetails.count != null) { details.count = prevDetails.count + 1; } } diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/clear_alarm_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/clear_alarm_node_script_fn.md new file mode 100644 index 0000000000..311086e785 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/clear_alarm_node_script_fn.md @@ -0,0 +1,69 @@ +#### Clear alarm details builder function + +
+
+ +*function Details(msg, metadata, msgType): any* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function generating **Alarm Details** object to update existing one. Used for storing additional parameters inside Alarm.
+For example you can save attribute name/value pair from Original Message payload or Metadata. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Should return the object presenting **Alarm Details**. + +Current Alarm Details can be accessed via `metadata.prevAlarmDetails`.
+**Note** that `metadata.prevAlarmDetails` is a raw String field, and it needs to be converted into object using this construction: + +```javascript +var details = {}; +if (metadata.prevAlarmDetails != null) { + details = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + metadata.remove('prevAlarmDetails'); + //now metadata is the same as it comes IN this rule node +} +{:copy-code} +``` + +
+ +##### Examples + +
    +
  • +Take count property from previous Alarm and increment it.
    +Also put temperature attribute from inbound Message payload into Alarm details: +
  • +
+ +```javascript +var details = {temperature: msg.temperature, count: 1}; + +if (metadata.prevAlarmDetails != null) { + var prevDetails = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + metadata.remove('prevAlarmDetails'); + if (prevDetails.count != null) { + details.count = prevDetails.count + 1; + } +} + +return details; +{:copy-code} +``` + +
+ +More details about Alarms can be found in [this tutorial{:target="_blank"}](${siteBaseUrl}/docs/user-guide/alarms/). + +You can see the real life example, where this node is used, in the next tutorial: + +- [Create and Clear Alarms{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/) + +
+
diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/common_node_script_args.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/common_node_script_args.md new file mode 100644 index 0000000000..296e5b735c --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/common_node_script_args.md @@ -0,0 +1,11 @@ +
    +
  • msg: {[key: string]: any} - is a Message payload key/value object. +
  • +
  • metadata: {[key: string]: string} - is a Message metadata key/value map, where both keys and values are strings. +
  • +
  • msgType: string - is a string containing Message type. See MessageType enum for common used values. +
  • +
+ +Enable 'debug mode' for your rule node to see the messages that arrive in near real-time. +See Debugging for more information. \ No newline at end of file diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/create_alarm_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/create_alarm_node_script_fn.md new file mode 100644 index 0000000000..afc9051590 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/create_alarm_node_script_fn.md @@ -0,0 +1,69 @@ +#### Create alarm details builder function + +
+
+ +*function Details(msg, metadata, msgType): any* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function generating **Alarm Details** object. Used for storing additional parameters inside Alarm.
+For example you can save attribute name/value pair from Original Message payload or Metadata. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Should return the object presenting **Alarm Details**. + +**Optional:** previous Alarm Details can be accessed via `metadata.prevAlarmDetails`.
+If previous Alarm does not exist, this field will not be present in Metadata. **Note** that `metadata.prevAlarmDetails`
+is a raw String field, and it needs to be converted into object using this construction: + +```javascript +var details = {}; +if (metadata.prevAlarmDetails) { + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + details = JSON.parse(metadata.prevAlarmDetails); +} +{:copy-code} +``` + +
+ +##### Examples + +
    +
  • +Take count property from previous Alarm and increment it.
    +Also put temperature attribute from inbound Message payload into Alarm details: +
  • +
+ +```javascript +var details = {temperature: msg.temperature, count: 1}; + +if (metadata.prevAlarmDetails) { + var prevDetails = JSON.parse(metadata.prevAlarmDetails); + // remove prevAlarmDetails from metadata + delete metadata.prevAlarmDetails; + if (prevDetails.count) { + details.count = prevDetails.count + 1; + } +} + +return details; +{:copy-code} +``` + +
+ +More details about Alarms can be found in [this tutorial{:target="_blank"}](${siteBaseUrl}/docs/user-guide/alarms/). + +You can see the real life example, where this node is used, in the next tutorial: + +- [Create and Clear Alarms{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/) + +
+
diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/filter_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/filter_node_script_fn.md new file mode 100644 index 0000000000..4435acaeff --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/filter_node_script_fn.md @@ -0,0 +1,84 @@ +#### Filter message function + +
+
+ +*function Filter(msg, metadata, msgType): boolean* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function defines a boolean expression based on the incoming Message and Metadata. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Must return a `boolean` value. If `true` - routes Message to subsequent rule nodes that are related via **True** link, +otherwise sends Message to rule nodes related via **False** link. +Uses 'Failure' link in case of any failures to evaluate the expression. + +
+ +##### Examples + +* Forward all messages with `temperature` value greater than `20` to the **True** link and all other messages to the **False** link. + Assumes that incoming messages always contain the 'temperature' field: + +```javascript +return msg.temperature > 20; +{:copy-code} +``` + + +Example of the rule chain configuration: + +![image](${helpBaseUrl}/help/images/rulenode/examples/filter-node.png) + +* Same as above, but checks that the message has 'temperature' field to **avoid failures** on unexpected messages: + +```javascript +return msg.temperature != null && msg.temperature > 20; +{:copy-code} +``` + +* Forward all messages with type `ATTRIBUTES_UPDATED` to the **True** chain and all other messages to the **False** chain: + +```javascript +if (msgType == 'ATTRIBUTES_UPDATED') { + return true; +} else { + return false; +} +{:copy-code} +``` + +
    +
  • Send message to the True chain if the following conditions are met.
    Message type is POST_TELEMETRY_REQUEST and
    +(device type is vehicle and humidity value is greater than 50 or
    +device type is controller and temperature value is greater than 20 and humidity value is greater than 60).
    +Otherwise send message to the False chain: +
  • +
+ +```javascript +if (msgType == 'POST_TELEMETRY_REQUEST') { + if (metadata.deviceType == 'vehicle') { + return msg.humidity > 50; + } else if (metadata.deviceType == 'controller') { + return msg.temperature > 20 && msg.humidity > 60; + } +} +return false; +{:copy-code} +``` + +
+ +You can see real life example, how to use this node in those tutorials: + +- [Create and Clear Alarms{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/create-clear-alarms/#node-a-filter-script) +- [Reply to RPC Calls{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#add-filter-script-node) + +
+
+ diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/generator_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/generator_node_script_fn.md new file mode 100644 index 0000000000..7618ac4090 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/generator_node_script_fn.md @@ -0,0 +1,110 @@ +#### Message generator function + +
+
+ +*function Generate(prevMsg, prevMetadata, prevMsgType): {msg: object, metadata: object, msgType: string}* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function generating new Message using previous Message payload, Metadata and Message type as input arguments. + +**Parameters:** + +
    +
  • prevMsg: {[key: string]: any} - is a previously generated Message payload key/value object. +
  • +
  • prevMetadata: {[key: string]: string} - is a previously generated Message metadata key/value object. +
  • +
  • prevMsgType: string - is a previously generated string Message type. See MessageType enum for common used values. +
  • +
+ +**Returns:** + +Should return the object with the following structure: + +```javascript +{ + msg: {[key: string]: any}, + metadata: {[key: string]: string}, + msgType: string +} +``` + +All fields in resulting object are mandatory. + +
+ +##### Examples + +* Generate message of type `POST_TELEMETRY_REQUEST` with random `temperature` value from `18` to `32`: + +```javascript +var temperature = 18 + Math.random() * (32 - 18); +// Round to at most 2 decimal places (optional) +temperature = Math.round( temperature * 100 ) / 100; +var msg = { temperature: temperature }; +return { msg: msg, metadata: {}, msgType: "POST_TELEMETRY_REQUEST" }; +{:copy-code} +``` + + +
    +
  • +Generate message of type POST_TELEMETRY_REQUEST with temp value 42, +humidity value 77
    +and metadata with field data having value 40: +
  • +
+ +```javascript +var msg = { temp: 42, humidity: 77 }; +var metadata = { data: 40 }; +return { msg: msg, metadata: metadata, msgType: "POST_TELEMETRY_REQUEST" }; +{:copy-code} +``` + +
    +
  • +Generate message of type POST_TELEMETRY_REQUEST with temperature value
    +increasing and decreasing linearly in the range from 18 to 32: +
  • +
+ +```javascript +var lower = 18; +var upper = 32; +var isDecrement = 'false'; +var temperature = lower; + +// Get previous values + +if (prevMetadata != null && prevMetadata.isDecrement != null) { + isDecrement = prevMetadata.isDecrement; +} +if (prevMsg != null && prevMsg.temperature != null) { + temperature = prevMsg.temperature; +} + +if (isDecrement == 'true') { + temperature--; + if (temperature <= lower) { + isDecrement = 'false'; + temperature = lower; + } +} else { + temperature++; + if (temperature >= upper) { + isDecrement = 'true'; + temperature = upper; + } +} + +var msg = { temperature: temperature }; +var metadata = { isDecrement: isDecrement }; + +return { msg: msg, metadata: metadata, msgType: "POST_TELEMETRY_REQUEST" }; +{:copy-code} +``` + +
+
diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/log_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/log_node_script_fn.md new file mode 100644 index 0000000000..bab38ad46f --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/log_node_script_fn.md @@ -0,0 +1,37 @@ +#### Message to string function + +
+
+ +*function toString(msg, metadata, msgType): string* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function transforming incoming Message to String for further logging to the server log file. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Should return `string` value used for logging to the server log file. + +
+ +##### Examples + +* Create string message containing incoming message and incoming metadata values: + +```javascript +return 'Incoming message:\n' + JSON.stringify(msg) + + '\nIncoming metadata:\n' + JSON.stringify(metadata); +{:copy-code} +``` + +
+ +You can see real life example, how to use this node in this tutorial: + +- [Reply to RPC Calls{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#log-unknown-request) + +
+
diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/switch_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/switch_node_script_fn.md new file mode 100644 index 0000000000..7fd3b7447b --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/switch_node_script_fn.md @@ -0,0 +1,101 @@ +#### Switch message function + +
+
+ +*function Switch(msg, metadata, msgType): string[]* + +[TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function computing **an array of Link names** to forward the incoming Message. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Should return an array of `string` values presenting **link names** that the Rule Engine should use to further route the incoming Message.
+If the result is an empty array - message will not be routed to any Node and will be immediately +acknowledged. + +
+ +##### Examples + +
    +
  • +Forward all messages with temperature value greater than 30 to the 'High temperature' chain,
    +with temperature value lower than 20 to the 'Low temperature' chain and all other messages
    +to the 'Other' chain: +
  • +
+ +```javascript +if (msg.temperature > 30) { + return ['High temperature']; +} else if (msg.temperature < 20) { + return ['Low temperature']; +} else { + return ['Other']; +} +{:copy-code} +``` + +Example of the rule chain configuration: + +![image](${helpBaseUrl}/help/images/rulenode/examples/switch-node.png) + +
    +
  • + For messages with type POST_TELEMETRY_REQUEST: +
      +
    • + if temperature value lower than 18 forward to the 'Low temperature telemetry' chain, +
    • +
    • + otherwise to the 'Normal temperature telemetry' chain. +
    • +
    + For messages with type POST_ATTRIBUTES_REQUEST:
    +
      +
    • + if currentState value is IDLE forward to the 'Idle State' and 'Update State Attribute' chains, +
    • +
    • + if currentState value is RUNNING forward to the 'Running State' and 'Update State Attribute' chains, +
    • +
    • + otherwise to the 'Unknown State' chain. +
    • +
    + For all other message types - discard the message (do not route to any Node). +
  • +
+ +```javascript +if (msgType == 'POST_TELEMETRY_REQUEST') { + if (msg.temperature < 18) { + return ['Low Temperature Telemetry']; + } else { + return ['Normal Temperature Telemetry']; + } +} else if (msgType == 'POST_ATTRIBUTES_REQUEST') { + if (msg.currentState == 'IDLE') { + return ['Idle State', 'Update State Attribute']; + } else if (msg.currentState == 'RUNNING') { + return ['Running State', 'Update State Attribute']; + } else { + return ['Unknown State']; + } +} +return []; +{:copy-code} +``` + +
+ +You can see real life example, how to use this node in this tutorial: + +- [Data function based on telemetry from 2 devices{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/function-based-on-telemetry-from-two-devices#delta-temperature-rule-chain) + +
+
diff --git a/ui-ngx/src/assets/help/en_US/rulenode/tbel/transformation_node_script_fn.md b/ui-ngx/src/assets/help/en_US/rulenode/tbel/transformation_node_script_fn.md new file mode 100644 index 0000000000..44ada19967 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/rulenode/tbel/transformation_node_script_fn.md @@ -0,0 +1,89 @@ +#### Transform message function + +
+
+ +*function Transform(msg, metadata, msgType): {msg: object, metadata: object, msgType: string}* + +The [TBEL{:target="_blank"}](${siteBaseUrl}/docs/user-guide/tbel/) function to transform input Message payload, Metadata and/or Message type to the output message. + +**Parameters:** + +{% include rulenode/tbel/common_node_script_args %} + +**Returns:** + +Should return the object with the following structure: + +```javascript +{ + msg?: {[key: string]: any}, + metadata?: {[key: string]: string}, + msgType?: string +} +``` + +All fields in resulting object are optional and will be taken from original message if not specified. + +
+ +##### Examples + +* Add sum of two fields ('a' and 'b') as a new field ('sum') of existing message: + +```javascript +if(msg.a != null && msg.b != null){ + msg.sum = msg.a + msg.b; +} +return {msg: msg}; +``` + +* Transform value of the 'temperature' field from °F to °C: + +```javascript +msg.temperature = toFixed((msg.temperature - 32) * 5 / 9, 1); +return {msg: msg}; +``` + +* Replace the incoming message with the new message that contains only one field - count of properties in the original message: + +```javascript +var newMsg = { + count: msg.size() +}; +return {msg: newMsg}; +``` + +
    +
  • Change message type to CUSTOM_UPDATE,
    add additional attribute version into payload with value v1.1,
    change sensorType attribute value in Metadata to roomTemp:
  • +
+ +```javascript +var newType = "CUSTOM_UPDATE"; +msg.version = "v1.1"; +metadata.sensorType = "roomTemp" +return {msg: msg, metadata: metadata, msgType: newType}; +{:copy-code} +``` + +* Replace the incoming message with **two** new messages that contain only one field - sum or difference of properties in the original message: + +```javascript +var sum = msg.a + msg.b; +var diff = msg.a - msg.b; + +return [ + {msg: {sum: sum}, metadata: metadata, msgType: msgType}, + {msg: {difference: diff}, metadata: metadata, msgType: msgType} + ]; +``` + +
+ +You can see real life example, how to use this node in those tutorials: + +- [Transform incoming telemetry{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/transform-incoming-telemetry/) +- [Reply to RPC Calls{:target="_blank"}](${siteBaseUrl}/docs/user-guide/rule-engine-2-0/tutorials/rpc-reply-tutorial#add-transform-script-node) + +
+
diff --git a/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_markdown_pattern.md b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_markdown_pattern.md new file mode 100644 index 0000000000..fd4ab60a9c --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/editor/widget_js_markdown_pattern.md @@ -0,0 +1,68 @@ +#### Markdown pattern + +
+
+ +The Markdown template displays the value of the first found key in the entities in the entity alias. + +
+
+ +#### Examples + +Use # to create a Markdown header. The number of characters # specifies the type of header: # - h1, ## - h2, ### - h3, etc. + +```markdown + ###### Markdown/HTML card +{:copy-code} +``` + ###### Markdown/HTML card + +
+
+ +Use - character to create list item. You can create nested lists separating them with tabs in the pattern: + + ```markdown + - Element 1 + - Element 2 + - Element 2.1 + - Element 2.2 + -Element 3 +{:copy-code} + ``` +- Element 1 +- Element 2 + - Element 2.1 + - Element 2.2 +- Element 3 + +
+
+ +Use * character to choose style: + + ```markdown + - *Element 1* + - **Element 2** + - ***Element 3*** +{:copy-code} + ``` +- *Element 1* +- **Element 2** +- ***Element 3*** + +
+
+ +Use ${} to add some value from your key: + ```markdown + - **Element 1**: ${key1Name} + - **Element 1**: ${key2Name} + - **Element 1**: ${key3Name} +{:copy-code} + ``` + - **Element 1**: key1Value + - **Element 2**: key2Value + - **Element 3**: key3Value + diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md index b532cfa3f8..7c74cccae3 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_disabled_fn.md @@ -10,6 +10,9 @@ A JavaScript function evaluating whether current node should be disabled (not se **Parameters:**
    +
  • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
  • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
    (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md index 1a71858c9b..9e1888dfb0 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_has_children_fn.md @@ -10,6 +10,9 @@ A JavaScript function evaluating whether current node has children (whether it c **Parameters:**
      +
    • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
    • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
      (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md index 1a3c0aec8e..2da8c7932c 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_icon_fn.md @@ -10,6 +10,9 @@ A JavaScript function used to compute node icon info. **Parameters:**
        +
      • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
      • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
        (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md index e85a2b1aa9..08c9607f0b 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_opened_fn.md @@ -10,6 +10,9 @@ A JavaScript function evaluating whether current node should be opened (expanded **Parameters:**
          +
        • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
        • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
          (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md index f312483d07..2120fe4eea 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_relation_query_fn.md @@ -10,6 +10,9 @@ A JavaScript function used to compute child nodes relations query for current no **Parameters:**
            +
          • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
          • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
            (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md index 76b70a73fb..5ce79b7d15 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/node_text_fn.md @@ -10,6 +10,9 @@ A JavaScript function used to compute text or HTML code for the current node. **Parameters:**
              +
            • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
            • nodeCtx: HierarchyNodeContext - An HierarchyNodeContext object containing entity field holding basic entity properties
              (ex. id, name, label) and data field holding other entity attributes/timeseries declared in widget datasource configuration. diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md index 779424b553..2c2375f1e4 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/entities_hierarchy/nodes_sort_fn.md @@ -10,6 +10,9 @@ A JavaScript function used to compare nodes of the same level when sorting. **Parameters:**
                +
              • widgetCtx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
              • nodeCtx1: HierarchyNodeContext - First node object to be compared.
              • diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/clustering_color_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/clustering_color_fn.md new file mode 100644 index 0000000000..ba58fa3cd3 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/clustering_color_fn.md @@ -0,0 +1,65 @@ +#### Clustering marker function + +
                +
                + +*function (data, childCount): string* + +A JavaScript function used to compute clustering marker color. + +**Parameters:** + +
                  +
                • data: FormattedData[] + - the array of total markers contained within each cluster.
                  + Represents basic entity properties (ex. entityId, entityName)
                  and provides access to other entity attributes/timeseries declared in widget datasource configuration. +
                • +
                • childCount: number - the total number of markers contained within that cluster +
                • +
                + +**Returns:** + +Should return string value presenting color of the marker. + +In case no data is returned, color value from **Color** settings field will be used. + +
                + +##### Examples + +
                  +
                • +Calculate color depending on temperature telemetry value: +
                • + + +```javascript +let customColor; +for (let markerData of data) { + if (markerData.temperature > 40) { + customColor = 'red' + } +} +return customColor ? customColor : 'green'; +{:copy-code} +``` + +
                • +Calculate color depending on childCount: +
                • + +```javascript +if (childCount < 10) { + return 'green'; +} else if (childCount < 100) { + return 'yellow'; +} else { + return 'red'; +} +{:copy-code} +``` + +
                +
                +
                diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md index 98821e70a5..5687e4fe84 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/map/position_fn.md @@ -3,14 +3,18 @@

                -*function (origXPos, origYPos): {x: number, y: number}* +*function (origXPos, origYPos, data, dsData, dsIndex, aspect): {x: number, y: number}* A JavaScript function used to convert original relative x, y coordinates of the marker. **Parameters:** -- **origXPos:** number - original relative x coordinate as double from 0 to 1; -- **origYPos:** number - original relative y coordinate as double from 0 to 1; +
                  +
                • origXPos: number - original relative x coordinate as double from 0 to 1.
                • +
                • origYPos: number - original relative y coordinate as double from 0 to 1.
                • + {% include widget/lib/map/map_fn_args %} +
                • aspect: number - image map aspect ratio.
                • +
                **Returns:** @@ -37,5 +41,25 @@ return {x: origXPos / 2, y: origYPos / 2}; {:copy-code} ``` +* Detect markers with same positions and place them with minimum overlap: + +```javascript +var xPos = data.xPos; +var yPos = data.yPos; +var locationGroup = dsData.filter((item) => item.xPos === xPos && item.yPos === yPos); +if (locationGroup.length > 1) { + const count = locationGroup.length; + const index = locationGroup.indexOf(data); + const radius = 0.035; + const angle = (360 / count) * index - 45; + const x = xPos + radius * Math.sin(angle*Math.PI/180) / aspect; + const y = yPos + radius * Math.cos(angle*Math.PI/180); + return {x: x, y: y}; +} else { + return {x: xPos, y: yPos}; +} +{:copy-code} +``` +

                diff --git a/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md index 9bbcb7fd7c..c11f412b6f 100644 --- a/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md +++ b/ui-ngx/src/assets/help/en_US/widget/lib/markdown/markdown_text_fn.md @@ -3,7 +3,7 @@

                -*function (data): string* +*function (data, ctx): string* A JavaScript function used to calculate markdown or HTML content. @@ -13,6 +13,9 @@ A JavaScript function used to calculate markdown or HTML content.
              • data: FormattedData[] - An array of FormattedData objects resolved from configured datasources.
                Each object represents basic entity properties (ex. entityId, entityName)
                and provides access to other entity attributes/timeseries declared in widget datasource configuration.
              • +
              • ctx: WidgetContext - A reference to WidgetContext that has all necessary API + and data used by widget instance. +
              **Returns:** diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json new file mode 100644 index 0000000000..3d6f2c163c --- /dev/null +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -0,0 +1,5830 @@ +{ + "access": { + "unauthorized": "No autoritzat", + "unauthorized-access": "Accés no autoritzat", + "unauthorized-access-text": "Has d'iniciar sessió per tenir accés a aquest recurs!", + "access-forbidden": "Accés prohibit", + "access-forbidden-text": "No tens suficients drets per accedir a aquesta ubicació!
              Intenta iniciar sessió amb un altre usuari si encara vols accedir a aquesta ubicació.", + "refresh-token-expired": "La sessió ha expirat", + "refresh-token-failed": "No és pot actualitzar la sessió", + "permission-denied": "Permís Denegat", + "permission-denied-text": "No tens suficients drets per fer aquesta operació!" + }, + "action": { + "activate": "Activar", + "suspend": "Suspendre", + "save": "Guardar", + "saveAs": "Guardar com", + "cancel": "Cancel·lar", + "ok": "OK", + "delete": "Eliminar", + "add": "Afegir", + "yes": "Sí", + "no": "No", + "update": "Actualitzar", + "remove": "Eliminar", + "select": "Seleccionar", + "search": "Cercar", + "clear-search": "Eliminar la recerca", + "assign": "Assignar", + "unassign": "Anul·lar l'assignació", + "share": "Compartir", + "make-private": "Fer privat", + "make-public": "Fer públic", + "apply": "Aplicar", + "apply-changes": "Aplicar canvis", + "edit-mode": "Mode Edició", + "enter-edit-mode": "Mode Edició", + "decline-changes": "Desfer canvis", + "open": "Obrir", + "close": "Tancar", + "back": "Darrere", + "run": "Executar", + "sign-in": "Entrar!", + "edit": "Editar", + "view": "Veure", + "create": "Crear", + "drag": "Arrossegar", + "refresh": "Actualitzar", + "undo": "Desfer", + "copy": "Copiar", + "paste": "Pegar", + "copy-reference": "Copiar referència", + "paste-reference": "Pegar referència", + "import": "Importar", + "export": "Exportar", + "share-via": "Compartir via {{provider}}", + "move": "Moure", + "continue": "Continuar", + "discard-changes": "Cancelar canvis", + "download": "Descarregar", + "next-with-label": "Següent: {{label}}", + "read-more": "Llegir més", + "hide": "Ocultar", + "done": "Acabat", + "print": "Imprimir", + "restore": "Restaurar", + "confirm": "Confirmar" + }, + "aggregation": { + "aggregation": "Agrupació", + "function": "Funció d'Agrupació", + "limit": "Valors Max", + "group-interval": "Interval d'agrupació", + "min": "Min", + "max": "Max", + "avg": "Mitjana", + "sum": "Suma", + "count": "Contar", + "none": "Ningú" + }, + "admin": { + "general": "General", + "general-settings": "Configuració general", + "home-settings": "Configuració d'inici", + "outgoing-mail": "Servidor de correu", + "outgoing-mail-settings": "Configuració del servidor de correu de sortida", + "system-settings": "Sistema", + "test-mail-sent": "Correu de prova enviat correctament!", + "base-url": "Base d'URL", + "base-url-required": "Base d'URL requerida.", + "prohibit-different-url": "Prohibir l'ús de hostname a capçaleres de sol·licitud del client", + "prohibit-different-url-hint": "Aquest ajust ha de ser activat en entorns de producció. Pot ocasionar errors de seguretat si està desactivat", + "mail-from": "Correu de", + "mail-from-required": "Cal correu electrònic", + "smtp-protocol": "Protocol SMTP", + "smtp-host": "Host SMTP", + "smtp-host-required": "Host SMTP requerit.", + "smtp-port": "Port SMTP", + "smtp-port-required": "Has d'ingresar un Port SMTP.", + "smtp-port-invalid": "No sembla un Port SMTP vàlid.", + "timeout-msec": "Temps d'espera (ms)", + "timeout-required": "Temps d'espera requerit.", + "timeout-invalid": "No sembla un temps d'espera vàlid.", + "enable-tls": "Habilitar TLS", + "tls-version": "Versió TLS", + "enable-proxy": "Habilitar proxy", + "proxy-host": "Host proxy", + "proxy-host-required": "Es necessita port Proxy.", + "proxy-port": "Port proxy", + "proxy-port-required": "Es necessita port Proxy.", + "proxy-port-range": "El port proxy ha d'estar amb un rang d'1 a 655535.", + "proxy-user": "Usuari proxy", + "proxy-password": "Contrasenya proxy", + "change-password": "Canvia la contrasenya", + "send-test-mail": "Enviar correu de prova", + "use-system-mail-settings": "Utilitzar la configuració del servidor de correu del sistema.", + "mail-templates": "Plantilles de correu.", + "mail-template-settings": "Configuració de plantilles de correu.", + "use-system-mail-template-settings": "Utilitza les plantilles de correu del sistema", + "mail-template": { + "mail-template": "Plantilles del correu", + "test": "Missatge de prova de correu", + "activation": "Missatge d'activació de compte", + "account-activated": "Missatge de compte activat", + "account-lockout": "Missatge de bloqueig del compte", + "reset-password": "Missatge per a restabliment de contrasenya", + "password-was-reset": "Missatge de contrasenya restablerta", + "user-activated": "Missatge activat per l'usuari", + "user-registered": "Missatge registrat de l'usuari", + "api-usage-state-enabled": "Estat d'ús de l'API activat", + "api-usage-state-warning": "Avís d'estat d'ús de l'API", + "api-usage-state-disabled": "Estat d'ús de l'API desactivat" + }, + "mail-subject": "Assumpte del correu", + "mail-body": "Cos del correu", + "sms-provider": "Proveïdor SMS", + "sms-provider-settings": "Configuració proveïdor SMS", + "use-system-sms-settings": "Utilitza la configuració del proveïdor de SMS del sistema", + "sms-provider-type": "Tipus de proveïdor SMS", + "sms-provider-type-required": "Es requereix proveïdor SMS.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", + "aws-access-key-id": "ID de clau d'accés AWS", + "aws-access-key-id-required": "Es requereix ID de clau d'accés AWS", + "aws-secret-access-key": "Clau d'accés secret AWS", + "aws-secret-access-key-required": "Es requereix Clau d'accés secret AWS", + "aws-region": "Regió AWS", + "aws-region-required": "Es requereix regió AWS", + "number-from": "Núm. de telèfon Origen", + "number-from-required": "Es requereix Núm. de telèfon origen.", + "number-to": "Núm. de telèfon de destí", + "number-to-required": "Es requereix Núm. de telèfon de destí.", + "phone-number-hint": "Núm. de telèfon en format E.164, ex. +3435550123", + "phone-number-hint-twilio": "Núm. de telèfon en format E.164/SID del número de telèfon/SID del servei de missatgeria, ex. +3435550123/PNXXX/MGXXX", + "phone-number-pattern": "Núm. Invàlid. Ha d'estar en format E.164, ex. +3435550123.", + "phone-number-pattern-twilio": "El número de telèfon no és vàlid. Hauria d'estar en el format E.164/SIF/Servei de Missatgeria del Número de telèfon, ex. +3435550123/PNXXX/MGXXX.", + "sms-message": "Missatge SMS", + "sms-message-required": "Es requereix missatge SMS.", + "sms-message-max-length": "Els SMS no poden ser més llargs de 1600 caràcters", + "twilio-account-sid": "SID de compte Twilio", + "twilio-account-sid-required": "Es requereix SID de compte Twilio", + "twilio-account-token": "Token de compte Twilio", + "twilio-account-token-required": "Es requereix Token Twilio", + "send-test-sms": "Enviar SMS de prova", + "test-sms-sent": "SMS enviat amb èxit!", + "security-settings": "Configuracions de seguretat", + "password-policy": "Política de contrasenyes", + "minimum-password-length": "Longitud mínima de contrasenya", + "minimum-password-length-required": "Es requereix una longitud mínima de contrasenya", + "minimum-password-length-range": "La longitud mínima de la contrasenya ha d'estar en un rang de 5 a 50", + "minimum-uppercase-letters": "Nom mínim de lletres majúscules", + "minimum-uppercase-letters-range": "El nom mínim de lletres majúscules no pot ser negatiu", + "minimum-lowercase-letters": "Nom mínim de lletres minúscules", + "minimum-lowercase-letters-range": "El nom mínim de lletres minúscules no pot ser negatiu", + "minimum-digits": "Nom mínim de dígits", + "minimum-digits-range": "El nom mínim de dígits no pot ser negatiu", + "minimum-special-characters": "Nom mínim de caràcters especials.", + "minimum-special-characters-range": "El nom mínim de caràcters especials no pot ser negatiu.", + "password-expiration-period-days": "Període de caducitat de contrasenya en dies", + "password-expiration-period-days-range": "El període de caducitat de la contrasenya en dies no pot ser negatiu", + "password-reuse-frequency-days": "Freqüència de reutilització de contrasenya en dies", + "password-reuse-frequency-days-range": "La freqüència de reutilització de contrasenya en dies no pot ser negativa", + "allow-whitespace": "Permet espais en blanc", + "general-policy": "Política general", + "max-failed-login-attempts": "Nom màxim d'intents fallits d'inici de sessió, abans que el compte estigui bloquejat", + "minimum-max-failed-login-attempts-range": "El nom màxim d'intents fallits d'inici de sessió no pot ser negatiu", + "user-lockout-notification-email": "En cas de bloqueig del compte de l'usuari, enviï una notificació per correu electrònic", + "domain-name": "Nom de domini", + "domain-name-unique": "El nom de domini i protocol ha de ser únic.", + "domain-name-max-length": "El nom del domini ha de ser inferior a 256", + "error-verification-url": "Un nom de domini no ha de contenir símbols '/' i ':'. Exemple: thingsboard.io", + "oauth2": { + "access-token-uri": "URI Access token", + "access-token-uri-required": "Es requereix URI Access token.", + "activate-user": "Activar usuari", + "add-domain": "Afegir domini", + "delete-domain": "Esborrar domini", + "add-provider": "Afegir proveïdor", + "delete-provider": "Esborrar proveïdor", + "allow-user-creation": "Permetre creació d'usuari", + "always-fullscreen": "Sempre pantalla completa", + "authorization-uri": "URI Autorizació", + "authorization-uri-required": "Es requereix l'autorització d'URI.", + "client-authentication-method": "Mètode d'autenticació", + "client-id": "ID Client", + "client-id-required": "Es requereix ID Client.", + "client-id-max-length": "L'identificador del client ha de ser inferior a 256", + "client-secret": "Secret de Client", + "client-secret-required": "Es requereix Secret de Client.", + "client-secret-max-length": "El secret del client hauria de ser inferior a 2049", + "custom-setting": "Configuració personalitzats", + "customer-name-pattern": "Patró nomeni de client", + "customer-name-pattern-max-length": "El patró del nom del client hauria de ser inferior a 256", + "parent-customer-name-pattern": "Patró del nom del client pare", + "user-groups-name-pattern": "Patró de nom de grups d'usuaris", + "default-dashboard-name": "Nom de panell per defecte", + "default-dashboard-name-max-length": "El nom del tauler predeterminat hauria de ser inferior a 256", + "delete-domain-text": "Atenció, després de la confirmació el domini i totes les dades del proveïdor no estaran disponibles.", + "delete-domain-title": "Eliminar els configuració del domini '{{domainName}}'?", + "delete-registration-text": "Atenció, després de la confirmació les dades del proveïdor no estaran disponibles.", + "delete-registration-title": "Eliminar el proveïdor '{{name}}'?", + "email-attribute-key": "Clau d'atribut de correu electrònic", + "email-attribute-key-required": "Cal la clau de l'atribut de correu electrònic.", + "email-attribute-key-max-length": "La clau de l'atribut de correu electrònic ha de ser inferior a 32", + "first-name-attribute-key": "Clau de atributs de nom", + "first-name-attribute-key-max-length": "La clau de l'atribut de nom ha de ser inferior a 32", + "general": "General", + "jwk-set-uri": "URI web key JSON", + "last-name-attribute-key": "Clau d'atributs de cognom", + "last-name-attribute-key-max-length": "La clau de l'atribut del cognom ha de ser inferior a 32", + "login-button-icon": "Icona del botó d'inici de sessió", + "login-button-label": "Etiqueta de proveïdor", + "login-button-label-placeholder": "Inicia la sessió amb $(Provider label)", + "login-button-label-required": "Clau d'etiqueta requerida.", + "login-provider": "Proveïdor d'inici de sessió", + "mapper": "Cartografiador", + "new-domain": "Nou domini", + "oauth2": "OAuth2", + "password-max-length": "La contrasenya ha de ser inferior a 256", + "redirect-uri-template": "Plantilla de redirecció URI", + "copy-redirect-uri": "Copiar URI de redirecció", + "registration-id": "ID de registre", + "registration-id-required": "Es requereix ID de registre.", + "registration-id-unique": "L'ID de registre ha de ser únic en el sistema.", + "scope": "Abast", + "scope-required": "Es requereix abast.", + "tenant-name-pattern": "Patró de nom de propietari", + "tenant-name-pattern-required": "Es requereix patró del nom del propietari.", + "tenant-name-pattern-max-length": "El patró de nom de l'inquilí pot ser inferior a 256", + "tenant-name-strategy": "Estratègia de Nom de Propietari", + "type": "Tipus de cartografiador", + "uri-pattern-error": "Format de URI invàlid.", + "url": "URL", + "url-pattern": "Format URL invàlid.", + "url-required": "Es requereix URL.", + "url-max-length": "L'URL ha de ser inferior a 256", + "user-info-uri": "URI Informació de l'usuari", + "user-info-uri-required": "Es requereix URI de la informació usuari.", + "username-max-length": "El nom d'usuari ha de ser inferior a 256", + "user-name-attribute-name": "Clau d'atributs de nom d'usuari", + "user-name-attribute-name-required": "Es requereix clau d'atributs de nom d'usuari", + "protocol": "Protocol", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "Activar configuració OAuth2", + "domains": "Dominis", + "mobile-apps": "Aplicacions mòbils", + "no-mobile-apps": "No s'ha configurat cap aplicació", + "mobile-package": "Paquet d'aplicació", + "mobile-package-placeholder": "Ex.: my.example.app", + "mobile-package-hint": "Per a Android: el vostre propi identificador únic d'aplicació. Per a iOS: identificador de paquet de producte", + "mobile-package-unique": "El paquet d'aplicació ha de ser únic.", + "mobile-app-secret": "Secret de l'aplicació", + "invalid-mobile-app-secret": "El secret de l'aplicació ha de contenir només caràcters alfanumèrics i ha de tenir entre 16 i 2048 caràcters de longitud.", + "copy-mobile-app-secret": "Copia el secret de l'aplicació", + "add-mobile-app": "Afegeix una aplicació", + "delete-mobile-app": "Suprimeix la informació de l'aplicació", + "providers": "Proveïdors", + "platform-web": "Web", + "platform-android": "Android", + "platform-ios": "iOS", + "all-platforms": "Totes les plataformes", + "allowed-platforms": "Plataformes permeses" + }, + "smpp-provider": { + "smpp-version": "Versión SMPP", + "smpp-host": "Host SMPP", + "smpp-host-required": "Host SMPP requerido", + "smpp-port": "Puerto SMPP", + "smpp-port-required": "Puerto SMPP requerido", + "system-id": "System ID", + "system-id-required": "System ID requerido", + "password": "Contraseña", + "password-required": "Contraseña requerida", + "type-settings": "Configuració de tipo", + "source-settings": "Configuració de origen", + "destination-settings": "Configuració de destino", + "additional-settings": "Configuració adicionales", + "system-type": "Tipo de sistema", + "bind-type": "Tipo de enlace", + "service-type": "Tipo de servicio", + "source-address": "Dirección de origen", + "source-ton": "Origen TON", + "source-npi": "Origen NPI", + "destination-ton": "Destino TON (Tipo de número)", + "destination-npi": "Destino NPI (Numbering Plan Identification)", + "address-range": "Rango de dirección", + "coding-scheme": "Esquema de codificación", + "bind-type-tx": "Transmisor", + "bind-type-rx": "Receptor", + "bind-type-trx": "Transceptor", + "ton-unknown": "Desconocido", + "ton-international": "Internacional", + "ton-national": "Nacional", + "ton-network-specific": "Específico de red", + "ton-subscriber-number": "Número de suscriptor", + "ton-alphanumeric": "Alfanumérico", + "ton-abbreviated": "Abreviado", + "npi-unknown": "0 - Desconocido", + "npi-isdn": "1 - RDSI/Teléfono plan numérico (E163/E164)", + "npi-data-numbering-plan": "3 - Datos plan numérico (X.121)", + "npi-telex-numbering-plan": "4 - Telex plan numérico (F.69)", + "npi-land-mobile": "6 - Línea Móvil (E.212)", + "npi-national-numbering-plan": "8 - Nacional", + "npi-private-numbering-plan": "9 - Privado", + "npi-ermes-numbering-plan": "10 - ERMES (ETSI DE/PS 3 01-3)", + "npi-internet": "13 - Internet (IP)", + "npi-wap-client-id": "18 - WAP Client Id (a definir por WAP Forum)", + "scheme-smsc": "0 - Alfabeto por defecto SMSC (ASCII para códigos cortos y largos y GSM para gratuitos)", + "scheme-ia5": "1 - IA5 (ASCII para códigos cortos y largos, Latin 9 para gratuitos (ISO-8859-9))", + "scheme-octet-unspecified-2": "2 - Octetos sin especificar (binario 8-bit)", + "scheme-latin-1": "3 - Latin 1 (ISO-8859-1)", + "scheme-octet-unspecified-4": "4 - Octetos sin especificar (binario 8-bit)", + "scheme-jis": "5 - JIS (X 0208-1990)", + "scheme-cyrillic": "6 - Ciríllico (ISO-8859-5)", + "scheme-latin-hebrew": "7 - Latin/Hebreo (ISO-8859-8)", + "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", + "scheme-pictogram-encoding": "9 - Codificación por Pictograma", + "scheme-music-codes": "10 - Códigos musicales (ISO-2022-JP)", + "scheme-extended-kanji-jis": "13 - Kanji extendido JIS (X 0212-1990)", + "scheme-korean-graphic-character-set": "14 - Set de carácteres Koreanos (KS C 5601/KS X 1001)" + }, + "queue-select-name": "Seleccionar nom de cua", + "queue-name": "Nom", + "queue-name-required": "Cal el nom de cua!", + "queues": "Cues", + "queue-partitions": "Particions", + "queue-submit-strategy": "Estratègia d'enviaments", + "queue-processing-strategy": "Estratègia de processament", + "queue-configuration": "Configuració Cua", + "repository-settings": "Ajustos del repositori", + "repository-url": "URL del repositori", + "repository-url-required": "Es requereix la URL del repositori.", + "default-branch": "Nom de branca per defecte", + "authentication-settings": "Ajustos d'autenticació", + "auth-method": "Mètode d'autenticació", + "auth-method-username-password": "Usuari / Contrasenya", + "auth-method-private-key": "Clau privada", + "password-access-token": "Contrasenya / Tóken d'accés", + "change-password-access-token": "Canviar contrasenya / Tóken d'accés", + "private-key": "Clau privada", + "drop-private-key-file-or": "Arrossegar i deixar anar un fitxer de clau privada o", + "passphrase": "Frase de contrasenya", + "enter-passphrase": "Entrar frase de contrasenya", + "change-passphrase": "Canviar frase de contrasenya", + "check-access": "Verificar accés", + "check-repository-access-success": "Accés al repositori verificat satisfactòriament!", + "delete-repository-settings-title": "Estàs segur d'esborrar els ajustos del repositori?", + "delete-repository-settings-text": "Atenció, després de la confirmació els ajustos del repositori seran eliminats i la característica de control de versions no estarà disponible.", + "auto-commit-settings": "Ajustis Acte-publicar", + "auto-commit-entities": "Entitats Acte-publicar", + "no-auto-commit-entities-prompt": "No hi ha entitats configurades per a acte-publicar", + "delete-auto-commit-settings-title": "Estàs segur d'esborrar els ajustos d'acte-publicar?", + "delete-auto-commit-settings-text": "Atenció, després de la confirmació els ajustos d'acte-publicar seran esborrats i la característica d'acte-publicar es desactivarà per a totes les entitats.", + "2fa": { + "2fa": "Autenticació de dos factors (2FA)", + "available-providers": "Proveïdors disponibles", + "issuer-name": "Nom d'emissor", + "issuer-name-required": "Cal el nom d'emissor.", + "max-verification-failures-before-user-lockout": "Màxim de fallades de verificació abans de bloquejar compte", + "max-verification-failures-before-user-lockout-pattern": "Màxim de fallades ha de ser un nombre enter positiu.", + "number-of-checking-attempts": "Nombre d'intents de verificació", + "number-of-checking-attempts-pattern": "Nombre d'intents ha de ser un nombre enter positiu.", + "number-of-checking-attempts-required": "Cal el nombre d'intents.", + "number-of-codes": "Nombre de codis", + "number-of-codes-pattern": "Nombre de codis ha de ser un nombre enter positiu.", + "number-of-codes-required": "Cal el nombre de codis.", + "provider": "Proveïdor", + "retry-verification-code-period": "reintents de codi de verificació (seg)", + "retry-verification-code-period-pattern": "El període mínim és de 5 seg", + "retry-verification-code-period-required": "Cal reintent.", + "total-allowed-time-for-verification": "Total de temps permès per a verificació (seg)", + "total-allowed-time-for-verification-pattern": "El mínim del total de temps permès és de 60 seg", + "total-allowed-time-for-verification-required": "Cal total del temps.", + "use-system-two-factor-auth-settings": "Usar ajustos 2FA del sistema", + "verification-code-check-rate-limit": "Límit de revisió mèdica del codi de verificació", + "verification-code-lifetime": "Temps de vida del codi de verificació (seg)", + "verification-code-lifetime-pattern": "Temps de vida del codi de verificació ha de ser un nombre enter positiu.", + "verification-code-lifetime-required": "Cal el temps de vida.", + "verification-message-template": "Plantilla del missatge de verificació", + "verification-limitations": "Límits de verificació", + "verification-message-template-pattern": "El missatge de verificació ha de contenir el patró: ${code}", + "verification-message-template-required": "Cal plantilla de missatge de verificació.", + "within-time": "Rang de temps (seg)", + "within-time-pattern": "Temps ha de ser un nombre enter positiu.", + "within-time-required": "Cal el temps." + } + }, + "alarm": { + "alarm": "Alarma", + "alarms": "Alarmes", + "select-alarm": "Seleccionar alarma", + "no-alarms-matching": "No s'han trobat alarmes coincidents amb '{{entity}}' .", + "alarm-required": "Cal alarma", + "alarm-status": "Estat d'alarma", + "alarm-status-list": "Llista d'estats d'Alarmes", + "any-status": "Qualsevol estat", + "search-status": { + "ANY": "Totes", + "ACTIVE": "Actives", + "CLEARED": "Borrades", + "ACK": "Reconegudes", + "UNACK": "Ignorades" + }, + "display-status": { + "ACTIVE_UNACK": "Activa no reconeguda", + "ACTIVE_ACK": "Activa reconeguda", + "CLEARED_UNACK": "Normalitzada no reconeguda", + "CLEARED_ACK": "Normalitzada reconeguda" + }, + "no-alarms-prompt": "No és van trobar alarmes", + "created-time": "Hora de creació", + "type": "Tipus", + "severity": "Gravetat", + "originator": "Origen", + "originator-type": "Tipus d'origen", + "details": "Detalls", + "status": "Estat", + "alarm-details": "Detalls Alarma", + "start-time": "Hora d'inici", + "end-time": "Hora fi", + "ack-time": "Hora de reconeixement", + "clear-time": "Hora de normalització", + "alarm-severity-list": "Llista de gravetat d'alarmes", + "any-severity": "Qualsevol gravetat", + "severity-critical": "Crítica", + "severity-major": "Major", + "severity-minor": "Menor", + "severity-warning": "Perill", + "severity-indeterminate": "Indeterminada", + "acknowledge": "Reconèixer", + "clear": "Normalitzar", + "search": "Buscar alarmes", + "selected-alarms": "{ count, plural, 1 {1 alarma} other {# alarmas} } seleccionades", + "no-data": "Sense dades que mostrar", + "polling-interval": "Cicle de refresc d'alarmes (seg)", + "polling-interval-required": "Es requereix un cicle de refresc vàlid.", + "min-polling-interval-message": "El cicle ha de ser almenys d'1 segon.", + "aknowledge-alarms-title": "Reconèixer { count, plural, 1 {1 alarma} other {# alarmas} }", + "aknowledge-alarms-text": "Aquestes segur de reconèixer { count, plural, 1 {1 alarma} other {# alarmas} }?", + "aknowledge-alarm-title": "Reconèixer Alarma", + "aknowledge-alarm-text": "Estàs segur de reconèixer Alarma?", + "clear-alarms-title": "Normalitzar { count, plural, 1 {1 alarma} other {# alarmas} }", + "clear-alarms-text": "Netejar { count, plural, 1 {1 alarma} other {# alarmas} }?", + "clear-alarm-title": "Netejar Alarma", + "clear-alarm-text": "Netejar Alarma?", + "alarm-status-filter": "Filtre d'estats d'Alarmes", + "alarm-filter": "Filtre d'Alarmes", + "max-count-load": "Nom màxim d'alarmes a carregar (0 - ilimitado)", + "max-count-load-required": "Es requereix nom màxim d'alarmes.", + "max-count-load-error-min": "El valor mínim és 0.", + "fetch-size": "Mida de cerca (Fetch)", + "fetch-size-required": "Es requereix grandària de cerca.", + "fetch-size-error-min": "El valor mínim és 10.", + "alarm-type-list": "Llista de tipus d'alarma", + "any-type": "Qualsevol tipus", + "search-propagated-alarms": "Buscar alarmes propagades" + }, + "alias": { + "add": "Afegir àlies", + "edit": "Editar àlies", + "name": "Nom Àlies", + "name-required": "Es requereix nom d'àlies", + "duplicate-alias": "Ja existeix aquest nom d'àlies.", + "filter-type-single-entity": "Única entitat", + "filter-type-entity-group": "Entitats de grup", + "filter-type-entity-list": "Llista d'entitats", + "filter-type-entity-name": "Nom d'entitat", + "filter-type-entity-type": "Tipus d'entitat", + "filter-type-entity-group-list": "Llista d'entitats de grup", + "filter-type-entity-group-name": "Nom d'entitat de grup", + "filter-type-entities-by-group-name": "Entitats per nom de grup", + "filter-type-state-entity": "Entitat des de l'estat del panell", + "filter-type-state-entity-description": "Entitat presa dels paràmetres de panell", + "filter-type-state-entity-owner": "Propietari de l'entitat des de l'estat del tauler", + "filter-type-state-entity-owner-description": "Propietari de l'entitat presa dels paràmetres d'estat del tauler de control", + "filter-type-asset-type": "Tipus d'actiu", + "filter-type-asset-type-description": "Actius del tipus '{{assetType}}'", + "filter-type-asset-type-and-name-description": "Actius del tipus '{{assetType}}' i el nom del qual comenci per '{{prefix}}'", + "filter-type-device-type": "Tipus de dispositiu", + "filter-type-device-type-description": "Dispositius de tipus '{{deviceType}}'", + "filter-type-device-type-and-name-description": "Dispositius de tipus '{{deviceType}}' i el nom del qual comenci per '{{prefix}}'", + "filter-type-entity-view-type": "Tipus de vista d'entitat", + "filter-type-entity-view-type-description": "Vistes d'entitat del tipus '{{entityView}}'", + "filter-type-entity-view-type-and-name-description": "Vistes d'entitat del tipus '{{entityView}}' i el nom del qual comenci per '{{prefix}}'", + "filter-type-edge-type": "Tipus de vora", + "filter-type-edge-type-description": "Vores del tipus '{{edgeType}}'", + "filter-type-edge-type-and-name-description": "Vores del tipus '{{edgeType}}' i el nom del qual comenci per '{{prefix}}'", + "filter-type-relations-query": "Consulta de relacions", + "filter-type-relations-query-description": "{{entities}} que tenen {{relationType}} relació {{direction}} {{rootEntity}}", + "filter-type-edge-search-query": "Consultar cerca de vora", + "filter-type-edge-search-query-description": "Vores amb tipus {{edgeTypes}} que tenen {{relationType}} relació {{direction}} {{rootEntity}}", + "filter-type-asset-search-query": "Cerca d'actius", + "filter-type-asset-search-query-description": "Actius amb tipus {{assetTypes}} que tenen {{relationType}} relació {{direction}} {{rootEntity}}", + "filter-type-device-search-query": "Cerca de dispositius", + "filter-type-device-search-query-description": "Dispositius amb tipus {{deviceTypes}} que tenen {{relationType}} relació {{direction}} {{rootEntity}}", + "filter-type-entity-view-search-query": "Consulta de cerca de vista d'entitat", + "filter-type-entity-view-search-query-description": "Vistes d'entitat amb tipus {{entityViewTypes}} que tenen tipus de relació {{relationType}} amb direcció {{direction}} {{rootEntity}}", + "filter-type-apiUsageState": "Ús d'API", + "entity-filter": "Filtre per entitat", + "resolve-multiple": "Prendre com a múltiples entitats", + "filter-type": "Filtre per tipus", + "filter-type-required": "Es requereix filtre per tipus.", + "entity-filter-no-entity-matched": "No s'han trobat entitats amb el filtre especificat.", + "no-entity-filter-specified": "No hi ha filtre d'entitats especificat", + "root-state-entity": "Utilitzar estat de panell com a arrel", + "group-state-entity": "Utilitzar l'entitat del panell d'estats com a entitat de grup", + "group-state-entity-owner": "Usa l'entitat de l'estat del tauler com a propietari del grup d'entitats", + "last-level-relation": "Buscar només la relació d'últim nivell", + "root-entity": "Entitat arrel", + "state-entity-parameter-name": "Nom de paràmetre d'entitat d'estat", + "default-state-entity": "Entitat d'estat predeterminada", + "default-state-entity-group": "Grup d'entitats d'estat predeterminat", + "default-entity-parameter-name": "Per defecte", + "max-relation-level": "Nivell máx de relació", + "unlimited-level": "Nivell il·limitat", + "state-entity": "Entitat estat del panell", + "entities-of-group-state-entity": "Entitats del grup d'entitats del panell d'estat", + "all-entities": "Totes les entitats", + "any-relation": "qualsevol", + "type-assigned-to-edge": "Assignat a vora", + "type-unassigned-from-edge": "Sense assignar des de vores" + }, + "asset": { + "asset": "Actiu", + "assets": "Actius", + "management": "Gestió d'Actius", + "view-assets": "Veure actius", + "add": "Afegir Actiu", + "asset-type-max-length": "El tipus d'actiu ha de ser inferior a 256", + "assign-to-customer": "Assignar al client", + "assign-asset-to-customer": "Assignar Actiu(s) A Client", + "assign-asset-to-customer-text": "Selecciona els actius a assignar al client", + "no-assets-text": "No és van trobar actius", + "assign-to-customer-text": "Selecciona el client al qual assignar els actius", + "public": "Públic", + "assignedToCustomer": "Assignat al client", + "make-public": "Fer actiu públic", + "make-private": "Fer actiu privat", + "unassign-from-customer": "Cancel·lar l'assignació d'actiu del client", + "delete": "Esborrar actiu", + "asset-public": "L'actiu és públic", + "asset-type": "Tipus d'actiu", + "asset-type-required": "Es requereix tipus d'actiu.", + "select-asset-type": "Selecciona tipus d'actiu", + "enter-asset-type": "Entrar tipus d'actiu", + "any-asset": "Qualsevol actiu", + "no-asset-types-matching": "No s'han trobat actius coincidint amb '{{entitySubtype}}' .", + "asset-type-list-empty": "No hi ha cap mena d'actiu seleccionat.", + "asset-types": "Tipus d'actiu", + "name": "Nom", + "name-required": "Cal nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "label-max-length": "L'etiqueta ha de ser inferior a 256", + "description": "Descripció", + "type": "Tipus", + "type-required": "Cal tipus.", + "details": "Detalls", + "events": "Esdeveniments", + "add-asset-text": "Afegir nou actiu", + "asset-details": "Detalls d'actiu", + "assign-assets": "Assignar activus", + "assign-assets-text": "Assignar { count, plural, 1 {1 activo} other {# activos} } a client", + "delete-assets": "Esborrar actius", + "unassign-assets": "Cancel·lar assignació d'actiu", + "unassign-assets-action-title": "Cancel·lar assignació de { count, plural, 1 {1 activo} other {# activos} } del client", + "assign-new-asset": "Assignar nou actiu", + "delete-asset-title": "Eliminar l'actiu '{{assetName}}'?", + "delete-asset-text": "Atenció, després de la confirmació l'actiu i les seves dades seran esborrades i irrecuperables.", + "delete-assets-title": "Eliminar els actius { count, plural, 1 {1 activo} other {# activos} }?", + "delete-assets-action-title": "Esborrar { count, plural, 1 {1 activo} other {# activos} }", + "delete-assets-text": "Atenció, després de la confirmació tots els actius seleccionats i les seves dades seran esborrades i irrecuperables.", + "make-public-asset-title": "Fer l'actiu '{{assetName}}' públic?", + "make-public-asset-text": "Després de la confirmació, l'actiu i les seves dades és faran públics i accessibles per uns altres.", + "make-private-asset-title": "Fer l'actiu '{{assetName}}' privat?", + "make-private-asset-text": "Després de la confirmació, l'actiu i les seves dades és faran privats i accessibles per uns altres.", + "unassign-asset-title": "Cancel·lar l'assignació de l'actiu '{{assetName}}'?", + "unassign-asset-text": "Després de la confirmació, l'actiu serà desassignat i no serà accessible pel client.", + "unassign-asset": "Cancel·lar assignació d'actiu", + "unassign-assets-title": "Cancel·lar les assignacions { count, plural, 1 {1 activo} other {# activos} }?", + "unassign-assets-text": "Després de la confirmació tots els actius seleccionats seran desassignats i no seran accessibles pel client.", + "copyId": "Copiar ID d'actiu", + "idCopiedMessage": "L'ID ha estat copiat al porta-retalls", + "select-asset": "Seleccionar actiu", + "no-assets-matching": "No s'han trobat actius que coincideixin amb '{{entity}}' .", + "asset-required": "Cal nom d'actiu", + "name-starts-with": "El nom de l'actiu que comenci amb", + "help-text": "Utilitzeu «%» segons la necessitat: «%asset.name.contains%», «%asset.name.ends», «asset.starts.with».", + "selected-assets": "{ count, plural, 1 {1 activo} other {# activos} } seleccionats", + "search": "Buscar actius", + "select-group-to-add": "Seleccionar grup objectiu per a afegir actius seleccionats", + "select-group-to-move": "Seleccionar grup objectiu per a moure actius seleccionats", + "remove-assets-from-group": "Està segur que desitja eliminar { count, plural, 1 {1 asset} other {# assets} } del grup '{{entityGroup}}'?", + "group": "Grup d'actius", + "list-of-groups": "{ count, plural, 1 {One asset group} other {List of # asset groups} }", + "group-name-starts-with": "Grups d'actius els noms dels quals comencen amb '{{prefix}}'", + "import": "Importar actius", + "asset-file": "Arxiu de l'actiu", + "label": "Etiqueta", + "assign-asset-to-edge": "Assignar actiu(s) a la vora", + "unassign-asset-from-edge": "Anul·lar actiu de vora", + "unassign-asset-from-edge-title": "Està segur que desitja desassignar l'actiu '{{assetName}}'?", + "unassign-asset-from-edge-text": "Després de la confirmació, l'actiu no serà assignat i la vora no podrà accedir a ell", + "unassign-assets-from-edge-title": "Està segur que desitja desassignar {count, plural, 1 {1 activo} other {# activos} }?", + "unassign-assets-from-edge-text": "Després de la confirmació, tots els actius seleccionats quedaran sense assignar i la vora no podrà accedir a ells.", + "assign-asset-to-edge-text": "Si us plau, seleccioni els actius per a assignar a la vora", + "unassign-assets-from-edge-action-title": "Anul·lar assignació {count, plural, 1 {1 activo} other {# activos} } des de la vora" + }, + "attribute": { + "attributes": "Atributs", + "latest-telemetry": "Última telemetria", + "attributes-scope": "Abast dels atributs del dispositiu", + "scope-latest-telemetry": "Última telemetria", + "scope-client": "Atributs del Client", + "scope-server": "Atributs del Servidor", + "scope-shared": "Atributs Compartits", + "add": "Afegir atribut", + "add-attribute-prompt": "Si us plau afegir atribut", + "key": "Clau", + "key-max-length": "La clau ha de ser inferior a 256", + "last-update-time": "Hora d'última actualització", + "key-required": "Clau de l'atribut requerida.", + "value": "Valor", + "value-required": "Cal valor de l'atribut.", + "delete-attributes-title": "Eliminar { count, plural, 1 {1 atributo} other {# atributos} }?", + "delete-attributes-text": "Atenció, després de la confirmació l'atribut serà eliminat, i la informació relacionada serà irrecuperable.", + "delete-attributes": "Esborrar atribut", + "enter-attribute-value": "Ingressar valor de l'atribut", + "show-on-widget": "Mostrar en Widget", + "widget-mode": "Widget", + "next-widget": "Widget següent", + "prev-widget": "Widget anterior", + "add-to-dashboard": "Afegir al Panell", + "add-widget-to-dashboard": "Afegir widget al Panell", + "selected-attributes": "{ count, plural, 1 {1 atributo} other {# atributos} } seleccionats", + "selected-telemetry": "{ count, plural, 1 {1 telemetría} other {# telemetrías} } seleccionades", + "no-attributes-text": "No és va trobar cap atribut", + "no-telemetry-text": "No és va trobar cap telemetria" + }, + "api-usage": { + "api-usage": "Ús de API", + "alarm": "Alarma", + "alarms-created": "Alarmes creades", + "alarms-created-daily-activity": "Alarmes creades activitat diària", + "alarms-created-hourly-activity": "Alarmes creades per hora", + "alarms-created-monthly-activity": "Alarmes creades activitat mensual", + "data-points": "Punts de dades", + "data-points-storage-days": "Dies d'enregistrament de punts de dades", + "email": "Correu electrònic", + "email-messages": "Missatges de correu electrònic", + "email-messages-daily-activity": "Activitat diaria de correus", + "email-messages-monthly-activity": "Activitat mensual de correus", + "exceptions": "Excepcions", + "executions": "Execucions", + "javascript": "JavaScript", + "javascript-executions": "Execucions JavaScript", + "javascript-functions": "Funcions JavaScript", + "javascript-functions-daily-activity": "Activitat diària de funcions JavaScript", + "javascript-functions-hourly-activity": "Activitat horària de funcions JavaScript", + "javascript-functions-monthly-activity": "Activitat mensual de funcions JavaScript", + "latest-error": "Últim error", + "messages": "Missatges", + "notifications": "Notificacions", + "notifications-email-sms": "Notificacions (Email/SMS)", + "notifications-hourly-activity": "Notificacions per hora", + "permanent-failures": "${entityName} Fallades permanents", + "permanent-timeouts": "${entityName} Temps d'espera permanentes", + "processing-failures": "${entityName} Fallades de processament", + "processing-failures-and-timeouts": "Fallades de processament i temps d'espera", + "processing-timeouts": "${entityName} Temps d'espera de processament", + "queue-stats": "Estadístiques de cues", + "rule-chain": "Cadena de regles", + "rule-engine": "Motor de regles", + "rule-engine-daily-activity": "Activitat diària de motor de regles", + "rule-engine-executions": "Execucions de motor de regles", + "rule-engine-hourly-activity": "Activitat horària de motor de regles", + "rule-engine-monthly-activity": "Activitat mensual de motor de regles", + "rule-engine-statistics": "Estadístiques del motor de regles", + "rule-node": "Node de regles", + "sms": "SMS", + "sms-messages": "Missatges SMS", + "sms-messages-daily-activity": "Activitat diària de missatges SMS", + "sms-messages-monthly-activity": "Activitat mensual de missatges SMS", + "successful": "${entityName} Exitós", + "telemetry": "Telemetria", + "telemetry-persistence": "Persistència de telemetria", + "telemetry-persistence-daily-activity": "Activitat diaria de persistencia de telemetria", + "telemetry-persistence-hourly-activity": "Activitat horària de persistencia de telemetria", + "telemetry-persistence-monthly-activity": "Activitat mensual de persistencia de telemetria", + "transport": "Transport", + "transport-daily-activity": "Activitat diaria de transport", + "transport-data-points": "Punts de dades de transport", + "transport-hourly-activity": "Activitat horària de transport", + "transport-messages": "Missatges de transport", + "transport-monthly-activity": "Activitat mensual de transport", + "view-details": "Veure detalls", + "view-statistics": "Veure estadístiques", + "email-messages-hourly-activity": "Activitat horària de Correus electrònics", + "sms-messages-hourly-activity": "Activitat horària de missatges SMS" + }, + "audit-log": { + "audit": "Auditoria", + "audit-logs": "Registre d'Auditoria", + "timestamp": "Marca horària", + "entity-type": "Tipus Entitat", + "entity-name": "Nom Entitat", + "user": "Usuari", + "type": "Tipus", + "status": "Estat", + "details": "Detalls", + "type-added": "Afegir", + "type-deleted": "Esborrat", + "type-updated": "Actualitzat", + "type-attributes-updated": "Atributs actualizats", + "type-attributes-deleted": "Atributs esborrats", + "type-rpc-call": "Trucada RPC", + "type-credentials-updated": "Credencials actualizades", + "type-assigned-to-customer": "Assignat al Client", + "type-unassigned-from-customer": "Designat al Client", + "type-assigned-to-edge": "Assignat a la vora", + "type-unassigned-from-edge": "Sense assignar de la vora", + "type-activated": "Activat", + "type-suspended": "Suspès", + "type-credentials-read": "Lectura de credencials", + "type-attributes-read": "Lectura d'atributs", + "type-added-to-entity-group": "Agregat al grup", + "type-removed-from-entity-group": "Eliminat del grup", + "type-relation-add-or-update": "Relació actualitzada", + "type-relation-delete": "Relació esborrada", + "type-relations-delete": "Esborrades totes les relacions", + "type-alarm-ack": "Alarma Acusada", + "type-alarm-clear": "Alarma Netejada", + "type-rest-api-rule-engine-call": "Trucada a l'API REST del motor de regles", + "type-made-public": "Fet públic", + "type-made-private": "Fet privat", + "type-login": "Iniciar sessió", + "type-logout": "Tancar sessió", + "type-lockout": "Tancament per bloqueig", + "status-success": "Èxit", + "status-failure": "Fallada", + "audit-log-details": "Detall del registre d'auditoria", + "no-audit-logs-prompt": "No és van trobar registres", + "action-data": "Dades d'acció", + "failure-details": "Detalls del error", + "search": "Buscar registres d'auditoria", + "clear-search": "Esborrar cerca", + "type-assigned-from-tenant": "Assignat des de l'administrador", + "type-assigned-to-tenant": "Assignat a l'administrador", + "type-provision-success": "Dispositiu aprovisionat", + "type-provision-failure": "Aprovisionament fallit", + "type-timeseries-updated": "Telemetria actualitzada", + "type-timeseries-deleted": "Telemetria esborrada", + "type-owner-changed": "S'ha canviat el propietari" + }, + "confirm-on-exit": { + "message": "Tens canvis sense guardar. Abandonar la pàgina?", + "html-message": "Tens canvis sense guardar.
              Abandonar la pàgina?", + "title": "Canvis sense guardar" + }, + "contact": { + "country": "País", + "city": "Ciutat", + "state": "Estat / Província", + "postal-code": "Códig Postal", + "postal-code-invalid": "Format de codi postal invàlid.", + "address": "Direcció", + "address2": "Direcció 2", + "phone": "Telèfon", + "email": "Correu electrònic", + "no-address": "Sense Direcció", + "state-max-length": "La longitud de l'estat ha de ser inferior a 256", + "phone-max-length": "El número de telèfon hauria de ser inferior a 256", + "city-max-length": "La ciutat especificada ha de ser inferior a 256" + }, + "common": { + "username": "Usuari", + "password": "Contrasenya", + "enter-username": "Introdueix el nom d'usuari.", + "enter-password": "Introdueix la contrasenya", + "enter-search": "Introdueix cerca", + "created-time": "Data de creació", + "loading": "Carregant...", + "proceed": "Continua", + "open-details-page": "Obre la pàgina de detalls" + }, + "converter": { + "converter": "Convertidor de dades", + "converters": "Convertidors de dades", + "select-converter": "Seleccionar convertidor de dades", + "no-converters-matching": "Convertidors de dades que coincideixin amb '{{entity}}' no van ser trobats.", + "converter-required": "Cal convertidor de dades", + "delete": "Eliminar convertidor", + "management": "Gestió de convertidors de dades", + "add-converter-text": "Afegir nou convertidor de dades", + "no-converters-text": "Convertidors de dades no trobats", + "selected-converters": "{ count, plural, 1 {1 data converter} other {# data converters} } seleccionats", + "delete-converter-title": "Està segur que desitja eliminar el convertidor de dades '{{converterName}}'?", + "delete-converter-text": "Anar amb compte, després de la confirmació, el convertidor de dades i totes les dades relacionades és tornaran irrecuperables.", + "delete-converters-title": "Està segur que desitja eliminar { count, plural, 1 {1 data converter} other {# data converters} }?", + "delete-converters-action-title": "Eliminar { count, plural, 1 {1 data converter} other {# data converters} }", + "delete-converters-text": "Anar amb compte, després de la confirmació s'eliminaran tots els convertidors de dades seleccionades i totes les dades relacionades és tornaran irrecuperables.", + "events": "Esdeveniments", + "add": "Afegeix convertidor de dades", + "search": "Cerca convertidors de dades", + "converter-details": "Detalls del convertidor de dades", + "details": "Detalls", + "copyId": "Copiar ID del convertidor", + "idCopiedMessage": "ID del convertidor ha estat copiada al porta-retalls", + "debug-mode": "Mode de depuració", + "created-time": "Hora de creació", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "description": "Descripció", + "decoder": "Descodificador", + "encoder": "Codificador", + "test-decoder-fuction": "Prova funció del descodificador", + "test-encoder-fuction": "Prova funció del codificador", + "decoder-input-params": "Paràmetres d'entrada del descodificador", + "encoder-input-params": "Paràmetres d'entrada del codificador", + "payload": "Càrrega útil", + "payload-content-type": "Tipus de contingut de la càrrega útil", + "payload-content": "Contingut de la càrrega útil", + "message": "Missatge", + "message-type": "Tipus de missatge", + "message-type-required": "Cal el tipus de missatge", + "test": "Prova", + "metadata": "Metadades", + "metadata-required": "Les entrades de metadades no poden estar buides.", + "integration-metadata": "Metadades d'integració", + "integration-metadata-required": "Les entrades de metadades d'integració no poden estar buides.", + "output": "Sortida", + "import": "Importar convertidor", + "export": "Exportar convertidor", + "export-failed-error": "No és pot exportar convertidor: {{error}}", + "create-new-converter": "Crear nou convertidor", + "converter-file": "Arxiu del convertidor", + "invalid-converter-file-error": "No és pot importar el convertidor: Estructura del convertidor de dades invàlida.", + "type": "Tipus", + "type-required": "Cal el tipus", + "type-uplink": "Enllaç ascendent", + "type-downlink": "Enllaç descendent" + }, + "content-type": { + "json": "Json", + "text": "Text", + "binary": "Binari (Base64)" + }, + "customer": { + "customer": "Client", + "customers": "Clients", + "management": "Gestió de Clients", + "dashboard": "Panell del Client", + "dashboards": "Panells del Client", + "devices": "Dispositius del client", + "entity-views": "Vistes d'Entitat del client", + "assets": "Actius del Client", + "public-dashboards": "Panells Públics", + "public-devices": "Dispositius Públics", + "public-assets": "Actius Públics", + "public-entity-views": "Vistes d'Entitat Públiques", + "add": "Afegir client", + "delete": "Eliminar client", + "manage-customer-user-groups": "Gestionar grups d'usuaris de clients", + "manage-customer-groups": "Gestionar grups de clients", + "manage-customer-device-groups": "Gestioneu grups de dispositius de clients", + "manage-customer-asset-groups": "Gestionar grups d'actius de clients", + "manage-customer-entity-view-groups": "Gestioneu els grups de visualització d'entitats de clients", + "manage-customer-edge-groups": "Gestionar grups de clients perifèrics", + "manage-customer-dashboard-groups": "Gestioneu grups de panells de clients", + "manage-customer-users": "Gestionar d'usuaris del client", + "manage-customers": "Gestionar clients", + "manage-customer-devices": "Gestionar dels dispositius del client", + "manage-customer-entity-views": "Gestioneu les visualitzacions de l'entitat del client", + "manage-customer-dashboards": "Gestionar els panells del client", + "manage-public-devices": "Gestionar dispositius públics", + "manage-public-dashboards": "Gestionar panells públics", + "manage-customer-assets": "Gestionar actius del client", + "manage-public-assets": "Gestionar actius públics", + "add-customer-text": "Afegir nou client", + "no-customers-text": "No s'han trobat clients", + "customer-details": "Detalls del client", + "delete-customer-title": "Eliminar el client '{{customerTitle}}'?", + "delete-customer-text": "Atenció, després de la confirmació el client serà eliminat i tota la informació relacionada serà irrecuperable.", + "delete-customers-title": "Eliminar { count, plural, 1 {1 cliente} other {# clientes} }?", + "delete-customers-action-title": "Esborrar { count, plural, 1 {1 cliente} other {# clientes} }", + "delete-customers-text": "Atenció, després de la confirmació tots els clients seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "manage-user-groups": "Gestionar grups d'usuaris", + "manage-asset-groups": "Gestionar grups d'actius", + "manage-device-groups": "Gestionar grups de dispositius", + "manage-dashboard-groups": "Gestionar grups de panells", + "manage-entity-view-groups": "Gestioneu grups de visualitzacions d'entitats", + "manage-edge-groups": "Gestionar grups edge", + "manage-users": "Gestionar usuaris", + "manage-assets": "Gestionar actius", + "manage-devices": "Gestionar dispositius", + "manage-dashboards": "Gestionar panells", + "title": "Títol client", + "title-required": "Cal el títol del client.", + "title-max-length": "El títol ha de ser inferior a 256", + "description": "Descripció", + "details": "Detalls", + "events": "Esdeveniments", + "copyId": "Copiar ID del client", + "idCopiedMessage": "El ID del client s'ha copiat al porta-retalls", + "select-customer": "Seleccionar Client", + "no-customers-matching": "No s'han trobat clients que coincideixin amb '{{entity}}' .", + "customer-required": "Cal client", + "selected-customers": "{ count, plural, 1 {1 cliente} other {# clientes} } seleccionats", + "search": "Buscar clients", + "select-group-to-add": "Seleccionar el grup objectiu per afegir clients seleccionats", + "select-group-to-move": "Seleccionar el grup abkectiu per moure clients seleccionats", + "remove-customers-from-group": "Esteu segur que voleu eliminar { count, plural, 1 {1 customer} other {# customers} } del grup '{{entityGroup}}'?", + "group": "Grup clients", + "list-of-groups": "{ count, plural, 1 {One customer group} other {List of # customer groups} }", + "group-name-starts-with": "Grups de clients els quals començen amb '{{prefix}}'", + "select-default-customer": "Seleccionar un client per defecte", + "default-customer": "Client per defecte", + "default-customer-required": "El client per defecte és necessari per depurar el tauler de control al nivell de l'arrendatari", + "allow-white-labeling": "Permet l'etiqueta blanca", + "edges": "Vores del client", + "manage-edges": "Gestionar les vores", + "public-edges": "Vores públiques", + "manage-customer-edges": "Administrar vores dels clients", + "manage-public-edges": "Administrar vores públiques" + }, + "customers-hierarchy": { + "customers-hierarchy": "Jerarquia dels clients", + "open-nav-tree": "Obre l'arbre de navegació", + "return-to-top-level": "Torna al nivell superior" + }, + "custom-menu": { + "custom-menu": "Menú personalitzat", + "custom-menu-hint": "Definiu el menú personalitzat JSON a continuació. Aquest JSON conté una llista d'elements de menú personalitzats." + }, + "custom-translation": { + "custom-translation": "Traducció personalitzada", + "translation-map": "Mapa de traducció", + "key": "Clau de traducció", + "import": "Importa la traducció", + "export": "Exporta la traducció", + "export-data": "Exporta les dades de traducció", + "import-data": "Importa les dades de traducció", + "translation-file": "Fitxer de traducció", + "invalid-translation-file-error": "No s'ha pogut importar el fitxer de traducció: l'estructura de dades de traducció no és vàlida.", + "custom-translation-hint": "Definiu el JSON de traducció personalitzat a continuació. Aquest JSON sobreescriurà la traducció predeterminada. Feu clic a «Baixa el fitxer locale» per a obtenir la traducció existent. També podeu utilitzar el fitxer baixat com a referència a les parelles disponibles de traducció clau-valor.", + "download-locale-file": "Baixa el fitxer locale" + }, + "datetime": { + "date-from": "Data des de", + "time-from": "Hora des de", + "date-to": "Data fins a", + "time-to": "Hora fins a" + }, + "dashboard": { + "dashboard": "Panell", + "dashboards": "Panells", + "management": "Gestió de Panells", + "view-dashboards": "Veure Panells", + "add": "Afegir Panell", + "assign-dashboard-to-customer": "Assignar panell(s) al client", + "assign-dashboard-to-customer-text": "Per favor, selecciona algún panell per assignar al Client.", + "assign-dashboard-to-edge-title": "Assignar panell(s) a Vora", + "assign-to-customer-text": "Si us plau, seleccioni algun client per a assignar el(els) panell(s).", + "assign-to-customer": "Assignar al client", + "unassign-from-customer": "Desassignar del client", + "make-public": "Fer panell públic", + "make-private": "Fer panell privat", + "manage-assigned-customers": "Administrar clients assignats", + "assigned-customers": "Clients assignats", + "assign-to-customers": "Assignar Panell / Panells a Clients", + "assign-to-customers-text": "Selecciona els clients per assignar els panells", + "unassign-from-customers": "Desassignar Panell / Panells de clients", + "unassign-from-customers-text": "Selecciona els clients per desassignar els panells", + "no-dashboards-text": "Cap panell trobat", + "no-widgets": "Cap widget configurat", + "add-widget": "Afegir nou widget", + "title": "Títol", + "image": "Imatge del tauler", + "mobile-app-settings": "Paràmetres de l'aplicació mòbil", + "mobile-order": "Ordre del tauler en una aplicació mòbil", + "mobile-hide": "Amaga el tauler a l'aplicació mòbil", + "update-image": "Actualitza la imatge del tauler", + "take-screenshot": "Pren una captura de pantalla", + "select-widget-title": "Seleccionar widget", + "select-widget-value": "{{title}}: seleccionar widget", + "select-widget-subtitle": "Llista de tipus de widgets disponibles", + "delete": "Eliminar panell", + "title-required": "Cal títol.", + "title-max-length": "El títol ha de ser inferior a 256", + "description": "Descripció", + "details": "Detalls", + "dashboard-details": "Detalls del panell", + "add-dashboard-text": "Afegir nou panell", + "assign-dashboards": "Assignar panells", + "assign-new-dashboard": "Assignar nou panell", + "assign-dashboards-text": "Assignar { count, plural, 1 {1 panel} other {# paneles} } al client", + "unassign-dashboards-action-text": "Desassignar { count, plural, 1 {1 panel} other {# paneles} } als clients", + "delete-dashboards": "Eliminar panells", + "unassign-dashboards": "Desassignar panells", + "unassign-dashboards-action-title": "Desassignar { count, plural, 1 {1 paneles} other {# paneles} } del client", + "delete-dashboard-title": "Eliminar el panell '{{dashboardTitle}}'?", + "delete-dashboard-text": "Atenció, el panell seleccionat serà eliminat i la informació relacionada serà irrecuperable.", + "delete-dashboards-title": "Eliminar { count, plural, 1 {1 panel} other {# paneles} }?", + "delete-dashboards-action-title": "Eliminar { count, plural, 1 {1 panel} other {# paneles} }", + "delete-dashboards-text": "Atenció, els panells seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "unassign-dashboard-title": "Desassignar el panell '{{dashboardTitle}}'?", + "unassign-dashboard-text": "Després de la confirmació, el panell serà desassignat i no podrà ser accessible pel client.", + "unassign-dashboard": "Desassignar panell", + "unassign-dashboards-title": "Desassignar { count, plural, 1 {1 panel} other {# paneles} }?", + "unassign-dashboards-text": "Atenció, després de la confirmació els panells seleccionats seran desassignats i no podran ser accessibles pel client.", + "public-dashboard-title": "El panell ara és públic", + "public-dashboard-text": "El teu panell {{dashboardTitle}} ara és públic i podrà ser accedit des de: aquí:", + "public-dashboard-notice": "Nota: No oblidis fer públics els dispositius relacionats per accedir a les seves dades.", + "public-dashboard-link": "Enllaç públic del tauler", + "public-dashboard-link-text": "El vostre tauler públic {{dashboardTitle}} és accessible a través del proper públic link:", + "public-dashboard-link-notice": "Note: No oblideu fer públics els dispositius, actius i entitats relacionats per a accedir a les seves dades.", + "make-private-dashboard-title": "Fer el panell '{{dashboardTitle}}' privat?", + "make-private-dashboard-text": "Després de la confirmació, el panell serà privat i no podrà ser accessible per uns altres.", + "make-private-dashboard": "Fer panell privat", + "socialshare-text": "'{{dashboardTitle}}' impulsat per ThingsBoard", + "socialshare-title": "'{{dashboardTitle}}' impulsat per ThingsBoard", + "select-dashboard": "Seleccionar panell", + "no-dashboards-matching": "Panell '{{entity}}' no trobat.", + "dashboard-required": "Cal panell.", + "select-existing": "Seleccionar panells existentes", + "create-new": "Crear nou panell", + "new-dashboard-title": "Nou títol", + "open-dashboard": "Obrir panell", + "set-background": "Definir fons", + "background-color": "Color de fons", + "background-image": "Imatge de fons", + "background-size-mode": "Manera grandària de fons", + "no-image": "No s'ha seleccionat cap imatge", + "empty-image": "Sense imatge", + "drop-image": "Deixi anar una imatge o faci clic per seleccionar un arxiu per carregar.", + "maximum-upload-file-size": "Mida màxima del fitxer de pujada: {{ size }}", + "cannot-upload-file": "No s'ha pogut pujar el fitxer", + "settings": "Configuració", + "layout-settings": "Paràmetres de la disposició", + "columns-count": "Número de columnes", + "columns-count-required": "Cal número de columnes.", + "min-columns-count-message": "Sol es permet un número mínim de 10 columnes.", + "max-columns-count-message": "Sol es permet un número màxim de 1000 columnes.", + "widgets-margins": "Marge entre widgets", + "margin-required": "Cal valor de marge.", + "min-margin-message": "0 és el valor de marge mínim permès.", + "max-margin-message": "50 és el valor de marge màxim permès.", + "horizontal-margin": "Marge horitzontal", + "horizontal-margin-required": "Cal marge horitzontal.", + "min-horizontal-margin-message": "Sol es permet marge horitzontal mínim de 0.", + "max-horizontal-margin-message": "Sol es permet marge horitzontal màxim de 50.", + "vertical-margin": "Marge vertical", + "vertical-margin-required": "Cal marge vertical.", + "min-vertical-margin-message": "Sol es permet marge vertical mínim de 0.", + "max-vertical-margin-message": "Sol es permet marge vertical màxim de 50.", + "autofill-height": "Alçada disseny autoomplert", + "mobile-layout": "Configuració de disseny mòbil", + "mobile-row-height": "Alçada de la fila per a mòbils, px", + "mobile-row-height-required": "Cal alçada de fila.", + "min-mobile-row-height-message": "Només es permeten 5 píxels com alçada mínima de fila (móvil).", + "max-mobile-row-height-message": "Només es permeten 200 píxels com alçada màxima de fila (móvil).", + "title-settings": "Paràmetres del títol", + "display-title": "Mostrar títol del panell", + "title-color": "Color del títol", + "toolbar-settings": "Paràmetres de la barra d'eines", + "hide-toolbar": "Amaga la barra d'eines", + "toolbar-always-open": "Mantenir la barra d'eines oberta", + "display-dashboards-selection": "Mostrar selecció de panells", + "display-entities-selection": "Mostrar selecció d'entitats", + "display-filters": "Mostrar filtres", + "display-dashboard-timewindow": "Mostrar finestra del temps", + "display-dashboard-export": "Mostrar exportar", + "display-update-dashboard-image": "Mostra la imatge del tauler d'actualització", + "dashboard-logo-settings": "Configuració del logotip del tauler de control", + "display-dashboard-logo": "Mostra el logotip en mode de pantalla completa del tauler", + "dashboard-logo-image": "Imatge del logotip del tauler de control", + "advanced-settings": "Configuració avançada", + "dashboard-css": "Tauler CSS", + "import": "Importar panell", + "export": "Exportar panell", + "export-failed-error": "Impossible exportar panell: {{error}}", + "export-pdf": "Exportar com PDF", + "export-png": "Exportar com PNG", + "export-jpg": "Exportar com JPEG", + "export-json-config": "Exportar configuració JSON", + "download-dashboard-progress": "Generant panell {{reportType}} ...", + "create-new-dashboard": "Crear nou panell", + "dashboard-file": "Arxivar panell", + "invalid-dashboard-file-error": "Impossible importar panell: Estructura de dades invàlides.", + "dashboard-import-missing-aliases-title": "Configurar àlies utilitzats pel panell importat", + "create-new-widget": "Crear nou widget", + "import-widget": "Importar widget", + "widget-file": "Arxiu de widget", + "invalid-widget-file-error": "Impossible importar widget: Estructura de dades invàlida.", + "widget-import-missing-aliases-title": "Configurar àlies utilitzats pel widget", + "open-toolbar": "Obrir toolbar del panell", + "close-toolbar": "Tancar toolbar", + "configuration-error": "Error de configuració", + "alias-resolution-error-title": "Error de configuració d'àlies del panell", + "invalid-aliases-config": "No es pot trobar cap dispositiu que coincideixi amb alguns dels àlies de filtre.
              Posi's en contacte amb el seu administrador per resoldre aquest problema.", + "select-devices": "Seleccionar dispositius", + "assignedToCustomer": "Assignat al client", + "assignedToCustomers": "Assignat als clients", + "public": "Públic", + "public-link": "Enllaç públic", + "copy-public-link": "Copiar enllaç públic", + "public-link-copied-message": "El link públic del panell s'ha copiat al porta-retalls", + "manage-states": "Administrar estats de panells", + "states": "Estats de panells", + "search-states": "Buscar estats de panells", + "selected-states": "{ count, plural, 1 {1 estado panel} other {# estat paneles} } seleccionats", + "edit-state": "Editar estat panell", + "delete-state": "Esborrar estat panell", + "add-state": "Afegir estat panell", + "no-states-text": "No s'han trobat estats", + "state": "Estat de panell", + "state-name": "Nom", + "state-name-required": "Cal nom de l'estat.", + "state-id": "ID Estat", + "state-id-required": "Cal el ID de l'estat.", + "state-id-exists": "Ja existeix un ID de l'estat.", + "is-root-state": "Estat arrel(Root)", + "delete-state-title": "Esborrar estat del panell", + "delete-state-text": "Eliminar l'estat del panell amb nom: '{{stateName}}'?", + "show-details": "Mostrar detalls", + "hide-details": "Ocultar detalls", + "select-state": "Seleccionar estat destí (target state)", + "state-controller": "Controlador d'estats", + "selected-dashboards": "{ count, plural, 1 {1 panel} other {# paneles} } seleccionats", + "search": "Buscar panells", + "home-dashboard": "Tauler d'inici", + "home-dashboard-hide-toolbar": "Amaga la barra d'eines del tauler d'inici", + "select-group-to-add": "Seleccioneu el grup de destinació per a afegir els panells seleccionats", + "select-group-to-move": "Seleccioneu el grup de destinació per a moure els panells seleccionats", + "remove-dashboards-from-group": "Esteu segur que voleu eliminar { count, plural, 1 {1 dashboard} other {# dashboards} } del grup '{{entityGroup}}'?", + "group": "Grup de penells", + "list-of-groups": "{ count, plural, 1 {One dashboard group} other {List of # dashboard groups} }", + "group-name-starts-with": "Grups de tauler amb noms que comencen per '{{prefix}}'", + "unassign-dashboard-from-edge-text": "Després de la confirmació, el tauler no serà assignat i la vora no podrà accedir a ell", + "unassign-dashboards-from-edge-title": "Esteu segur que voleu desassignar { count, plural, 1 {1 dashboard} other {# dashboards} }?", + "unassign-dashboards-from-edge-text": "Després de la confirmació, és anul·larà l'assignació de tots els panells seleccionats i no seran accessibles per de vora", + "assign-dashboard-to-edge": "Assignar panell(és) a la vora", + "assign-dashboard-to-edge-text": "Si us plau selecciona els panells per assignar a la vora", + "non-existent-dashboard-state-error": "Estat del tauler amb ID \"{{ stateId }}\" no s'ha trobat" + }, + "datakey": { + "settings": "Configuració", + "advanced": "Avançat", + "label": "Etiqueta", + "color": "Color", + "units": "Símbol especial per mostrar juntament amb el valor", + "decimals": "Nombre de dígits després de la coma", + "data-generation-func": "Funció de generació de dades", + "use-data-post-processing-func": "Utilitzar funció de postprocessament de dades", + "configuration": "Configuració de clau de dades", + "timeseries": "Sèrie de temps", + "attributes": "Atributs", + "entity-field": "Camp d'entitat", + "alarm": "Camps d'alarma", + "timeseries-required": "Sèries del temps del dispositiu requerit.", + "timeseries-or-attributes-required": "Sèries del temps/*Atributs requerits.", + "alarm-fields-timeseries-or-attributes-required": "Es requereixen camps d'alarma o sèries del temps/atributs.", + "maximum-timeseries-or-attributes": "Màxim { count, plural, 1 {1 timeseries/atributo és permès.} other {# timeseries/atributos són permitidos} }", + "alarm-fields-required": "Cal camps d'alarma", + "function-types": "Tipus de funcions", + "function-types-required": "Cal tipus de funcions.", + "alarm-keys": "Claus d'alarmes", + "alarm-key": "Clau d'alarma", + "alarm-key-functions": "Funcions de les claus d'alarmes", + "alarm-key-function": "Funció de clau d'alarma", + "latest-keys": "Últimes claus", + "latest-key": "Última clau", + "latest-key-functions": "Funcions d'últimes claus", + "latest-key-function": "Funció d'última clau", + "timeseries-keys": "Claus de sèries de temps", + "timeseries-key": "Clau de sèries de temps", + "timeseries-key-functions": "Funcions de sèries de temps", + "timeseries-key-function": "Funció de sèrie de temps", + "maximum-function-types": "Màxim { count, plural, 1 {1 tipo de función está permitida.} other {# tipos de funciones están permitidos} }", + "time-description": "Hora del valor actual", + "value-description": "El valor actual", + "prev-value-description": "resultat de la crida anterior de la funció", + "time-prev-description": "hora del valor previ", + "prev-orig-value-description": "valor original previ" + }, + "datasource": { + "type": "Tipus de font de dades", + "name": "Nom", + "label": "Etiqueta", + "add-datasource-prompt": "Si us plau, agrega una font de dades" + }, + "details": { + "details": "Detalls", + "edit-mode": "Manera d'edició", + "edit-json": "Editar JSON", + "toggle-edit-mode": "Anar a Manera d'Edició" + }, + "device": { + "device": "Dispositiu", + "device-required": "Cal dispositiu.", + "devices": "Dispositius", + "management": "Gestió de Dispositius", + "view-devices": "Veure Dispositius", + "device-alias": "Àlies de dispositiu", + "device-type-max-length": "El tipus de dispositiu ha de ser inferior a 256", + "aliases": "Àlies de dispositius", + "no-alias-matching": "'{{alias}}' no trobat.", + "no-aliases-found": "Cap àlies trobat.", + "no-key-matching": "'{{key}}' no trobat.", + "no-keys-found": "Ninguna clau trobada.", + "create-new-alias": "Crear nou àlies!", + "create-new-key": "Crear nova clau!", + "duplicate-alias-error": "Àlies duplicat '{{alias}}'.
              L'àlies dels dispositius han de ser únics dins del panell.", + "configure-alias": "Configurar àlies '{{alias}}'", + "no-devices-matching": "No s'ha trobat dispositiu '{{entity}}'", + "alias": "Àlies", + "alias-required": "Cal àlies de dispositiu.", + "remove-alias": "Eliminar àlies", + "add-alias": "Afegir àlies", + "name-starts-with": "Nom comenci amb", + "help-text": "Useu «%» segons la necessitat: «%device.name.contains%», «%device.name.ends», «device.starts.with».", + "device-list": "Llista de dispositius", + "use-device-name-filter": "Utilitzar filtre", + "device-list-empty": "Cap dispositiu seleccionat.", + "device-name-filter-required": "Cal nom del filtre.", + "device-name-filter-no-device-matched": "Cap dispositiu trobat que comenci amb '{{device}}'.", + "add": "Afegir dispositiu", + "assign-to-customer": "Assignar a client", + "assign-device-to-customer": "Assignar dispositiu(s) a Client", + "assign-device-to-customer-text": "Si us plau, seleccioni els dispositius que seran assignats al client", + "assign-device-to-edge-title": "Assignar Dispositiu(s) a Vora", + "assign-device-to-edge-text": "Selecciona els dispositius a assignar a la Vora", + "make-public": "Fer dispositiu públic", + "make-private": "Fer dispositiu privat", + "no-devices-text": "Cap dispositiu trobat", + "assign-to-customer-text": "Si us plau, seleccioni el client per assignar el(els) dispositiu(s)", + "device-details": "Detalls del dispositiu", + "add-device-text": "Afegir nou dispositiu", + "credentials": "Credencials", + "manage-credentials": "Gestionar credencials", + "delete": "Eliminar dispositiu", + "assign-devices": "Assignar dispositiu", + "assign-devices-text": "Assignar { count, plural, 1 {1 dispositivo} other {# dispositivos} } al client", + "delete-devices": "Eliminar dispositiu", + "unassign-from-customer": "Desassignar el client", + "unassign-devices": "Desassignar dispositius", + "unassign-devices-action-title": "Desassignar { count, plural, 1 {1 dispositivo} other {# dispositivos} } del client", + "unassign-device-from-edge-title": "Està segur que vol desassignar el dispositiu '{{deviceName}}'?", + "unassign-device-from-edge-text": "Després de la confirmació, el dispositiu no serà assignat i la vora no podrà accedir a ell", + "unassign-devices-from-edge": "Desassigna els dispositius de la vora", + "assign-new-device": "Assignar nou dispositiu", + "make-public-device-title": "Fer el dispositiu '{{deviceName}}' públic?", + "make-public-device-text": "Després de la confirmació, el dispositiu i la informació relacionada seran públics i podrà ser accessible per uns altres.", + "make-private-device-title": "Fer el dispositiu '{{deviceName}}' privat?", + "make-private-device-text": "Després de la confirmació, el dispositiu i la informació relacionada seran privats i no podrà ser accessible per uns altres.", + "view-credentials": "Veure credencials", + "delete-device-title": "Eliminar el dispositiu '{{deviceName}}'?", + "delete-device-text": "Atenció, després de la confirmació els dispositius seran eliminats i la informació relacionada serà irrecuperable.", + "delete-devices-title": "Eliminar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", + "delete-devices-action-title": "Eliminar { count, plural, 1 {1 dispositivo} other {# dispositivos} }", + "delete-devices-text": "Atenció, després de la confirmació els dispositius seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "unassign-device-title": "Desassignar el dispositiu '{{deviceName}}'?", + "unassign-device-text": "Després de la confirmació, el dispositiu serà desasignado i no podrà ser accessible pel client.", + "unassign-device": "Desassignar dispositiu", + "unassign-devices-title": "Desassignar { count, plural, 1 {1 dispositivo} other {# dispositivos} }?", + "unassign-devices-text": "Després de la confirmació, els dispositius seleccionats seran desasignados i no podran ser accedits pel client.", + "device-credentials": "Credencials del dispositiu", + "loading-device-credentials": "S'estan carregant les credencials del dispositiu..", + "credentials-type": "Tipus de credencial", + "access-token": "Tóken d'accés", + "access-token-required": "Cal access token.", + "access-token-invalid": "Access token ha de tenir entre 1 a 32 caràcters.", + "certificate-pem-format": "Certificat en format PEM", + "certificate-pem-format-required": "Cal certificat.", + "lwm2m-security-config": { + "identity": "Identitat del client", + "identity-required": "Cal identitat del client.", + "identity-tooltip": "L'identificador PSK és un identificador PSK arbitrari de fins a 128 bytes, tal com es descriu a l'estàndard [RFC7925].\nL'identificador PSK S'HA DE convertir primer en una cadena de caràcters i després codificar-se en octets mitjançant UTF-8.", + "client-key": "Clau del client", + "client-key-required": "Cal clau del client.", + "client-key-tooltip-prk": "La clau pública o l'identificador RPK ha d'estar en l'estàndard [RFC7250] i codificat en format Base64!", + "client-key-tooltip-psk": "La clau PSK ha de tenir el format estàndard [RFC4279] i HexDec: 32, 64, 128 caràcters!", + "endpoint": "Nom del client del punt final", + "endpoint-required": "Cal nom del client del punt final.", + "client-public-key": "Clau pública del client", + "client-public-key-hint": "Si la clau pública del client està buida, s'utilitzarà el certificat de confiança", + "client-public-key-tooltip": "La clau pública X509 ha d'estar en format X509v3 codificat amb DER i suportar exclusivament l'algoritme EC i després codificada en format Base64!", + "mode": "Mode de configuració de seguretat", + "client-tab": "Configuració de seguretat del client", + "client-certificate": "Certificat de client", + "bootstrap-tab": "Client Bootstrap", + "bootstrap-server": "Servidor Bootstrap", + "lwm2m-server": "Servidor LwM2M", + "client-publicKey-or-id": "Clau pública o identificació del client", + "client-publicKey-or-id-required": "Cal Clau pública o identificació del client.", + "client-publicKey-or-id-tooltip-psk": "L'identificador PSK és un identificador PSK arbitrari de fins a 128 bytes, tal com es descriu a l'estàndard [RFC7925].\nL'identificador PSK S'HA DE convertir primer en una cadena de caràcters i després codificar-se en octets mitjançant UTF-8.", + "client-publicKey-or-id-tooltip-rpk": "La clau pública o l'identificador RPK ha d'estar en l'estàndard [RFC7250] i codificat en format Base64!", + "client-publicKey-or-id-tooltip-x509": "La clau pública X509 ha d'estar en format X509v3 codificat amb DER i suportar exclusivament l'algorisme EC i després codificar-se en format Base64", + "client-secret-key": "Clau secreta del client", + "client-secret-key-required": "Cal clau secreta del client.", + "client-secret-key-tooltip-psk": "La clau PSK ha de tenir el format estàndard [RFC4279] i HexDec: 32, 64, 128 caràcters!", + "client-secret-key-tooltip-prk": "La clau secreta RPK ha d'estar en format PKCS_8 (codificació DER, estàndard [RFC5958]) i després codificada en format Base64!", + "client-secret-key-tooltip-x509": "La clau secreta X509 ha d'estar en format PKCS_8 (codificació DER, estàndard [RFC5958]) i després codificada en format Base64!" + }, + "client-id": "ID Client", + "client-id-pattern": "Conté caràcter invàlid.", + "user-name": "Nom Usuari", + "user-name-required": "Cal nom d'usuari.", + "client-id-or-user-name-necessary": "L'ID Client i/o el Nom d'usuari són necessaris", + "password": "Contrasenya", + "secret": "Secreta", + "secret-required": "Cal secreta.", + "device-type": "Tipus de dispositiu", + "device-type-required": "Cal tipus de dispositiu.", + "select-device-type": "Seleccionar tipus de dispositiu", + "enter-device-type": "Entrar tipus de dispositiu", + "any-device": "Cualquier dispositiu", + "no-device-types-matching": "No hi ha cap tipus de dispositiu que coincideixin amb '{{entitySubtype}}' .", + "device-type-list-empty": "No hi ha cap tipus de dispositiu seleccionats.", + "device-types": "Tipus de dispositiu", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "label-max-length": "L'etiqueta ha de ser inferior a 256", + "description": "Descripció", + "label": "Etiqueta", + "events": "Esdeveniments", + "details": "Detalls", + "copyId": "Copiar ID", + "copyAccessToken": "Copiar access token", + "copy-mqtt-authentication": "Copiar credencials MQTT", + "idCopiedMessage": "Id del dispositiu copiat al porta-retalls", + "accessTokenCopiedMessage": "Access token del dispositiu copiat al porta-retalls", + "mqtt-authentication-copied-message": "Les dades d'autenticació MQTT s'han copiat al porta-retalls", + "assignedToCustomer": "Assignat al client", + "unable-delete-device-alias-title": "Impossible eliminar àlies del dispositiu", + "unable-delete-device-alias-text": "Àlies '{{deviceAlias}}' no pot ser eliminat. Esta siendo usado per el(els) widget(s):
              {{widgetsList}}", + "is-gateway": "És gateway", + "overwrite-activity-time": "Sobreescriure hora d'activitat per al dispositiu connectat", + "public": "Públic", + "device-public": "El dispositiu és públic", + "select-device": "Seleccionar dispositiu", + "selected-devices": "{ count, plural, 1 {1 dispositivo} other {# dispositivos} } seleccionats", + "search": "Buscar dispositius", + "select-group-to-add": "Seleccionar grup objetiu per afegir dispositius seleccionats", + "select-group-to-move": "Seleccionar grup objetiu per moure dispositius seleccionats", + "remove-devices-from-group": "Està segur de que desitja eliminar { count, plural, 1 {1 device} other {# devices} } del grup '{{entityGroup}}'?", + "group": "Grup de dispositius", + "list-of-groups": "{ count, plural, 1 {One device group} other {List of # device groups} }", + "group-name-starts-with": "Grup de dispositius els quals comencen amb '{{prefix}}'", + "import": "Importar dispositiu", + "device-file": "Arxiu de dispositiu", + "device-configuration": "Configuració del dispositiu", + "transport-configuration": "Configuració del transport", + "wizard": { + "device-wizard": "Assistent de dispositiu", + "device-details": "Detalls del dispositiu", + "new-device-profile": "Crear un nou perfil de dispositiu", + "existing-device-profile": "Seleccionar un perfil existent", + "specific-configuration": "Configuració específica", + "customer-to-assign-device": "Client al que assignar el dispositiu", + "add-credentials": "Afegir credencial" + }, + "unassign-devices-from-edge-title": "Està segur de que desitja desassignar {count, plural, 1 {1 dispositivo} other {# dispositivos} }?", + "unassign-devices-from-edge-text": "Després de la confirmació, tots els dispositius seleccionats quedaran sense assignar i la vora no podrà accedir a ells." + }, + "device-profile": { + "device-profile": "Perfil de dispositiu", + "device-profiles": "Perfils de dispositiu", + "all-device-profiles": "Tots", + "add": "Afegir perfil de dispositiu", + "edit": "Editar perfil de dispositiu", + "device-profile-details": "Detalls de perfil de dispositiu", + "no-device-profiles-text": "No s'han trobat perfils", + "search": "Buscar perfils", + "selected-device-profiles": "{ count, plural, 1 {1 perfil} other {# perfiles} } seleccionats", + "no-device-profiles-matching": "No existeix perfil que coincideixi amb '{{entity}}'.", + "device-profile-required": "Cal perfil de dispositiu", + "idCopiedMessage": "S'ha copiat el ID de perfil al porta-retalls", + "set-default": "Fer perfil per defecte", + "delete": "Esborrar perfil de dispositiu", + "copyId": "Copiar ID de perfil", + "name-max-length": "El nom ha de ser inferior a 256", + "new-device-profile-name": "Nom del perfil", + "new-device-profile-name-required": "Cal nom de perfil.", + "name": "Nom", + "name-required": "Cal nom.", + "type": "Tipus de perfil", + "type-required": "Cal tipus de perfil.", + "type-default": "Per defecte", + "image": "Imatge del perfil del dispositiu", + "transport-type": "Tipus de transport", + "transport-type-required": "Cal tipus de transport.", + "transport-type-default": "Per defecte", + "transport-type-default-hint": "Suporta transports per MQTT bàsic, HTTP i CoAP", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Activa configuracions avançats de transport MQTT", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "Activa la configuració avançada de transport CoAP", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "Transport LWM2M", + "transport-type-snmp": "SNMP", + "transport-type-snmp-hint": "Especifiqueu la configuració de transport SNMP", + "description": "Descripció", + "default": "Defecte", + "profile-configuration": "Configuració de perfil", + "transport-configuration": "Configuració de transport", + "default-rule-chain": "Cadena de regles per defecte", + "mobile-dashboard": "Tauler de control mòbil", + "mobile-dashboard-hint": "Utilitzat per l'aplicació mòbil com a tauler de detalls del dispositiu", + "select-queue-hint": "Selecciona des de el desplegable o afegir un nom personalitzat.", + "delete-device-profile-title": "Eliminar el perfil '{{deviceProfileName}}'?", + "delete-device-profile-text": "Atenció, després de la confirmació el perfil i totes les vostres dades seran esborrades i irrecuperables.", + "delete-device-profiles-title": "EEliminar { count, plural, 1 {1 perfil} other {# perfiles} }?", + "delete-device-profiles-text": "Atenció, després de la confirmació els perfils seleccionats i totes les vostres dades seran esborrades i irrecuperables.", + "set-default-device-profile-title": "Establir el perfil '{{deviceProfileName}}' com perfil per defecte?", + "set-default-device-profile-text": "Després de la confirmació, el perfil serà marcat com a defecte i serà utilitzat per tots els nous dispositius que no tinguin perfil especificat.", + "no-device-profiles-found": "No s'han trobar perfils.", + "create-new-device-profile": "Crear un nou perfil!", + "mqtt-device-topic-filters": "Filtres de topic MQTT", + "mqtt-device-topic-filters-unique": "Els filtres de topic de dispositiu MQTT han de ser únics.", + "mqtt-device-payload-type": "Payload de dispositiu MQTT", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-json-payload-format": "Activa la compatibilitat amb altres formats de càrrega útil.", + "mqtt-enable-compatibility-with-json-payload-format-hint": "Quan està habilitada, la plataforma utilitzarà un format de càrrega útil Protobuf de manera predeterminada. Si l'anàlisi falla, la plataforma intentarà utilitzar el format de càrrega útil JSON. Útil per a la compatibilitat enrere durant les actualitzacions de firmware. Per exemple, la versió inicial del firmware utilitza Json, mentre que la nova versió utilitza Protobuf. Durant el procés d'actualització del microprogramari per a la flota de dispositius, cal que admeti Protobuf i JSON simultàniament. El mode de compatibilitat introdueix una lleugera degradació del rendiment, per la qual cosa es recomana desactivar aquest mode un cop s'actualitzin tots els dispositius.", + "mqtt-use-json-format-for-default-downlink-topics": "Utilitzeu el format Json per als temes d'enllaç descendent predeterminat", + "mqtt-use-json-format-for-default-downlink-topics-hint": "Quan estigui habilitada, la plataforma utilitzarà el format de càrrega útil Json per enviar atributs i RPC mitjançant els temes següents: v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes , v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. Aquesta configuració no afecta les subscripcions d'atributs i rpc enviades amb temes nous (v2): v2/a/res/$request_id, v2/a, v2/r /req/$request_id, v2/r/res/$request_id. On $request_id és un identificador de sol·licitud d'enter.", + "mqtt-send-ack-on-validation-exception": "Enviar PUBACK en error de validació a la publicació (PUBLICAR)", + "mqtt-send-ack-on-validation-exception-hint": "Per defecte, la plataforma tancarà la sessió MQTT en cas d'error de validació del missatge. Quan estigui activat, la plataforma enviarà un reconeixement de publicació en lloc de tancar la sessió.", + "snmp-add-mapping": "Afegeix mapeig SNMP", + "snmp-mapping-not-configured": "No s'ha configurat cap mapeig per a OID a sèries temporals/telemetria", + "snmp-timseries-or-attribute-name": "Sèries temporals/nom d'atribut per al mapeig", + "snmp-timseries-or-attribute-type": "Sèries temporals/tipus d'atribut per al mapeig", + "snmp-method-pdu-type-get-request": "Obteniu la sol·licitud", + "snmp-method-pdu-type-get-next-request": "Obteniu la següent sol·licitud", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Cal tipus de Payload.", + "coap-device-type": "Tipus de dispositiu CoAP", + "coap-device-payload-type": "Càrrega útil del dispositiu CoAP", + "coap-device-type-required": "Cal tipus de dispositiu CoAP.", + "coap-device-type-default": "Per defecte", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "Se suporten els wildcards únics [+] i multinivell [#].", + "telemetry-topic-filter": "Filtre de topic en telemetria", + "telemetry-topic-filter-required": "Cal filtre de topic (telemetria).", + "attributes-topic-filter": "Filtre de topic en atributs", + "attributes-topic-filter-required": "Cal filtre de topic (atributs).", + "telemetry-proto-schema": "Proto esquema de telemetria", + "telemetry-proto-schema-required": "Cal proto esquema de telemetria.", + "attributes-proto-schema": "Proto esquema de atributs", + "attributes-proto-schema-required": "Cal proto esquema de atributs.", + "rpc-response-proto-schema": "RPC resposta proto esquema", + "rpc-response-proto-schema-required": "Cal RPC resposta proto esquema.", + "rpc-response-topic-filter": "Filtre de topic de respuesta RPC", + "rpc-response-topic-filter-required": "Cal fitro de respuesta RPC.", + "rpc-request-proto-schema": "RPC petició proto esquema", + "rpc-request-proto-schema-required": "Cal RPC petició proto esquema.", + "rpc-request-proto-schema-hint": "RPC petició el missatge ha de tenir sempre camps: mètode de cadena = 1; int32 requestId = 2; i paràmetres = 3 de qualsevol tipus de dades.", + "not-valid-pattern-topic-filter": "No és un patró de filtre vàlid", + "not-valid-single-character": "Ús invàlid de wildcard únic", + "not-valid-multi-character": "Ús invàlid de wildcard multi-nivell", + "single-level-wildcards-hint": "[+] és adequat per qualsevol nivell. Ej.: v1/devices/+/telemetry o +/devices/+/attributes.", + "multi-level-wildcards-hint": "[#] pot reemplaçar el mateix filtre i ha de ser l'últim símbol del topic. Ej.: # o v1/devices/me/#.", + "alarm-rules": "Regles d'alarma", + "alarm-rules-with-count": "Regles d'alarma ({{count}})", + "no-alarm-rules": "No hi ha cap regla d'alarma configurada", + "add-alarm-rule": "Afegir regla d'alarma", + "edit-alarm-rule": "Editar regla d'alarma", + "alarm-type": "Tipus d'alarma", + "alarm-type-required": "Cal tipus d'alarma.", + "alarm-type-unique": "El tipus d'alarma, ha de ser únic dins de les regles d'alarma del perfil de dispositiu.", + "alarm-type-max-length": "El tipus d'alarma ha de ser inferior a 256", + "create-alarm-pattern": "Crear alarma {{alarmType}}", + "create-alarm-rules": "Crear regles d'alarma", + "no-create-alarm-rules": "No hi ha condicions de creació d'alarma configurades", + "add-create-alarm-rule-prompt": "Per favor, afegiu una regla d'alarma", + "clear-alarm-rule": "Esborrar regla d'alarma", + "no-clear-alarm-rule": "No hi ha condicions de esborrat d'alarma configurades", + "add-create-alarm-rule": "Afegir crear condició (activar alarma)", + "add-clear-alarm-rule": "Afegir esborrar condició (limpiar alarma)", + "select-alarm-severity": "Seleccioneu severitat d'alarma", + "alarm-severity-required": "Cal especificar severitat d'alarma.", + "condition-duration": "Duració de condició", + "condition-duration-value": "Valor de duració", + "condition-duration-time-unit": "Unitat del temps", + "condition-duration-value-range": "El valor ha d'estar en un rang des de 1 a 2147483647.", + "condition-duration-value-pattern": "El valor de duració ha de ser un número enter.", + "condition-duration-value-required": "Cal valor de duració.", + "condition-duration-time-unit-required": "Cal una unidad del temps.", + "advanced-settings": "Configuració avançada", + "alarm-rule-details": "Detalls", + "alarm-rule-details-hint": "Suggeriment: utilitzeu ${keyName} per substituir els valors de les claus d'atribut o de telemetria que s'utilitzen en condicions de regla d'alarma.", + "add-alarm-rule-details": "Afegir detalls", + "alarm-rule-mobile-dashboard": "Tauler de control mòbil", + "alarm-rule-mobile-dashboard-hint": "Utilitzat per l'aplicació mòbil com a quadre de comandament de detalls d'alarma", + "alarm-rule-no-mobile-dashboard": "No s'ha seleccionat cap tauler", + "propagate-alarm": "Propagar alarma", + "alarm-rule-relation-types-list": "Tipus de relació per propagar", + "alarm-rule-relation-types-list-hint": "Si no está seleccionat 'propagar relacions', les alarmes seran propagadas sense filtrar per relació.", + "propagate-alarm-to-owner": "Propaga l'alarma al propietari de l'entitat (Customer or Tenant)", + "propagate-alarm-to-owner-hierarchy": "Propaga l'alarma a la jerarquia dels propietaris de l'entitat", + "propagate-alarm-to-tenant": "Propaga l'alarma al llogater", + "alarm-details": "Detalls d'alarma", + "alarm-rule-condition": "Condicions de regla d'alarma", + "enter-alarm-rule-condition-prompt": "Per favor, afegir una condició d'alarma", + "edit-alarm-rule-condition": "Editar condició d'alarma", + "device-provisioning": "Aprovisionament de dispositius", + "provision-strategy": "Estrategia d'aprovisionament", + "provision-strategy-required": "Cal estrategia d'aprovisionament.", + "provision-strategy-disabled": "Desactivat", + "provision-strategy-created-new": "Permetre crear nous dispositius", + "provision-strategy-check-pre-provisioned": "Revisar dispositius pre-aprovisionats", + "provision-device-key": "Clau d'aprovisionament", + "provision-device-key-required": "Cal clau d'aprovisionament.", + "copy-provision-key": "Copiar clau d'aprovisionament", + "provision-key-copied-message": "La clau d'aprovisionament s'ha copiat al porta-retalls", + "provision-device-secret": "Secret d'aprovisionament", + "provision-device-secret-required": "Cal secret d'aprovisionament.", + "copy-provision-secret": "Copiar secret d'aprovisionament", + "provision-secret-copied-message": "S'ha copiat el secret d'aprovisionament al porta-retalls", + "condition": "Condició", + "condition-type": "Tipus de condició", + "condition-type-simple": "Simple", + "condition-type-duration": "Duració", + "condition-during": "Durant {{during}}", + "condition-during-dynamic": "Durant \"{{ attribute }}\" ({{during}})", + "condition-type-repeating": "Repetitiva", + "condition-type-required": "Cal tipus de condició.", + "condition-repeating-value": "Nº de esdeveniments", + "condition-repeating-value-range": "El Nº de esdeveniments ha d'estar en un rang de 1 to 2147483647.", + "condition-repeating-value-pattern": "Nº de esdeveniments ha de ser un número enter.", + "condition-repeating-value-required": "Cal Nº de esdeveniments.", + "condition-repeat-times": "Repetició { count, plural, 1 {1 vez} other {# veces} }", + "condition-repeat-times-dynamic": "Repeats \"{ attribute }\" ({ count, plural, 1 {1 time} other {# times} })", + "schedule-type": "Tipus d'horari", + "schedule-type-required": "Cal tipus d'horari.", + "schedule": "Horari", + "edit-schedule": "Editar horari d'alarma", + "schedule-any-time": "Sempre actiu", + "schedule-specific-time": "Actiu en una hora específica", + "schedule-custom": "Personalitzat", + "schedule-day": { + "monday": "Dilluns", + "tuesday": "Dimarts", + "wednesday": "Dimecres", + "thursday": "Dijous", + "friday": "Divendres", + "saturday": "Dissabte", + "sunday": "Diumenge" + }, + "schedule-days": "Dies", + "schedule-time": "Hora", + "schedule-time-from": "De", + "schedule-time-to": "Fins a", + "schedule-days-of-week-required": "Ha de ser seleccionat almenys un dia de la setmana.", + "create-device-profile": "Crea un perfil nou de dispositiu", + "import": "Importa el perfil del dispositiu", + "export": "Exporta el perfil del dispositiu", + "export-failed-error": "No s'ha pogut exportar el perfil del dispositiu: {{error}}", + "device-profile-file": "Fitxer de perfil del dispositiu", + "invalid-device-profile-file-error": "No s'ha pogut importar el perfil del dispositiu: l'estructura de dades del perfil del dispositiu no és vàlida.", + "power-saving-mode": "Mode d'estalvi d'energia", + "power-saving-mode-type": { + "default": "Utilitza el mode d'estalvi d'energia del perfil del dispositiu", + "psm": "Mode d'estalvi d'energia (PSM)", + "drx": "Recepció contínua (DRX)", + "edrx": "Recepció discontinu ampliada (eDRX)" + }, + "edrx-cycle": "Cicle eDRX", + "edrx-cycle-required": "Cal cicle eDRX.", + "edrx-cycle-pattern": "El cicle eDRX ha de ser un nombre enter positiu.", + "edrx-cycle-min": "El nombre mínim de cicles eDRX és {{ min }} segons.", + "paging-transmission-window": "Paging Transmission Window", + "paging-transmission-window-required": "Cal finestra de transmissió de paginació.", + "paging-transmission-window-pattern": "La finestra de transmissió de paginació ha de ser un nombre enter positiu.", + "paging-transmission-window-min": "El nombre mínim de finestra de transmissió de paginació és {{ min }} segons.", + "psm-activity-timer": "Temporitzador d'activitats PSM", + "psm-activity-timer-required": "Cal temporitzador d'activitats PSM.", + "psm-activity-timer-pattern": "El temporitzador d'activitat PSM ha de ser un nombre enter positiu.", + "psm-activity-timer-min": "El nombre mínim de temporitzadors d'activitat PSM és {{ min }} segons.", + "lwm2m": { + "object-list": "Llista d'objectes", + "object-list-empty": "No s'ha seleccionat cap objecte.", + "no-objects-found": "No s'ha trobat cap objecte.", + "no-objects-matching": "No hi ha cap objecte que coincideixi '{{object}}' els van trobar.", + "model-tab": "Model LWM2M", + "add-new-instances": "Afegeix noves instàncies", + "instances-list": "Llista d'instàncies", + "instances-list-required": "Cal llista d'instàncies.", + "instance-id-pattern": "L'identificador de la instància ha de ser un nombre enter positiu.", + "instance-id-max": "Valor màxim d'identificador de la instància {{max}}.", + "instance": "Instància", + "resource-label": "#ID Nom del recurs", + "observe-label": "Observa", + "attribute-label": "Atribut", + "telemetry-label": "Telemetria", + "edit-observe-select": "Per editar, seleccioneu la telemetria o l'atribut", + "edit-attributes-select": "Per editar els atributs, seleccioneu la telemetria o l'atribut", + "no-attributes-set": "No s'han establert atributs", + "key-name": "Nom clau", + "key-name-required": "Cal nom clau", + "attribute-name": "Atribut de nom", + "attribute-name-required": "Cal atribut de nom.", + "attribute-value": "Valor de l'atribut", + "attribute-value-required": "Cal valor de l'atribut.", + "attribute-value-pattern": "El valor de l'atribut ha de ser un nombre enter positiu.", + "edit-attributes": "Edita els atributs: {{ name }}", + "view-attributes": "Mostra els atributs: {{ name }}", + "add-attribute": "Afegeix un atribut", + "edit-attribute": "Edita l'atribut", + "view-attribute": "Veure l'atribut", + "remove-attribute": "Eliminar l'atribut", + "delete-server-text": "Aneu amb compte, després de la confirmació, la configuració del servidor es tornarà irrecuperable.", + "delete-server-title": "Esteu segur que voleu suprimir el servidor?", + "mode": "Mode de configuració de seguretat", + "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Servidor Bootstrap (ShortId...)", + "lwm2m-server-legend": "Servidor LwM2M (ShortId...)", + "server": "Servidor", + "short-id": "Identificador curt del servidor", + "short-id-tooltip": "Identificador curt del servidor. S'utilitza com a enllaç a la instància d'objecte del servidor associada.\nAquest identificador identifica de manera única cada servidor LwM2M configurat per al client LwM2M.\nEl recurs S'HA d'establir quan el recurs del servidor Bootstrap té un valor 'fals'.\nEls valors ID:0 i ID :65535 NO S'HAN d'utilitzar per identificar el servidor LwM2M.", + "short-id-required": "Cal identificador curt del servidor.", + "short-id-range": "L'identificador de servidor curt hauria d'estar entre 1 i 65534.", + "short-id-pattern": "L'identificador de servidor curt ha de ser un nombre enter positiu.", + "lifetime": "Vida útil del registre del client", + "lifetime-required": "Cal vida útil del registre del client.", + "lifetime-pattern": "La vida útil del registre del client ha de ser un nombre enter positiu.", + "default-min-period": "Període mínim entre dues notificacions (s)", + "default-min-period-tooltip": "El valor predeterminat que el client LwM2M hauria d'utilitzar durant el període mínim d'una observació si no s'inclou aquest paràmetre en una observació..", + "default-min-period-required": "Cal període mínim.", + "default-min-period-pattern": "El període mínim ha de ser un nombre enter positiu.", + "notification-storing": "Emmagatzematge de notificacions quan està desactivat o fora de línia", + "binding": "Enquadernació", + "binding-type": { + "u": "U: Es pot contactar amb el client mitjançant l'enllaç UDP en qualsevol moment.", + "m": "M: Es pot contactar amb el client mitjançant l'enllaç MQTT en qualsevol moment.", + "h": "H: El client és accessible mitjançant l'enllaç HTTP en qualsevol moment.", + "t": "T: Es pot contactar amb el client mitjançant l'enllaç TCP en qualsevol moment.", + "s": "S: Es pot contactar amb el client mitjançant l'enllaç SMS en qualsevol moment.", + "n": "N: El client HA d'enviar la resposta a aquesta sol·licitud mitjançant l'enllaç no IP (s'admet des de LWM2M 1.1).", + "uq": "UQ: Connexió UDP en mode de cua (no s'admet des de LWM2M 1.1)", + "uqs": "UQS: les connexions UDP i SMS actives; UDP en mode de cua, SMS en mode estàndard (no s'admet des de LWM2M 1.1)", + "tq": "TQ: Connexió TCP en mode de cua (no s'admet des de LWM2M 1.1)", + "tqs": "TQS: les connexions TCP i SMS actives; TCP en mode de cua, SMS en mode estàndard (no s'admet des de LWM2M 1.1)", + "sq": "SQ: Connexió d'SMS en mode de cua (no s'admet des de LWM2M 1.1)" + }, + "binding-tooltip": "Aquesta és la llista del recurs\"enllaç\" de l'objecte del servidor LwM2M - /1/x/7.\nIndica els modes d'enllaç admesos al client LwM2M.\nAquest valor HA de ser el mateix que el valor de 'Supported'. Enllaç i modes” a l'objecte del dispositiu (/3/0/16).\nTot i que s'admeten diversos transports, només es pot utilitzar una vinculació de transport durant tota la sessió de transport.\nPer exemple, quan s'admeten UDP i SMS. , el client LwM2M i el servidor LwM2M poden triar comunicar-se mitjançant UDP o SMS durant tota la sessió de transport.", + "bootstrap-server": "Servidor Bootstrap", + "lwm2m-server": "Servidor LwM2M", + "include-bootstrap-server": "Inclou actualitzacions del servidor Bootstrap", + "bootstrap-update-title": "Ja heu configurat el servidor Bootstrap. Esteu segur que voleu excloure les actualitzacions?", + "bootstrap-update-text": "Aneu amb compte, després de la confirmació, les dades de configuració del servidor Bootstrap seran irrecuperables.", + "server-host": "Host", + "server-host-required": "Cal host.", + "server-port": "Port", + "server-port-required": "Cal port.", + "server-port-pattern": "El port ha de ser un nombre enter positiu.", + "server-port-range": "El port ha d'estar en un rang d'1 a 65535.", + "server-public-key": "Clau pública del servidor", + "server-public-key-required": "Cal clau pública del servidor.", + "client-hold-off-time": "Temps d'espera", + "client-hold-off-time-required": "cal temps d'espera.", + "client-hold-off-time-pattern": "El temps d'espera ha de ser un enter positiu.", + "client-hold-off-time-tooltip": "El client manté el temps d'espera per al seu ús només amb un servidor Bootstrap", + "account-after-timeout": "Compte després del temps d'espera", + "account-after-timeout-required": "El compte després del temps d'espera és obligatori.", + "account-after-timeout-pattern": "El compte després del temps d'espera ha de ser un enter positiu.", + "account-after-timeout-tooltip": "Compte de servidor d'arrencada després del valor de temps d'espera donat per aquest recurs.", + "server-type": "Tipus de servidor", + "add-new-server-title": "Afegeix una nova configuració del servidor", + "add-server-config": "Afegeix la configuració del servidor", + "add-lwm2m-server-config": "Afegeix el servidor LwM2M", + "no-config-servers": "No s'ha configurat cap servidor", + "others-tab": "Altres configuracions", + "client-strategy": "Estratègia del client a l'hora de connectar-se", + "client-strategy-label": "Estratègia", + "client-strategy-only-observe": "Observeu només la sol·licitud al client després de la connexió inicial", + "client-strategy-read-all": "Llegiu tots els recursos i observeu la sol·licitud al client després del registre", + "fw-update": "Actualització del firmware", + "fw-update-strategy": "Estratègia d'actualització del firmware", + "fw-update-strategy-data": "Envieu l'actualització del microprogramari com a fitxer binari mitjançant l'objecte 19 i el recurs 0 (dades)", + "fw-update-strategy-package": "Envieu l'actualització del microprogramari com a fitxer binari mitjançant l'objecte 5 i el recurs 0 (paquet)", + "fw-update-strategy-package-uri": "Genera automàticament un URL CoAP únic per descarregar el paquet i enviar l'actualització del microprogramari com a Objecte 5 i Recurs 1 (URI del paquet)", + "sw-update": "Actualització de software", + "sw-update-strategy": "Estratègia d'actualització de programari", + "sw-update-strategy-package": "Envieu el fitxer binari mitjançant l'objecte 9 i el recurs 2 (paquet)", + "sw-update-strategy-package-uri": "Genera automàticament un URL CoAP únic per descarregar el paquet i impulsar l'actualització del programari mitjançant Objecte 9 i Recurs 3 (URI del paquet)", + "fw-update-resource": "Recurs CoAP d'actualització del firmware", + "fw-update-resource-required": "Cal recurs CoAP d'actualització del firmware.", + "sw-update-resource": "Recurs CoAP d'actualització de programari", + "sw-update-resource-required": "Cal Recurs CoAP d'actualització de programari.", + "config-json-tab": "Dispositiu de perfil de configuració Json", + "attributes-name": { + "min-period": "Període mínim", + "max-period": "Període màxim", + "greater-than": "Més gran que", + "less-than": "Menys que", + "step": "Pas", + "min-evaluation-period": "Període mínim d'avaluació", + "max-evaluation-period": "Període màxim d'avaluació" + }, + "composite-operations-support": "Admet operacions compostes de lectura/escriptura/observació" + }, + "snmp": { + "add-communication-config": "Afegeix la configuració de comunicació", + "add-mapping": "Afegeix mapeig", + "authentication-passphrase": "Frase de contrasenya d'autenticació", + "authentication-passphrase-required": "Cal frase de contrasenya d'autenticació.", + "authentication-protocol": "Protocol d'autenticació", + "authentication-protocol-required": "Cal protocol d'autenticació.", + "communication-configs": "Configuracions de comunicació", + "community": "Cadena comunitària", + "community-required": "Cal cadena comunitària.", + "context-name": "Nom del context", + "data-key": "Clau de dades", + "data-key-required": "Cal clau de dades.", + "data-type": "Tipus de dades", + "data-type-required": "Cal tipus de dades.", + "engine-id": "ID del motor", + "host": "Host", + "host-required": "Cal host.", + "oid": "OID", + "oid-pattern": "Format OID no vàlid.", + "oid-required": "Cal OID.", + "please-add-communication-config": "Si us plau, afegiu la configuració de comunicació", + "please-add-mapping-config": "Si us plau, afegiu la configuració de mapes", + "port": "Port", + "port-format": "Format de port no vàlid.", + "port-required": "Cal port.", + "privacy-passphrase": "Frase de contrasenya de privadesa", + "privacy-passphrase-required": "Cal frase de contrasenya de privadesa.", + "privacy-protocol": "Protocol de privadesa", + "privacy-protocol-required": "Cal protocol de privadesa.", + "protocol-version": "Versió del protocol", + "protocol-version-required": "Cal versió del protocol.", + "querying-frequency": "Freqüència de consulta, ms", + "querying-frequency-invalid-format": "La freqüència de consulta ha de ser un nombre enter positiu.", + "querying-frequency-required": "Cal freqüència de consulta.", + "retries": "Reintents", + "retries-invalid-format": "Els reintents han de ser un nombre enter positiu.", + "retries-required": "Cal reintents.", + "scope": "Àmbit", + "scope-required": "Cal àmbit.", + "security-name": "Nom de seguretat", + "security-name-required": "Cal nom de seguretat.", + "timeout-ms": "Temps d'espera, ms", + "timeout-ms-invalid-format": "El temps d'espera ha de ser un nombre enter positiu.", + "timeout-ms-required": "Cal temps d'espera.", + "user-name": "Nom d'usuari", + "user-name-required": "Cal nom d'usuari." + } + }, + "dialog": { + "close": "Tancar diàleg" + }, + "direction": { + "column": "Columna", + "row": "Fila" + }, + "edge": { + "edge": "Vora", + "edge-instances": "Instàncies de Vora", + "edge-file": "Arxiu de vora", + "name-max-length": "El nom ha de ser inferior a 256", + "label-max-length": "L'etiqueta ha de ser inferior a 256", + "type-max-length": "El tipus ha de ser inferior a 256", + "management": "Gestió de vores", + "no-edges-matching": "No s'han trobar vores que coincideixin amb '{{entity}}'", + "add": "Afegir vora", + "no-edges-text": "No s'han trobar vores", + "edge-details": "Detalls del vora", + "add-edge-text": "Afegir nova vora", + "delete": "Eliminar vora", + "delete-edge-title": "Està segur de que desitja eliminar la vora '{{edgeName}}'?", + "delete-edge-text": "Aneu amb compte, després de la confirmació, la vora i totes les dades relacionades seran irrecuperables", + "delete-edges-title": "Està segur de que desitja edge {count, plural, 1 {1 borde} other {# bordes} }?", + "delete-edges-text": "Aneu amb compte, després de la confirmació s'eliminaran totes les vores seleccionades i totes les dades relacionades seran irrecuperables", + "name": "Nom", + "name-starts-with": "El nom de la vora comença per", + "name-required": "Cal nom", + "edge-license-key": "Clau de llicència Edge", + "edge-license-key-required": "Necessiteu la clau de llicència Edge", + "edge-license-key-max-length": "La clau de llicència Edge ha de ser inferior a 31", + "edge-license-key-hint": "Per obtenir la seva llicència, aneu a la pàgina de preus i seleccioneu la millor opció de llicència si escau.", + "cloud-endpoint": "Punt final del núvol", + "cloud-endpoint-required": "Cal punt final del núvol", + "cloud-endpoint-max-length": "Cloud Endpoint hauria de ser inferior a 256", + "cloud-endpoint-hint": "Edge requereix l'accés HTTP (s) a la nube (ThingsBoard CE / PE) per verificar la clau de llicència. Especifiqueu l'URL de la núvol a la que Edge pot connectar-se.", + "description": "Descripció", + "details": "Detalls", + "events": "Esdeveniments", + "copy-id": "Copiar ID de vora", + "id-copied-message": "El ID de vora s'ha copiat al porta-retalls", + "sync": "Sinc Edge", + "edge-required": "Cal Edge", + "edge-type": "Tipus de vora", + "edge-type-required": "Cal tipus de vora.", + "event-action": "Informació de l'entitat", + "entity-id": "ID d'entitat", + "select-edge-type": "Seleccionar tipus de vora", + "assign-to-customer": "Assignar al client", + "assign-to-customer-text": "Selecciona el client per assignar les vores", + "assign-edge-to-customer": "Assignar vora(s) al client", + "assign-edge-to-customer-text": "Selecciona les vores per assignar al client", + "assignedToCustomer": "Asignada a la client", + "edge-public": "Edge és pública", + "assigned-to-customer": "Assignat al client", + "unassign-from-customer": "Anul·lar assignació del client", + "unassign-edge-title": "Està segur de que desitja desassignar la vora '{{edgeName}}'?", + "unassign-edge-text": "Després de la confirmació, la vora quedará sense assignar i el client no podrà accedir a ell", + "unassign-edges-title": "Està segur de que desitja anul·lar l'assignació de {count, plural, 1 {1 borde} other {# bordes} }?", + "unassign-edges-text": "Després de la confirmació de totes les vores seleccionades, s'anul·larà l'assignació i el client no podrà accedir a ells.", + "make-public": "Fer públic la vora", + "make-public-edge-title": "Estás segur de que quieres fer públic el edge '{{edgeName}}'?", + "make-public-edge-text": "Després de la confirmació, la vora i totes les seves dades seran públiques i accessibles per altres", + "make-private": "Fer que edge sigui privat", + "public": "Públic", + "make-private-edge-title": "Està segur de que desitja que la vora '{{edgeName}}' sigui privat?", + "make-private-edge-text": "Després de la confirmació, la vora i totes les seves dades seran privades i altres no podrán accedir a ells", + "import": "Importar vora", + "label": "Etiqueta", + "load-entity-error": "Entitat no trobada. No s'ha pogut carregar la informació", + "assign-new-edge": "Assignar nova vora", + "unassign-from-edge": "Anul·lar assignació de vora", + "edge-key": "Clau de vora", + "copy-edge-key": "Copiar clau de vora", + "edge-key-copied-message": "La clau de vora s'ha copiat al porta-retalls", + "edge-secret": "Vora secret", + "copy-edge-secret": "Copiar vora secret", + "edge-secret-copied-message": "El secret de vora s'ha copiat al porta-retalls", + "edge-assets": "Gestionar actius de vores", + "edge-devices": "Gestionar dispositius de vora", + "edge-entity-views": "Gestionar vistes d'entitat de vora", + "edge-dashboards": "Administrar panells de vora", + "edge-rulechains": "Cadenes de regles de vora", + "assets": "Actius de vora", + "devices": "Dispositius de vora", + "entity-views": "Vistes d'entitat de vora", + "dashboard": "Panell de control Edge", + "dashboards": "Panells de vora", + "rulechain-templates": "Plantilles, de cadena de regles", + "rulechains": "Cadenes de regla de vora", + "search": "Vores de cerca", + "selected-edges": "{count, plural, 1 {1 borde} other {# bordes} } seleccionades", + "any-edge": "Qualsevol vora", + "no-edge-types-matching": "No s'han trobar tipus de aristas que coincideixin amb '{{entitySubtype}}'.", + "edge-type-list-empty": "No s'ha seleccionat cap tipus de vora.", + "edge-types": "Tipus de vores", + "enter-edge-type": "Introduïu el tipus de vora", + "deployed": "Desplegada", + "pending": "Pendent", + "downlinks": "Enllaços descendents", + "no-downlinks-prompt": "No s'han trobar enllaços descendents", + "sync-process-started-successfully": "El procés de sincronització és va iniciar correctament!", + "missing-related-rule-chains-title": "A la vora li falten cadenes de regles relacionades", + "missing-related-rule-chains-text": "Assignat a la (es) cadena (es) de regles de vora utilitza nodes de regles que reenvien missatges a cadenes de regles que no están assignades a aquest vora.

              Llista de cadenes de regles que manca:
              {{missingRuleChains}}", + "widget-datasource-error": "Aquest widget només admet la font de dades de l'entitat EDGE", + "assign-to-edge": "Assignar la vora", + "assign-to-edge-title": "Assignar grup (s) d'entitat a Edge", + "manage-edge-user-groups": "Administrar grups d'usuaris perimetrals", + "manage-edge-asset-groups": "Administrar grups d'actius perimetrals", + "manage-edge-device-groups": "Administrar grups de dispositius perimetrals", + "manage-edge-entity-view-groups": "Administrar grups de vistes d'entitats perimetrals", + "manage-edge-dashboard-groups": "Administrar grups de panells de vora", + "manage-edge-rule-chains": "Administrar cadenes de regles de vora", + "manage-edge-scheduler-events": "Administrar esdeveniments del programador de vora", + "select-group-to-add": "Selecciona el grup de destí per afegir les vores seleccionades", + "select-group-to-move": "Selecciona el grup de destí per moure les vores seleccionades", + "remove-edges-from-group": "Està segur de que desitja eliminar {count, plural, 1 {1 borde} other {# bordes} } del grup '{entityGroup}'?", + "group": "Grup de vores", + "list-of-groups": "{count, plural, 1 {Un grupo de bodre} other {Lista de # grupos de bordes} }", + "group-name-starts-with": "Grups de vora els quals comencen amb '{{prefix}}'", + "unassign-entity-group-from-edge-title": "Està segur de que desitja anul·lar l'assignació del grup d'entitat '{{entityGroupName}}'?", + "unassign-entity-group-from-edge-text": "Després de la confirmació, s'anul·larà l'assignació del grup d'entitats i no es podrà accedir a ell des de la vora.", + "unassign-entity-group-from-edge": "Desassignar grup d'entitats des de la vora", + "unassign-entity-groups-from-edge-title": "Està segur de que desitja anul·lar l'assignació de {{count}} grups d'entitats?", + "unassign-entity-groups-from-edge-text": "Després de la confirmació, els grups d'entitats seran desassignat i no seran accessibles des de la vora.", + "unassign-entity-groups-from-edge": "Anul·lar l'assignació de grups d'entitats des de la vora", + "unassign-scheduler-events-from-edge": "Anul·lar l'assignació de esdeveniments del programador des de la vora", + "unassign-scheduler-event-from-edge-title": "Està segur de que desitja anul·lar l'assignació del esdeveniment del programador '{{schedulerEventName}}'?", + "unassign-scheduler-event-from-edge-text": "Després de la confirmació, s'anul·larà l'assignació del esdeveniment del programador i la vora no podrà accedir a ell.", + "unassign-scheduler-events-from-edge-title": "Està segur de que desitja anul·lar l'assignació {{count}} esdeveniments del programador?", + "unassign-scheduler-events-from-edge-text": "Després de la confirmació, tots els esdeveniments del programador seleccionat seran desassignats i no seran accessibles per la vora.", + "manage-user-groups": "Administrar grups d'usuaris", + "manage-asset-groups": "Administrar grups d'actius", + "manage-device-groups": "Administrar grups de dispositius", + "manage-dashboard-groups": "Administrar grups de panells", + "manage-entity-view-groups": "Administrar grups de vista d'entitat", + "manage-scheduler-events": "Administrar esdeveniments del planificador", + "manage-rulechains": "Administrar cadenes de regles", + "assign-scheduler-event-to-edge-title": "Assignar esdeveniments del programador a Edge", + "assign-scheduler-event-to-edge-text": "Selecciona els esdeveniments del programador per assignar a la vora", + "assign-entity-groups-to-edge-text": "Selecciona els grups d'entitats per assignar a la vora" + }, + "edge-event": { + "type-dashboard": "Panell", + "type-asset": "Actiu", + "type-device": "Dispositiu", + "type-device-profile": "Perfil del dispositiu", + "type-entity-view": "Vista d'entitat", + "type-alarm": "Alarma", + "type-entity-group": "Grup d'Entitats", + "type-rule-chain": "Cadena de regles", + "type-rule-chain-metadata": "Metadades de la cadena de regles", + "type-edge": "Edge", + "type-user": "Usuari", + "type-customer": "Client", + "type-relation": "Relació", + "type-widgets-bundle": "Paquet de widgets", + "type-widgets-type": "Tipus de widgets", + "type-admin-settings": "Configuració d'administrador", + "type-scheduler-event": "Agenda d'esdeveniments", + "type-white-labeling": "Etiquetat blanc", + "type-login-white-labeling": "Inici de sessió Etiqueta blanca", + "type-custom-translation": "Traducció personalitzada", + "type-role": "Rol", + "type-group-permission": "Permís de grup", + "action-type-added": "Afegit", + "action-type-deleted": "S'ha suprimit", + "action-type-updated": "Actualitzat", + "action-type-post-attributes": "Atributs de publicació", + "action-type-attributes-updated": "Atributs actualitzats", + "action-type-attributes-deleted": "Atributs suprimits", + "action-type-timeseries-updated": "Sèries temporals actualitzades", + "action-type-credentials-updated": "Credencials actualitzades", + "action-type-assigned-to-customer": "Assignat al client", + "action-type-unassigned-from-customer": "No assignat del client", + "action-type-relation-add-or-update": "Afegir o actualitzar la relació", + "action-type-relation-deleted": "S'ha eliminat la relació", + "action-type-rpc-call": "Trucada RPC", + "action-type-alarm-ack": "Ack d'alarma", + "action-type-alarm-clear": "Alarma esborrada", + "action-type-assigned-to-edge": "Assignat a Edge", + "action-type-unassigned-from-edge": "Sense assignar des d'Edge", + "action-type-credentials-request": "Sol·licitud de credencials", + "action-type-entity-merge-request": "Sol·licitud de fusió d'entitats", + "action-type-added-to-entity-group": "S'ha afegit al grup d'entitats", + "action-type-removed-from-entity-group": "S'ha eliminat del grup d'entitats", + "action-type-change-owner": "Canvia de propietari", + "action-type-relations-deleted": "S'han suprimit les relacions" + }, + "error": { + "unable-to-connect": "Impossible connectar amb el servidor! Per favor, revisi la seva connexió a internet.", + "unhandled-error-code": "Codi d'error no controlat: {{errorCode}}", + "unknown-error": "Error desconegut" + }, + "entity": { + "entity": "Entitat", + "entities": "Entitats", + "entities-count": "Les entitats compten", + "aliases": "Àlies d'entitat", + "entity-alias": "Àlies d'entitat", + "unable-delete-entity-alias-title": "No ha estat possible eliminar l'àlies d'entitat", + "unable-delete-entity-alias-text": "L'àlies d'entitat '{{entityAlias}}' no pot ser eliminat, ja que s'està usant per als següents widgets:
              {{widgetsList}}", + "duplicate-alias-error": "Trobat un àlies duplicat '{{alias}}'.
              Els àlies d'entitat han de ser únics per a cada panell.", + "missing-entity-filter-error": "Falta el filtre per l'àlies '{{alias}}'.", + "configure-alias": "Configurar àlies '{{alias}}' ", + "alias": "Àlies", + "alias-required": "Cal àlies d'entitat.", + "remove-alias": "Eliminar àlies d'entitat", + "add-alias": "Afegir àlies d'entitat", + "entity-list": "Llista d'entitats", + "entity-type": "Tipus d'entitat", + "entity-types": "Tipus d'entitats", + "entity-type-list": "Llista de tipus d'entitat", + "any-entity": "Qualsevol entitat", + "enter-entity-type": "Introduir tipus d'entitat", + "no-entities-matching": "No s'han trobat entitats que coincideixin amb '{{entity}}' .", + "no-entity-types-matching": "No s'han trobat tipus d'entitat que coincideixin amb '{{entityType}}' .", + "name-starts-with": "Nom comença amb", + "help-text": "Utilitzeu '%' segons les necessitats: '%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'.", + "use-entity-name-filter": "Utilitza filtre", + "entity-list-empty": "No hi ha entitats seleccionades.", + "entity-type-list-empty": "No hi ha tipus d'entitat seleccionats.", + "entity-name-filter-required": "Cal filtre de nom d'entitat.", + "entity-name-filter-no-entity-matched": "No hi ha entitats que comencen amb '{{entity}}' .", + "all-subtypes": "Tots", + "select-entities": "Seleccionar entitats", + "no-aliases-found": "No s'han trobat àlies.", + "no-alias-matching": "'{{alias}}' no trobat.", + "create-new-alias": "Crear nou àlies!", + "key": "Clau", + "key-name": "Nom de clau", + "no-keys-found": "No s'han trobat claus.", + "no-key-matching": "'{{key}}' no trobada.", + "create-new-key": "Crear nova clau!", + "type": "Tipus", + "type-required": "Cal tipus d'entitat.", + "type-device": "Dispositiu", + "type-devices": "Dispositius", + "list-of-devices": "{ count, plural, 1 {Un dispositivo} other {Lista de # Dispositivos} }", + "device-name-starts-with": "Dispositius els quals comencen per '{{prefix}}'", + "type-device-profile": "Perfil de dispositiu", + "type-device-profiles": "Perfils de dispositiu", + "list-of-device-profiles": "{ count, plural, 1 {un perfil} other {Lista de # perfiles} }", + "device-profile-name-starts-with": "Perfils els quals comenci per '{{prefix}}'", + "type-asset": "Actiu", + "type-assets": "Actius", + "list-of-assets": "{ count, plural, 1 {Un activo} other {Lista de # activos} }", + "asset-name-starts-with": "Actius els quals comencen per '{{prefix}}'", + "type-entity-view": "Vista Entitat", + "type-entity-views": "Vistes Entitats", + "list-of-entity-views": "{ count, plural, 1 {Una vista de entidad} other {Lista de # Vistas de Entitats} }", + "entity-view-name-starts-with": "Vistes de Entitats els quals comencen per '{{prefix}}'", + "type-rule": "Regla", + "type-rules": "Regles", + "list-of-rules": "{ count, plural, 1 {Una regla} other {Lista de # regles} }", + "rule-name-starts-with": "Regles les quals comencen per '{{prefix}}'", + "type-plugin": "Plugin", + "type-plugins": "Plugins", + "list-of-plugins": "{ count, plural, 1 {Un plugin} other {Lista de # plugins} }", + "plugin-name-starts-with": "Plugins els quals comencen per '{{prefix}}'", + "type-tenant": "Propietari", + "type-tenants": "Propietaris", + "list-of-tenants": "{ count, plural, 1 {Un propietario} other {Lista de # propietarios} }", + "tenant-name-starts-with": "Propietaris els quals comencen per '{{prefix}}'", + "type-tenant-profile": "Perfil de Propietari", + "type-tenant-profiles": "Perfils de propietari", + "list-of-tenant-profiles": "{ count, plural, 1 {Un perfil de propietario} other {Lista de # perfils de propietario} }", + "tenant-profile-name-starts-with": "Pefils de propietari els quals comencen per '{{prefix}}'", + "type-customer": "Client", + "type-customers": "Clients", + "list-of-customers": "{ count, plural, 1 {Un cliente} other {Lista de # clientes} }", + "customer-name-starts-with": "Clients els quals comencen per '{{prefix}}'", + "type-user": "Usuari", + "type-users": "Usuaris", + "list-of-users": "{ count, plural, 1 {Un usuario} other {Lista de # usuaris} }", + "user-name-starts-with": "Usuaris els quals comencen per '{{prefix}}'", + "type-dashboard": "Panell", + "type-dashboards": "Panells", + "list-of-dashboards": "{ count, plural, 1 {Un panel} other {Lista de # paneles} }", + "dashboard-name-starts-with": "Panells els quals comencen per '{{prefix}}'", + "type-alarm": "Alarma", + "type-alarms": "Alarmes", + "list-of-alarms": "{ count, plural, 1 {Una alarma} other {Lista de # alarmas} }", + "alarm-name-starts-with": "Alarmes les quals comencen amb '{{prefix}}'", + "type-rulechain": "Cadena de regles", + "type-rulechains": "Cadenes de regles", + "list-of-rulechains": "{ count, plural, 1 {Una cadena de regles} other {Lista de # cadenes de regles} }", + "rulechain-name-starts-with": "Cadenes de regles les quals comencen amb '{{prefix}}'", + "type-scheduler-event": "Planificador d'esdeveniment", + "type-scheduler-events": "Planificador d'esdeveniment", + "list-of-scheduler-events": "{ count, plural, 1 {One scheduler event} other {List of # scheduler events} }", + "scheduler-event-name-starts-with": "Planificador d'esdeveniment els quals comencen amb '{{prefix}}'", + "type-blob-entity": "Entitat blob", + "type-blob-entities": "Entitats blob", + "list-of-blob-entities": "{ count, plural, 1 {One blob entity} other {List of # blob entities} }", + "blob-entity-name-starts-with": "Entitats blob els quals comencen amb '{{prefix}}'", + "type-rulenode": "Node de regles", + "type-rulenodes": "Nodes de regles", + "list-of-rulenodes": "{ count, plural, 1 {Un nodo de regles} other {Lista de # nodes de regles} }", + "rulenode-name-starts-with": "Nodes de regles els quals comencen amb '{{prefix}}'", + "type-current-customer": "Client Actual", + "type-current-tenant": "Propietari Actual", + "type-current-user": "Usuari Actual", + "type-current-user-owner": "Usuari Propietari Actual", + "search": "Buscar entitats", + "selected-entities": "{ count, plural, 1 {1 entitat} other {# entitats} } seleccionades", + "entity-name": "Nom d'entitat", + "entity-label": "Etiqueta d'entitat", + "details": "Detalls d'entitat", + "no-entities-prompt": "No s'han trobat entitats", + "no-data": "No hi ha dades que mostrar", + "columns-to-display": "Columnes a Mostrar", + "type-api-usage-state": "Estat d'ús de la API", + "type-entity-group": "Grup d'entitats", + "type-converter": "Convertidor de dades", + "type-converters": "Convertidors de dades", + "list-of-converters": "{ count, plural, 1 {One data converter} other {List of # data converters} }", + "converter-name-starts-with": "Convertidors de dades els quals comencen amb '{{prefix}}'", + "type-integration": "Integració", + "type-integrations": "Integracions", + "list-of-integrations": "{ count, plural, 1 {One integration} other {List of # integrations} }", + "integration-name-starts-with": "Integracions les quals comencen amb '{{prefix}}'", + "type-role": "Rol", + "type-roles": "Rols", + "list-of-roles": "{ count, plural, 1 {One role} other {List of # roles} }", + "role-name-starts-with": "Rols els noms dels quals comencen per '{{prefix}}'", + "type-group-permission": "Permís de grup", + "type-edge": "Vora", + "type-edges": "Vores", + "list-of-edges": "{count, plural, 1 {Un borde} other {Lista de # bordes} }", + "edge-name-starts-with": "Vores les quals comencen amb '{{prefijo}}'", + "type-tb-resource": "Recurs", + "type-ota-package": "Paquet OTA" + }, + "entity-group": { + "entity-group": "Grup d'entitats", + "details": "Detalls", + "columns": "Columnes", + "add-column": "Afegir columna", + "column-value": "Valor", + "column-value-required": "Cal valor de la columna.", + "column-title": "Títol", + "default-sort-order": "Orde de clasificació predeterminat", + "default-sort-order-required": "Cal orde de clasificació predeterminat.", + "hide-in-mobile-view": "Móvil ocult", + "use-cell-style-function": "Utilizar funció d'estil de cel·la", + "use-cell-content-function": "Utilizar funció de contingut de cel·la", + "edit-column": "Editar columna", + "column-details": "Detalls de la columna", + "actions": "Accions", + "settings": "Configuració", + "search": "Cerca grups d'entitats", + "delete": "Eliminar grup d'entitats", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "description": "Descripció", + "add": "Afegir grup d'entitats", + "open-entity-group": "Grup d'entitats obert", + "add-entity-group-text": "Afegir nou grup d'entitats", + "no-entity-groups-text": "Grups d'entitats no trobats", + "entity-group-details": "Detalls del grup d'entitats", + "selected-entity-groups": "{ count, plural, 1 {1 entity group} other {# entity groups} } seleccionat", + "delete-entity-groups": "Eliminar grups d'entitats", + "delete-entity-group-title": "Està segur de que desitja eliminar el grup d'entitats '{{entityGroupName}}'?", + "delete-entity-group-text": "Aneu amb compte, després de la confirmació, el grup d'entitats i totes les dades relacionades seran irrecuperables.", + "delete-entity-groups-title": "Està segur de que desitja eliminar { count, plural, 1 {1 entity group} other {# entity groups} }?", + "delete-entity-groups-action-title": "Eliminar { count, plural, 1 {1 entity group} other {# entity groups} }", + "delete-entity-groups-text": "Aneu amb compte, després de la confirmació s'eliminaran tots els grups d'entitats seleccionats i totes les dades relacionades seran irrecuperables.", + "device-groups": "Grups de dispositius", + "asset-groups": "Grups d'actius", + "customer-groups": "Grups de clients", + "device-group": "Grup de dispositius", + "asset-group": "Grup d'actius", + "user-group": "Grup d'usuaris", + "user-groups": "Grups d'usuaris", + "customer-group": "Grup de clients", + "entity-view-groups": "Grups de vista d'entitat", + "entity-view-group": "Grup de vista d'entitat", + "edge-groups": "Grups de vores", + "edge-group": "Grup de vora", + "dashboard-groups": "Grups de panells", + "dashboard-group": "Grup de quadres de comandament", + "fetch-more": "Portar més", + "column-type": { + "column-type": "Tipus de columna", + "client-attribute": "Atribut del client", + "shared-attribute": "Atribut compartit", + "server-attribute": "Atribut del servidor", + "timeseries": "Series temporals", + "entity-field": "Camp d'entitat" + }, + "column-type-required": "Cal el tipus de columna.", + "entity-field": { + "created-time": "Temps de creació", + "name": "Nom", + "type": "Tipus", + "device_profile": "Perfil del dispositiu", + "assigned_customer": "Client Assignat", + "authority": "Autoritat", + "first_name": "Nom", + "last_name": "Cognom", + "email": "Correu electrònic", + "title": "Títol", + "country": "País", + "state": "Estat", + "city": "Ciutat", + "address": "Direcció", + "address2": "Direcció 2", + "zip": "Codi postal", + "phone": "Telèfon", + "label": "Etiqueta" + }, + "sort-order": { + "asc": "Ascendent", + "desc": "Descendent", + "none": "Ningú" + }, + "details-mode": { + "on-row-click": "Clic en la fila", + "on-action-button-click": "Clic en el botó de detalls", + "disabled": "Inhabilitat" + }, + "change-owner": "Change owner", + "select-target-owner": "Seleccioneu el propietari objectiu", + "no-owners-matching": "No hi ha cap propietari que coincideixi '{{owner}}' els van trobar.", + "target-owner-required": "Cal propietari objectiu.", + "confirm-change-owner-title": "Esteu segur que voleu canviar de propietari per { count, plural, 1 {1 selected entity} other {# selected entities} }?", + "confirm-change-owner-text": "Aneu amb compte, després de la confirmació, totes les entitats seleccionades s'eliminaran del propietari actual i es col·locaran al grup 'Tots' del propietari objectiu..", + "add-to-group": "Afegir al grup", + "move-to-group": "Moure al grup", + "select-entity-group": "Seleccionar grup d'entitats", + "no-entity-groups-matching": "Grups d'entitats que coincideixin amb '{{entityGroup}}' no han estat trobats.", + "target-entity-group-required": "Cal grup d'entitats objetiu.", + "select-user-group": "Seleccioneu el grup d'usuaris", + "no-user-groups-matching": "No hi ha cap grup d'usuaris que coincideixi '{{entityGroup}}' els van trobar.", + "target-user-group-required": "Cal grup d'usuaris objectiu.", + "remove-from-group": "Eliminar des de grup", + "group-table-title": "Títol de panell de grup", + "enable-search": "Habilitar cerca d'entitats", + "enable-add": "Habilitar agregació d'entitats", + "enable-delete": "Habilitar eliminació d'entitats", + "enable-selection": "Habilitar selecció d'entitats", + "enable-group-transfer": "Habilitar accions de transferencia de grup", + "display-pagination": "Mostrar paginació", + "default-page-size": "Mida de pàgina predeterminat", + "enable-assignment-actions": "Habilitar accions de assignació", + "enable-credentials-management": "Habilitar gestió de credencials", + "enable-login-as-user": "Activa l'inici de sessió com a acció de l'usuari", + "enable-users-management": "Habilitar gestió d'usuaris", + "enable-customers-management": "Habilitar la gestió de clients", + "enable-assets-management": "Habilitar gestió d'actius", + "enable-devices-management": "Habilitar gestió de dispositius", + "enable-entity-views-management": "Habilitar la gestió de vistes d'entitats", + "enable-edges-management": "Habilitar la gestió de vores", + "enable-dashboards-management": "Habilitar gestió de panells", + "enable-scheduler-events-management": "Habilitar la gestió de esdeveniments del programador", + "open-details-on": "Obrir detalls de l'entitat en", + "select-existing": "Seleccionar grup d'entitats existent", + "create-new": "Crear nou grup d'entitats", + "new-entity-group-name": "Nou nom del grup d'entitats", + "entity-group-list": "Llista de grup d'entitats", + "entity-group-list-empty": "Grups d'entitats no seleccionats.", + "name-starts-with": "El nom de l'entitat de grup comença amb", + "entity-group-name-filter-required": "Cal el nom de filtre per entitat de grup.", + "roles": "Rols", + "permissions": "Permissions", + "public": "Públic", + "entity-group-public": "El grup d'entitats és públic", + "make-public": "Fer públic el grup d'entitats", + "make-private": "Fes que el grup d'entitats sigui privat", + "make-public-entity-group-title": "Esteu segur que voleu fer el grup d'entitats '{{entityGroupName}}' públic?", + "make-public-entity-group-text": "Després de la confirmació, el grup d'entitats i totes les seves entitats es faran públiques i es faran accessibles per altres.", + "make-private-entity-group-title": "Esteu segur que voleu fer el grup d'entitats '{{entityGroupName}}' private?", + "make-private-entity-group-text": "Després de la confirmació, el grup d'entitats i totes les seves entitats es convertiran en privats i no seran accessibles per altres.", + "share": "Comparteix el grup d'entitats", + "copyId": "Copia l'identificador del grup d'entitats", + "idCopiedMessage": "L'identificador del grup d'entitats s'ha copiat al porta-retalls", + "entity-group-name": "Nom del grup d'entitats", + "all-users": "Tots els usuaris" + }, + "entity-field": { + "created-time": "Hora de creació", + "name": "Nom", + "type": "Tipus", + "first-name": "Nom", + "last-name": "Cognom", + "email": "Correu electrònic", + "title": "Títol", + "country": "País", + "state": "Estat", + "city": "Ciudad", + "address": "Direcció", + "address2": "Direcció 2", + "zip": "Códi postal", + "phone": "Telèfon", + "label": "Etiqueta" + }, + "entity-view": { + "entity-view": "Vista d'entitat", + "entity-view-required": "Cal vista d'entitat.", + "entity-views": "Vistes d'entitat", + "management": "Gestió de vistes d'entitat", + "view-entity-views": "Veure vista d'entitat", + "entity-view-alias": "Àlies de vista d'entitat", + "aliases": "Àlies de vista d'entitat", + "no-alias-matching": "'{{alias}}' no trobat.", + "no-aliases-found": "No s'han trobar àlies.", + "no-key-matching": "'{{key}}' no trobada.", + "no-keys-found": "No s'han trobar claus.", + "create-new-alias": "¡Crear un nou!", + "create-new-key": "¡Crear una nova!", + "duplicate-alias-error": "Àlies duplicat'{{alias}}'.
              Els àlies de Entity View han de ser els únics en el panell.", + "configure-alias": "Configurar àlies '{{alias}}'", + "no-entity-views-matching": "No s'han trobar vistes que coincideixin amb '{{entity}}'.", + "public": "Públic", + "alias": "Àlies", + "alias-required": "Cal àlies de vista d'entitat.", + "remove-alias": "Esborrar àlies de la vista d'entitat", + "add-alias": "Afegir àlies a la vista d'entitat", + "name-starts-with": "Nom de vista d'entitat comença amb", + "help-text": "Utilitzeu '%' segons les necessitats: '%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", + "entity-view-list": "Llista de vistes d'entitat", + "use-entity-view-name-filter": "Utilitzar el filtre", + "entity-view-list-empty": "No hi ha vistes d'entitat seleccionades.", + "entity-view-name-filter-required": "Cal nom del filtre de vista d'entitat.", + "entity-view-name-filter-no-entity-view-matched": "No s'han trobar vistes d'entitat que comencen amb '{{entityView}}'.", + "add": "Afegir vista d'entitat", + "entity-view-public": "Vista d'entitat és pública", + "assign-to-customer": "Assignar a client", + "assign-entity-view-to-customer": "Assignar vista d'entitat a client", + "assign-entity-view-to-customer-text": "Per favor, selecciona les vistes d'entitat per assignar al client", + "no-entity-views-text": "No s'han trobar vistas d'entitat", + "assign-to-customer-text": "Per favor, selecciona el client per assignar la vista d'entitat", + "entity-view-details": "Detalls de la vista d'entitat", + "add-entity-view-text": "Afegir nova vista d'entitat", + "delete": "Esborrar vista d'entitat", + "assign-entity-views": "Assignar vistes d'entitat", + "assign-entity-views-text": "Assignar { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } a client", + "delete-entity-views": "Esborrar vistes d'entitat", + "make-public": "Fer pública la vista d'entitat", + "make-private": "Fer que la vista d'entitat sigui privada", + "unassign-from-customer": "Anul·lar assignació a client", + "unassign-entity-views": "Anul·lar assignació de vistes d'entitat", + "unassign-entity-views-action-title": "Anul·lar assignació { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } al client", + "assign-new-entity-view": "Assignar nova vista d'entitat", + "delete-entity-view-title": "Esteu segur que voleu esborrar la vista entitat '{{entityViewName}}'?", + "delete-entity-view-text": "Compte! Després de la confirmació, la vista de l'entitat i totes les dades relacionades seran irrecuperables.", + "delete-entity-views-title": "Esteu segur que voleu esborrar les vistes d'entitat { count, plural, 1 {1 entityView} other {# entityViews} }?", + "delete-entity-views-action-title": "Esborrar { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} }", + "delete-entity-views-text": "Compte! Després de la confirmació, totes les vistes d'entitats seleccionades s'eliminaran i totes les dades relacionades seran irrecuperables.", + "make-public-entity-view-title": "Està segur de que desitja que la vista d'entitat '{{entityViewName}}' sigui pública?", + "make-public-entity-view-text": "Després de la confirmació, la vista de l'entitat i totes les dades seran públiques i accessibles per altres.", + "make-private-entity-view-title": "Està segur de que desitja que la vista d'entitat '{{entityViewName}}' sigui privada?", + "make-private-entity-view-text": "Després de la confirmació, la vista de l'entitat i totes les dades seran privats i no seran accessibles per altres.", + "unassign-entity-view-title": "Esteu segur que voleu anul·lar l'assignació de la vista d'entitat '{{entityViewName}}'?", + "unassign-entity-view-text": "Després de la confirmació, la vista de l'entitat quedarà sense assignar i el client no hi podrà accedir.", + "unassign-entity-view": "Anul·lar assignació de la vista d'entitat", + "unassign-entity-views-title": "Esteu segur que voleu anul·lar l'assignació de { count, plural, 1 {1 vista de entidad} other {# vistas de entidad} }?", + "unassign-entity-views-text": "Després de la confirmació, totes les vistes d'entitats seleccionades quedaran sense assignar i el client no podrà accedir-hi.", + "entity-view-type": "Tipus de vista d'entitat", + "entity-view-type-required": "Cal tipus de vista d'entitat.", + "select-entity-view-type": "Selecciona el tipus de vista d'entitat", + "enter-entity-view-type": "Teclegeu el tipus de vista d'entitat", + "any-entity-view": "Qualsevol vista d'entitat", + "no-entity-view-types-matching": "No s'han trobar tipus de vista d'entitat que coincideixin amb '{{entitySubtype}}'.", + "entity-view-type-list-empty": "No hi ha tipus de vista d'entitat seleccionada.", + "entity-view-types": "Tipus de vista d'entitat", + "created-time": "Data de creació", + "name": "Nom", + "name-required": "Cal nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "type-max-length": "El tipus de visualització d'entitat ha de ser inferior a 256", + "description": "Descripció", + "events": "Esdeveniments", + "details": "Detalls", + "copyId": "Copiar el Id de la vista d'entitat", + "idCopiedMessage": "El Id de la vista d'entitat s'ha copiat al porta-retalls", + "assignedToCustomer": "Assignat a client", + "unable-entity-view-device-alias-title": "No es pot eliminar l'àlies de vista d'entitat", + "unable-entity-view-device-alias-text": "L'àlies del dispositiu '{{entityViewAlias}}' no es pot borrar perquè està sent usat pel widget(s):
              {{widgetsList}}", + "select-entity-view": "Seleccionar vista d'entitat", + "start-date": "Data d'inici", + "start-ts": "Temps d'inici", + "end-date": "Data de finalització", + "end-ts": "Temps de finalització", + "date-limits": "Limits de data", + "client-attributes": "Atributs de client", + "shared-attributes": "Atributs compartits", + "server-attributes": "Atributs de servidor", + "timeseries": "Series temporals", + "client-attributes-placeholder": "Atributs de client", + "shared-attributes-placeholder": "Atributs compartits", + "server-attributes-placeholder": "Atributs de servidor", + "timeseries-placeholder": "Series temporals", + "target-entity": "Entitat objetiu", + "attributes-propagation": "Propagació de atributs", + "attributes-propagation-hint": "La vista d'entitat copiarà automàticament els atributs especificats de l'entitat de destí cada vegada que guardi o actualitzi esta vista d'entitat. Per razones de rendimiento, els atributs d'entitat objetiu no es propagan a la vista d'entitat en cada cambio d'atribut. Puede habilitar la propagación automàtica configurando el node de la regla \"copiar a la vista\" en la seva cadena de regles i vincular els missatges \"Atributs de la publicación\" i \"Atributs actualizados\" al nou node de la regla.", + "timeseries-data": "Dades de series temporals", + "timeseries-data-hint": "Configura les claus de les dades de les series temporals de l'entitat de destí que seran accessibles per la vista de l'entitat. Les dades d'aquesta sèrie temporal són de només lectura.", + "selected-entity-views": "{ count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } seleccionades", + "search": "Buscar vistes d'entitat", + "select-group-to-add": "Seleccioneu el grup objectiu per afegir visualitzacions d'entitat seleccionades", + "select-group-to-move": "Seleccioneu el grup objectiu per moure les vistes d'entitat seleccionades", + "remove-entity-views-from-group": "Esteu segur que voleu eliminar-lo { count, plural, 1 {1 entity view} other {# entity views} } del grup '{{entityGroup}}'?", + "group": "Grup de vistes d'entitat", + "list-of-groups": "{ count, plural, 1 {One entity view group} other {List of # entity view groups} }", + "group-name-starts-with": "Grups de visualització d'entitats els noms dels quals comencen per '{{prefix}}'", + "assign-entity-view-to-edge": "Assignar vista (es) d'entitat a vora", + "assign-entity-view-to-edge-text": "Selecciona les vistes d'entitat per assignar a la vora", + "unassign-entity-view-from-edge-title": "Està segur de que desitja anul·lar l'assignació de la vista d'entitat '{{entityViewName}}'?", + "unassign-entity-view-from-edge-text": "Després de la confirmació, la vista d'entitat quedará sense assignar i la vora no podrà accedir a ella", + "unassign-entity-views-from-edge-action-title": "Anul·lar assignació {count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } del vora", + "unassign-entity-view-from-edge": "Anul·lar assignació de vista d'entitat", + "unassign-entity-views-from-edge-title": "Està segur de que desitja desassignar {count, plural, 1 {1 vista de entidad} other {# vistas de entidad} }?", + "unassign-entity-views-from-edge-text": "Després de la confirmació, totes les vistas d'entitat seleccionades no seran assignades i la vora no podrà accedir a ellas" + }, + "event": { + "events": "Esdeveniments", + "event-type": "Tipus d'esdeveniment", + "events-filter": "Filtre d'esdeveniments", + "clean-events": "Esborrar esdeveniments", + "type-error": "Error", + "type-lc-event": "Cicle de vida de l'esdeveniment", + "type-stats": "Estadístiques", + "type-debug-converter": "Depurar", + "type-debug-integration": "Depurar", + "type-debug-rule-node": "Depuració", + "type-debug-rule-chain": "Depuració", + "no-events-prompt": "Cap esdeveniment trobat.", + "error": "Error", + "alarm": "Alarma", + "event-time": "Hora de l'esdeveniment", + "server": "Servidor", + "body": "Cos", + "method": "Mètode", + "type": "Tipus", + "in": "Dins", + "out": "Fora", + "metadata": "Metadades", + "message": "Missatge", + "entity": "Entitat", + "message-id": "Id Missatge", + "message-type": "Tipus Missatge", + "data-type": "Tipus de Dades", + "relation-type": "Tipus de relació", + "data": "Dades", + "event": "Esdeveniment", + "status": "Estat", + "success": "Èxit", + "failed": "Fallada", + "messages-processed": "Missatges processats", + "min-messages-processed": "Mínim missatges processats", + "errors-occurred": "Van passar errors", + "min-errors-occurred": "S'han produït errors mínims", + "min-value": "S'han produït errors mínims.", + "all-events": "Tots", + "has-error": "Té error", + "entity-id": "Identificador de l'entitat", + "entity-type": "Tipus d'entitat", + "clear-filter": "Esborra el filtre", + "clear-request-title": "Esborra tots els esdeveniments", + "clear-request-text": "Esteu segur que voleu esborrar tots els esdeveniments?", + "type-edge-event": "Enllaç descendent" + }, + "extension": { + "extensions": "Extensions", + "selected-extensions": "{ count, plural, 1 {1 extensión} other {# extensiones} } seleccionades", + "type": "Tipus", + "key": "Clau", + "value": "Valor", + "id": "ID", + "extension-id": "ID d'extensió", + "extension-type": "Tipus d'extensió", + "transformer-json": "JSON *", + "unique-id-required": "El id d'extensió ja existeix.", + "delete": "Esborrar Extensió", + "add": "Afegir Extensió", + "edit": "Editar Extensió", + "view": "Mostra l'extensió", + "delete-extension-title": "Eliminar la extensió '{{extensionId}}'?", + "delete-extension-text": "Atenció, després de la confirmació, l'extensió i els seus dades seran esborrades i irrecuperables.", + "delete-extensions-title": "Eliminar les extensions { count, plural, 1 {1 extensión} other {# extensiones} }?", + "delete-extensions-text": "Atenció, després de la confirmació totes les extensions seleccionades i els seus dades seran esborrats i irrecuperables.", + "converters": "Convertidors", + "converter-id": "Id convertidor", + "configuration": "Configuració", + "converter-configurations": "Configuració de convertidor", + "token": "Tóken de seguretat", + "add-converter": "Afegir convertidor", + "add-config": "Afegir configuració de convertidor", + "device-name-expression": "Expressió del nom de dispositiu", + "device-type-expression": "Expressió del tipus de dispositiu", + "custom": "Personalitzat", + "to-double": "Per a duplicar", + "transformer": "Transformador", + "json-required": "Cal el JSON del transformador.", + "json-parse": "No ha estat possible analitzar el JSON del transformador.", + "attributes": "Atributs", + "add-attribute": "Afegir Atribut", + "add-map": "Afegir element de mapejat", + "timeseries": "Series del temps", + "add-timeseries": "Afegir series del temps", + "field-required": "Cal Camp", + "brokers": "Corredors", + "add-broker": "Afegir corredor", + "host": "Host", + "port": "Port", + "port-range": "El port ha d'estar en un rang de 1 a 65535.", + "ssl": "SSL", + "credentials": "Credencials", + "username": "Usuari", + "password": "Contrasenya", + "retry-interval": "Interval de reintent en mil·lisegons", + "sas": "Signatura d'accés compartit", + "anonymous": "Anònim", + "basic": "Bàsic", + "pem": "PEM", + "ca-cert": "Arxiu de certificat CA *", + "private-key": "Arxiu de clau privat *", + "cert": "Arxiu certificat *", + "no-file": "Cap arxiu seleccionat.", + "drop-file": "Colocar un arxiu o fer clic per seleccionar un arxiu per carregar .", + "mapping": "Mapeig", + "topic-filter": "Filtre de tema", + "converter-type": "Tipus de convertidor", + "converter-json": "Json", + "json-name-expression": "Expressió json per nom del dispositiu", + "topic-name-expression": "Expressió temàtica per nom del dispositiu", + "json-type-expression": "Expressió json per tipus de dispositiu", + "topic-type-expression": "Expressió temàtica per tipus de dispositiu", + "attribute-key-expression": "Expressió per clau d'atribut", + "attr-json-key-expression": "Expressió json per clau d'atribut", + "attr-topic-key-expression": "Expressió temàtica per clau d'atribut", + "request-id-expression": "Expressió per sol·licitud d'ID", + "request-id-json-expression": "Expressió json per sol·licitud d'ID", + "request-id-topic-expression": "Expressió temàtica per sol·licitud d'ID", + "response-topic-expression": "Expressió temàtica per respuesta", + "value-expression": "Expressió per valor", + "topic": "Tema", + "timeout": "Temps d'espera en mil·lisegons", + "converter-json-required": "Cal convertidor json.", + "converter-json-parse": "No es pot analitzar el convertidor json.", + "filter-expression": "Expressió per filtre", + "connect-requests": "Sol·licituds de connexió", + "add-connect-request": "Afegir solicituts de connexió", + "disconnect-requests": "Sol·licituds de desconexió", + "add-disconnect-request": "Afegir sol·licitud de desconexió", + "attribute-requests": "Sol·licituds d'atribut", + "add-attribute-request": "Afegir solicituts d'atribut", + "attribute-updates": "Actualizaciones d'atribut", + "add-attribute-update": "Afegir actualitzacions d'atribut", + "server-side-rpc": "RPC costat servidor", + "add-server-side-rpc-request": "Afegir sol·licitud RPC costat servidor", + "device-name-filter": "Filtre de nom de dispositiu", + "attribute-filter": "Filtre d'atribut", + "method-filter": "Filtre de mètode", + "request-topic-expression": "Expressió temàtica per sol·licitud", + "response-timeout": "Temps d'espera de respuesta en mil·lisegons", + "topic-expression": "Expressió temàtica", + "client-scope": "Alcance del client", + "add-device": "Afegir dispositiu", + "opc-server": "Servidors", + "opc-add-server": "Afegir servidor", + "opc-add-server-prompt": "Per favor afegir servidor", + "opc-application-name": "Nom d'aplicació", + "opc-application-uri": "Aplicació URI", + "opc-scan-period-in-seconds": "Període d'exploració en segons", + "opc-security": "Seguretat", + "opc-identity": "Identitat", + "opc-keystore": "Magatzem de claus", + "opc-type": "Tipus", + "opc-keystore-type": "Tipus", + "opc-keystore-location": "Ubicació *", + "opc-keystore-password": "Contrasenya", + "opc-keystore-alias": "Àlies", + "opc-keystore-key-password": "Clau de contrasenya", + "opc-device-node-pattern": "Patró de node de dispositiu", + "opc-device-name-pattern": "Patró de nom de dispositiu", + "modbus-server": "Servidors/esclaus", + "modbus-add-server": "Afegir servidor/esclau", + "modbus-add-server-prompt": "Per favor afegir servidor/esclau", + "modbus-transport": "Transport", + "modbus-tcp-reconnect": "Reconexió automàtica", + "modbus-rtu-over-tcp": "RTU sobre TCP", + "modbus-port-name": "Nom del port serial", + "modbus-encoding": "Codificació", + "modbus-parity": "Paritat", + "modbus-baudrate": "Taxa de bauds", + "modbus-databits": "Bits de dades", + "modbus-stopbits": "Bits de parada", + "modbus-databits-range": "Bits de dades han d'estar en un rang entre 7 i 8.", + "modbus-stopbits-range": "Bits de parada han d'estar en un rang entre 1 a 2.", + "modbus-unit-id": "ID de unidad", + "modbus-unit-id-range": "ID de unidad ha d'estar en un rang entre 1 a 247.", + "modbus-device-name": "Nom del dispositiu", + "modbus-poll-period": "Període de sondeig (ms)", + "modbus-attributes-poll-period": "Atributs del període de sondeig (ms)", + "modbus-timeseries-poll-period": "Període de sondeig de les series temporals (ms)", + "modbus-poll-period-range": "El període de sondeig ha de ser una valor positiu.", + "modbus-tag": "Etiqueta", + "modbus-function": "Funció", + "modbus-register-address": "Direcció del registre", + "modbus-register-address-range": "Direcció del registre ha d'estar en un rang entre 0 i 65535.", + "modbus-register-bit-index": "Índex de bit", + "modbus-register-bit-index-range": "Índex de bit ha d'estar en un rang entre 0 i 15.", + "modbus-register-count": "Contador del registre", + "modbus-register-count-range": "Contador del registre ha de ser un valor positiu.", + "modbus-byte-order": "Orde del byte", + "sync": { + "status": "Estat", + "sync": "Sincronitzat", + "not-sync": "No Sincronitzat", + "last-sync-time": "Hora d'última sincronització", + "not-available": "No disponible" + }, + "export-extensions-configuration": "Exportar configuració d'extensions", + "import-extensions-configuration": "Importar configuració d'extensions", + "import-extensions": "Importar extensions", + "import-extension": "Importar extensió", + "export-extension": "Exportar extensió", + "file": "Fitxer d'extensions", + "invalid-file-error": "Fitxer d'extensions invàlid", + "text": "TEXT", + "json": "JSON", + "binary": "BINARY", + "hex": "HEX" + }, + "filter": { + "add": "Afegir filtre", + "edit": "Editar filtre", + "name": "Nom de filtre", + "name-required": "Cal nom de filtre.", + "duplicate-filter": "Ja existeix un filtre amb el mateix nom.", + "filters": "Filtres", + "unable-delete-filter-title": "Error esborrant filtre", + "unable-delete-filter-text": "El filtre '{{filter}}' no pot ser borrat pel fet que està sent usat actualment pels següents widgets:
              {{widgetsList}}", + "duplicate-filter-error": "S'ha trobat un filtre duplicat '{{filter}}'.
              Els filtres han de ser únics en el panell.", + "missing-key-filters-error": "No s'ha trobar la clau de filtres per el filtre '{{filter}}'.", + "filter": "Filtre", + "editable": "Editable", + "no-filters-found": "No s'han trobar filtres.", + "no-filter-text": "No s'ha especificat filtre", + "add-filter-prompt": "Per favor, añadir filtre", + "no-filter-matching": "'{{filter}}' no trobat.", + "create-new-filter": "Crear un filtre nou!", + "filter-required": "Cal filtre.", + "operation": { + "operation": "Operació", + "equal": "igual", + "not-equal": "no igual", + "starts-with": "comença amb", + "ends-with": "acaba amb", + "contains": "conté", + "not-contains": "no conté", + "greater": "més gran que", + "less": "menor que", + "greater-or-equal": "més gran o igual", + "less-or-equal": "menor o igual", + "and": "i", + "or": "o", + "in": "dins de ", + "not-in": "no dins" + }, + "ignore-case": "Ignorar majús/minus", + "value": "Valor", + "remove-filter": "Esborrar filtre", + "preview": "Vista previa de filtre", + "no-filters": "No hi ha filtres configurats", + "add-filter": "Afegir filtre", + "add-complex-filter": "Afegir filtre complex", + "add-complex": "Afegir filtre complex", + "complex-filter": "Filtre complex", + "edit-complex-filter": "Editar filtre complex", + "edit-filter-user-params": "Editar paràmetres d'usuari del filtre", + "filter-user-params": "Filtre de paràmetres d'usuari (predicado)", + "user-parameters": "Paràmetres d'usuari", + "display-label": "Etiqueta a mostrar", + "autogenerated-label": "Auto generar etiqueta", + "order-priority": "Prioritat orden de campos", + "key-filter": "Filtres (clau)", + "key-filters": "Filtres (claus)", + "key-name": "Nom de clau", + "key-name-required": "Cal nom de clau.", + "key-type": { + "key-type": "Tipus de clau", + "attribute": "Atribut", + "timeseries": "Sèries temporals", + "entity-field": "Camp d'entitat", + "constant": "Constant" + }, + "value-type": { + "value-type": "Tipus de valor", + "string": "Cadena", + "numeric": "Numèric", + "boolean": "Booleà", + "date-time": "Data/Hora" + }, + "value-type-required": "Cal tipus de valor.", + "key-value-type-change-title": "Canviar el tipus de valor de la clau?", + "key-value-type-change-message": "Si tu confirmes el nou tipus, tots els filtres s'esborraran.", + "no-key-filters": "No hi ha filtres claus configurats", + "add-key-filter": "Afegir filtre clau", + "remove-key-filter": "Esborrar filtre clau", + "edit-key-filter": "Editar filtre clau", + "date": "Data", + "time": "Hora", + "current-tenant": "Admin actual", + "current-customer": "Client actual", + "current-user": "Usuari actual", + "current-device": "Dispositiu actual", + "default-value": "Valor per defecte", + "dynamic-source-type": "Tipus d'origen dinàmic", + "dynamic-value": "Valor dinàmic", + "no-dynamic-value": "Sense valor dinàmic", + "source-attribute": "Atribut d'origen", + "switch-to-dynamic-value": "Canviar a valor dinàmic", + "switch-to-default-value": "Canviar a valor per defecte", + "inherit-owner": "Heretar del propietari", + "source-attribute-not-set": "Si l'atribut d'origen no està definit" + }, + "fullscreen": { + "expand": "Expandir a Pantalla Completa", + "exit": "Sortir de Pantalla Completa", + "toggle": "Canviar el modo de Pantalla Completa", + "fullscreen": "Pantalla Completa" + }, + "function": { + "function": "Funció" + }, + "gateway": { + "add-entry": "Afegir configuració", + "connector-add": "Afegir conector", + "connector-enabled": "Activar conector", + "connector-name": "Nom conector", + "connector-name-required": "Cal nom conector.", + "connector-type": "Tipus conector", + "connector-type-required": "Cal tipus conector.", + "connectors": "Configuració de conectors", + "create-new-gateway": "Crear un gateway nou", + "create-new-gateway-text": "Crear un nou gateway amb el nom: '{{gatewayName}}'?", + "delete": "Esborrar configuració", + "download-tip": "Descarregar fitxer de configuració", + "gateway": "Gateway", + "gateway-exists": "Ja existeix un dispositiu amb el mateix nom.", + "gateway-name": "Nom de Gateway", + "gateway-name-required": "Cal un nom de gateway.", + "gateway-saved": "Configuració de gateway gravada satisfactòriament.", + "json-parse": "JSON no vàlid.", + "json-required": "El camp no pot ser buit.", + "no-connectors": "No hi ha conectors", + "no-data": "No hi ha configuracions", + "no-gateway-found": "No s'ha trobat cap gateway.", + "no-gateway-matching": " '{{item}}' no trobat.", + "path-logs": "Ruta als fitxers de log", + "path-logs-required": "Cal ruta.", + "remote": "Configuració remota", + "remote-logging-level": "Nivel de logging", + "remove-entry": "Esborrar configuració", + "save-tip": "Gravar fitxer de configuració", + "security-type": "Tipus de seguretat", + "security-types": { + "access-token": "Token d'accés", + "tls": "TLS" + }, + "storage": "Grabació", + "storage-max-file-records": "Número màxim de registres en fitxer", + "storage-max-files": "Número màxim de fitxers", + "storage-max-files-min": "El número mínim és 1.", + "storage-max-files-pattern": "Número no vàlid.", + "storage-max-files-required": "Cal número.", + "storage-max-records": "Màxim de registres en el magatzem", + "storage-max-records-min": "El número mínim és 1.", + "storage-max-records-pattern": "Número no vàlid.", + "storage-max-records-required": "Cal número.", + "storage-pack-size": "Mida màxim de esdeveniments", + "storage-pack-size-min": "El número mínim és 1.", + "storage-pack-size-pattern": "Número no vàlid.", + "storage-pack-size-required": "Cal número.", + "storage-path": "Ruta de magatzem", + "storage-path-required": "Cal ruta de magatzem.", + "storage-type": "Tipus de magatzem", + "storage-types": { + "file-storage": "Magatzem fitxer", + "memory-storage": "Magatzem en memoria" + }, + "thingsboard": "ThingsBoard", + "thingsboard-host": "Host ThingsBoard", + "thingsboard-host-required": "Cal Host.", + "thingsboard-port": "Port ThingsBoard", + "thingsboard-port-max": "El port màxim és 65535.", + "thingsboard-port-min": "El port mínim és 1.", + "thingsboard-port-pattern": "Port no vàlid.", + "thingsboard-port-required": "Cal port.", + "tidy": "Endreçat", + "tidy-tip": "Endreçat JSON", + "title-connectors-json": "Configuració conector {{typeName}}", + "tls-path-ca-certificate": "Ruta al certificat CA al gateway", + "tls-path-client-certificate": "Ruta al certificat client al gateway", + "tls-path-private-key": "Ruta a la clau privada al gateway", + "toggle-fullscreen": "Pantalla completa fullscreen", + "transformer-json-config": "Configuració JSON*", + "update-config": "Afegir/actualizar configuració JSON" + }, + "grid": { + "delete-item-title": "Vols eliminar aquest item?", + "delete-item-text": "Atenció, després de la confirmació l'item serà eliminat i la informació relacionada serà irrecuperable.", + "delete-items-title": "Vols eliminar { count, plural, 1 {1 item} other {# items} }?", + "delete-items-action-title": "Eliminar { count, plural, 1 {1 item} other {# items} }", + "delete-items-text": "Atenció, després de la confirmació els items seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "add-item-text": "Afegir nou item", + "no-items-text": "Cap item trobat", + "item-details": "Detalls del item", + "delete-item": "Esborrar Item", + "delete-items": "Esborrar Items", + "scroll-to-top": "Anar cap amunt" + }, + "help": { + "goto-help-page": "Anar a la pàgina d'ajuda", + "show-help": "Mostra ajuda" + }, + "home": { + "home": "Principal", + "profile": "Perfil", + "logout": "Sortir", + "menu": "Menu", + "avatar": "Avatar", + "open-user-menu": "Obrir menú d'usuari" + }, + "file-input": { + "browse-file": "Navegar fitxer", + "browse-files": "Navegar fitxers" + }, + "image-input": { + "drop-image-or": "Arrossegar i deixar anar imatges o", + "drop-images-or": "Arrossegar i deixar anar imatges o", + "no-images": "No hi ha imatges seleccionades", + "images": "imatges" + }, + "import": { + "no-file": "Cap arxiu seleccionat", + "drop-file": "Deixeu anar un arxiu JSON o feu clic per seleccionar un arxiu per carregar.", + "drop-json-file-or": "Sol un fitxer JSON o", + "drop-csv-file": "Deixeu anar un fitxer CSV o feu clic per seleccionar un fitxer per carregar.", + "drop-file-csv": "Suelte un arxiu CSV o haga clic per seleccionar un arxiu per carregar.", + "column-value": "Valor", + "column-title": "Títol", + "column-example": "Dades Sortird'exemple", + "column-key": "Clau d'atribut/telemetria", + "credentials": "Credencials", + "csv-delimiter": "Delimitador CSV", + "csv-first-line-header": "La primera línia conté noms de columna.", + "csv-update-data": "Actualizar atributs/telemetria", + "details": "Detalls", + "import-csv-number-columns-error": "Un arxiu ha de contener almenys dos columnes", + "import-csv-invalid-format-error": "Formato de arxiu invàlid. Línea: '{{line}}'", + "column-type": { + "name": "Nom", + "type": "Tipus", + "label": "Etiqueta", + "column-type": "Tipus de columna", + "client-attribute": "Atribut de client", + "shared-attribute": "Atribut compartit", + "server-attribute": "Atribut de servidor", + "timeseries": "Series del temps", + "entity-field": "Camp d'entitat", + "access-token": "Token d'accés", + "x509": "X.509", + "mqtt": { + "client-id": "ID de client MQTT", + "user-name": "Nom d'usuari MQTT", + "password": "Contrasenya MQTT" + }, + "lwm2m": { + "client-endpoint": "Nom del client del punt final LwM2M", + "security-config-mode": "Mode de configuració de seguretat LwM2M", + "client-identity": "Identitat del client LwM2M", + "client-key": "Clau de client LwM2M", + "client-cert": "Clau pública del client LwM2M", + "bootstrap-server-security-mode": "Mode de seguretat del servidor d'arrencada LwM2M", + "bootstrap-server-secret-key": "Clau secreta del servidor d'arrencada LwM2M", + "bootstrap-server-public-key-id": "Clau pública o identificador del servidor d'arrencada LwM2M", + "lwm2m-server-security-mode": "Mode de seguretat del servidor LwM2M", + "lwm2m-server-secret-key": "Clau secreta del servidor LwM2M", + "lwm2m-server-public-key-id": "ID o clau pública del servidor LwM2M" + }, + "isgateway": "Es Gateway", + "activity-time-from-gateway-device": "Data d'activitat des del dispositiu gateway", + "description": "Descripció", + "edge-license-key": "Clau de llicència", + "cloud-endpoint": "Punt final del núvol", + "routing-key": "Clau Edge", + "secret": "Edge secret" + }, + "stepper-text": { + "select-file": "Selecciona un arxiu", + "configuration": "Importar configuració", + "column-type": "Seleccionar tipus de columnes", + "creat-entities": "Creant noves entitats", + "done": "Fet" + }, + "message": { + "create-entities": "Es van crear{{count}} noves entitats correctament.", + "update-entities": "{{count}} entitats s'han actualitzat correctament.", + "error-entities": "S'ha produit un error en crear {{count}} entitats." + } + }, + "integration": { + "integration": "Integració", + "integrations": "Integracions", + "select-integration": "Seleccionar integració", + "no-integrations-matching": "Integracions que coincideixin amb '{{entity}}' no han estat trobades.", + "integration-required": "Cal integració", + "delete": "Eliminar integració", + "management": "Gestió d'integracions", + "add-integration-text": "Afegir nova integració", + "no-integrations-text": "Integracions no trobades", + "selected-integrations": "{ count, plural, 1 {1 integration} other {# integrations} } seleccionades", + "delete-integration-title": "Està segur de que desitja eliminar la integració '{{integrationName}}'?", + "delete-integration-text": "Aneu amb compte, després de la confirmació, la integració i totes les dades relacionades seran irrecuperables.", + "delete-integrations-title": "Està segur de que desitja eliminar { count, plural, 1 {1 integration} other {# integrations} }?", + "delete-integrations-action-title": "Eliminar { count, plural, 1 {1 integration} other {# integrations} }", + "delete-integrations-text": "Aneu amb compte, després de la confirmació s'eliminaran totes les integracions seleccionades i totes les dades relacionades seran irrecuperables.", + "events": "Esdeveniments", + "enabled": "Habilitat", + "allow-create-devices-or-assets": "Permet crear dispositius o actius", + "add": "Afegir Integració", + "search": "Cerca integracions", + "integration-details": "Detalls d'Integració", + "details": "Detalls", + "copyId": "Copiar ID d'integració", + "idCopiedMessage": "ID d'integració ha estat copiada al porta-retalls", + "debug-mode": "Manera de depuració", + "enable-security": "Habilitar seguretat", + "enable-security-new": "Habiliteu la seguretat per les actualitzacions automàtiques de tokens", + "headers-filter": "Filtre d'encapçalats", + "header": "Encapçalats", + "no-headers-filter": "Cap filtre d'encapçalats", + "downlink-url": "URL d'enllaç descendent", + "downlink-url-required": "Cal URL d'enllaç descendent", + "create-loriot-output": "Creeu la sortida de l'aplicació Loriot", + "send-downlink": "Envia l'enllaç descendent", + "server": "Servidor", + "server-required": "Cal servidor", + "domain": "Domini", + "app-id": "ID de l'aplicació", + "app-id-required": "Cal ID de l'aplicació", + "app-token": "Token d'accés a l'aplicació", + "app-token-required": "Cal token d'accés a l'aplicació", + "email": "Correu electrònic", + "email-required": "Cal correu electrònic", + "application-uri": "Aplicació URI", + "as-id": "ID AS", + "as-id-required": "Cal ID AS.", + "as-key": "Clau AS", + "as-key-required": "Cal clau AS.", + "client-id-new": "Identificació del client", + "client-id-new-required": "Cal ID de client (inici de sessió)", + "client-secret": "Contrasenya del client", + "client-secret-required": "Cal el secret del client (contrasenya).", + "max-time-diff-in-seconds": "Màxima diferencia del temps (segons)", + "max-time-diff-in-seconds-required": "Diferencia màxima del temps és requerida.", + "created-time": "Temps creat", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "description": "Descripció", + "base-url": "URL base", + "base-url-required": "Cal URL base", + "security-key": "Clau de seguretat", + "http-endpoint": "URL del punt final HTTP", + "replace-no-content-to-ok": "Substitueix l'estat de resposta de 'Sense contingut' per 'D'acord'", + "copy-http-endpoint-url": "Copiar URL del punt final HTTP", + "http-endpoint-url-copied-message": "L'URL del punt final HTTP ha estat copiada al porta-retalls", + "host": "Host", + "host-required": "Cal Host.", + "host-type": "Tipus de Host", + "host-type-required": "Cal tipus de Host.", + "api-version": "Utilitzeu l'API v3", + "custom-host": "Host personalitzat", + "custom-host-required": "Cal Host personalitzat.", + "port": "Port", + "port-required": "Cal Port.", + "port-range": "El port ha d'estar en un rang entre 1 i 65535.", + "connect-timeout": "Temps d'espera de connexió (seg)", + "connect-timeout-required": "Cal temps d'espera de connexió.", + "connect-timeout-range": "Temps d'espera de connexió ha d'estar en un rang entre 1 i 200.", + "client-id": "ID del client", + "client-id-required": "Cal Client ID.", + "client-id-range": "L'identificador de client ha de tenir entre 1 i 23 caràcters. [MQTT-3.1.3-5]", + "client-id-pattern": "L'identificador de client ha de constar de números, lletres majúscules i minúscules. [MQTT-3.1.3-5]", + "client-id-hint": "Pista: opcional. Deixeu en blanc l'identificador de client generat automàticament. Aneu amb compte quan especifiqueu l'identificador de client. La majoria dels corredors de MQTT no permetran connexions múltiples amb el mateix identificador de client. Per connectar-se a aquests corredors, el vostre identificador de client mqtt ha de ser únic.", + "max-bytes-in-message": "Màxim bytes al missatge", + "max-bytes-in-message-range": "El màxim de bytes del missatge hauria d'estar en un interval d'1 a 256000000.", + "device-id": "ID del dispositiu", + "device-id-required": "Cal ID del dispositiu.", + "device-id-range": "L'identificador del dispositiu ha d'estar en un interval d'entre 1 i 65535 caràcters.", + "device-id-pattern": "L'identificador del dispositiu ha de constar de números, lletres majúscules i minúscules. [MQTT-3.1.3-5]", + "group-id": "ID del grup", + "group-id-required": "Cal ID del grup.", + "topics": "Temes", + "topics-required": "Cal temes.", + "routing-keys": "Claus d'encaminament", + "routing-keys-required": "Cal claus d'encaminament.", + "queues": "Cues", + "queues-required": "Cal el nom de la cua.", + "durable": "Durable", + "exclusive": "Exclusiu", + "autoDelete": "Supressió automàtica", + "exchange-name": "Nom d'intercanvi", + "exchange-name-required": "Cal nom d'intercanvi.", + "downlink-topic": "Tema d'enllaç descendent", + "connection-timeout": "Temps d'espera de connexió, ms", + "connection-timeout-min": "Valor de temps d'espera de connexió no vàlid.", + "handshake-timeout": "Temps d'espera de l'encaixada, ms", + "handshake-timeout-min": "El valor del temps d'espera de la connexió de mans no és vàlid.", + "virtual-host": "Amfitrió virtual", + "rabbit-mq-poll-interval": "Interval d'enquesta, ms", + "rabbit-mq-poll-interval-min": "El valor de l'interval d'enquesta no és vàlid.", + "application-server-url": "URL del servidor d'aplicacions", + "application-server-url-required": "Cal URL del servidor d'aplicacions.", + "application-server-api-token": "Token de l'API del servidor d'aplicacions", + "application-server-api-token-required": "Cal Token de l'API del servidor d'aplicacions.", + "bootstrap-servers": "Servidors d'arrencada", + "bootstrap-servers-required": "Cal servidors d'arrencada.", + "poll-interval": "Interval d'enquesta", + "poll-interval-required": "Cal interval d'enquesta.", + "auto-create-topics": "Creació automàtica de temes", + "clean-session": "Netejar sessió", + "enable-ssl": "Habilitar SSL", + "credentials": "Credencials", + "credentials-type": "Tipus de credencials", + "credentials-type-required": "Cal el tipus de credencials.", + "username": "Nom d'usuari", + "username-required": "Cal el nom d'usuari.", + "password": "Contrasenya", + "password-required": "Cal contrasenya és requerid.", + "azure-ca-cert": "Fitxer de certificat CA", + "ca-cert": "Arxiu de certificat CA *", + "private-key": "Arxiu de clau privat *", + "private-key-password": "Clau de contrasenya privada", + "cert": "Arxiu de certificat *", + "no-file": "Cap arxiu seleccionat.", + "drop-file": "Colocar un arxiu o fer clic per seleccionar un arxiu per carregar .", + "check-connection": "Comproveu la connexió", + "check-success": "Connexió establerta.", + "topic-filters": "Filtres de tema", + "remove-topic-filter": "Eliminar filtres de tema", + "add-topic-filter": "Afegir filtres de tema", + "add-topic-filter-prompt": "Per favor afegir filtres de tema", + "topic": "Tema", + "mqtt-qos": "QoS", + "mqtt-qos-at-most-once": "Com a màxim una vegada", + "mqtt-qos-at-least-once": "Almenys una vegada", + "mqtt-qos-exactly-once": "Exactamente una vegada", + "downlink-topic-pattern": "Patró de tema del enllaç descendent", + "downlink-topic-pattern-required": "Cal patró de tema del enllaç descendent.", + "aws-access-key-id": "Id. de la clau d'accés AWS", + "aws-secret-access-key": "Clau d'accés secreta d'AWS", + "aws-region": "Regió", + "aws-iot-endpoint": "Extrem AWS IoT", + "aws-iot-endpoint-required": "Cal extrem AWS IoT.", + "aws-iot-credentials": "Credencials AWS IoT", + "aws-sqs-polling-period-in-seconds": "Període de votació en segons", + "aws-sqs-queue-url": "URL de la cua SQS", + "aws-sqs-queue-url-required": "Cal URL de la cua SQS", + "aws-sqs-access-key-id-required": "Cal Id. de la clau d'accés", + "aws-sqs-secret-access-key-required": "Cal clau d'accés secreta", + "application-credentials": "Credencials d'aplicació", + "api-key": "Clau API", + "api-key-required": "Cal clau API.", + "api-key-format": "Format de clau d'API no vàlid.", + "auth-token": "Token d'Autenticació", + "auth-token-required": "Cal Token d'Autenticació.", + "region": "Regió", + "region-required": "Cal regió.", + "application-id": "ID d'aplicació", + "application-id-required": "Cal ID de Aplicació.", + "access-key": "Clau de Accés", + "access-key-required": "Cal clau de Accés.", + "connection-parameters": "Paràmetres de connexió", + "service-bus-namespace-name": "Espai de Noms del Bus de Serveis", + "service-bus-namespace-name-required": "Cal nom de l'espai de Noms del Bus de Serveis.", + "connection-string": "Cadena de connexió", + "consumer-group": "Grup de consumidors", + "connection-string-required": "Cal cadena de connexió!", + "event-hub-name": "Nom del Concentrador de Esdeveniments", + "event-hub-name-required": "Cal nom del Concentrador de Esdeveniments.", + "event-iot-hub-name-required": "El nom del concentrador Iot és necessari per a l'enllaç descendent", + "sas-key-name": "Nom de clau SAS", + "sas-key-name-required": "Cal nom de Clau SAS.", + "sas-key": "Clau SAS", + "sas-key-required": "Cal clau SAS.", + "iot-hub-name": "Nom del Concentrador IoT (Cal per enllaç descendent)", + "hostname": "Hostname", + "hostname-required": "Cal hostname", + "integration-clazz": "Classe d'integració", + "integration-clazz-required": "Classe d'integració", + "integration-configuration": "Configuració JSON d'integració", + "metadata": "Metadades", + "type": "Tipus", + "type-required": "Cal el tipus.", + "uplink-converter": "Convertidor de dades del enllaç ascendent", + "uplink-converter-required": "Cal convertidor de dades del enllaç ascendent.", + "downlink-converter": "Convertidor de dades del enllaç descendent", + "type-http": "HTTP", + "type-ocean-connect": "OceanConnect", + "type-sigfox": "SigFox", + "type-thingpark": "ThingPark", + "type-loriot": "Loriot", + "type-thingpark-enterprise": "ThingParkEnterprise", + "type-tmobile-iot-cdp": "iotcreators.com (T-Mobile – IoT CDP)", + "type-mqtt": "MQTT", + "type-aws-iot": "AWS IoT", + "type-aws-sqs": "AWS SQS", + "type-aws-kinesis": "AWS Kinesis", + "type-ibm-watson-iot": "IBM Watson IoT", + "type-ttn": "The Things Stack Community", + "type-tti": "The Things Stack Industries", + "type-chirpstack": "ChirpStack", + "type-azure-event-hub": "Azure Event Hub", + "type-azure-iot-hub": "Azure IoT Hub", + "type-opc-ua": "OPC-UA", + "type-custom": "Custom", + "type-coap": "CoAP", + "type-udp": "UDP", + "type-tcp": "TCP", + "type-kafka": "Kafka", + "type-rabbitmq": "RabbitMQ", + "type-pubsub": "Pub/Sub", + "opc-ua-application-name": "Nom d'aplicació", + "opc-ua-application-uri": "Aplicació URI", + "opc-ua-scan-period-in-seconds": "Període d'exploració en segons", + "opc-ua-scan-period-in-seconds-required": "Cal període d'exploració", + "opc-ua-timeout": "Temps d'espera en mil·lisegons", + "opc-ua-timeout-required": "Cal temps d'espera", + "opc-ua-security": "Seguretat", + "opc-ua-security-required": "Cal seguretat", + "opc-ua-identity": "Identitat", + "opc-ua-identity-required": "Cal identitat", + "opc-ua-keystore": "Repositori", + "add-opc-ua-keystore-prompt": "Per favor afegir arxiu del repositori", + "opc-ua-keystore-required": "Cal repositori", + "opc-ua-type": "Tipus", + "opc-ua-keystore-type": "Tipus", + "opc-ua-keystore-type-required": "Cal tipus", + "opc-ua-keystore-location": "Ubicació *", + "opc-ua-keystore-password": "Contrasenya", + "opc-ua-keystore-password-required": "Cal contrasenya", + "opc-ua-keystore-alias": "Àlies", + "opc-ua-keystore-alias-required": "Cal Àlies", + "opc-ua-keystore-key-password": "Clau de contrasenya", + "opc-ua-keystore-key-password-required": "Cal clau de contrasenya", + "opc-ua-mapping": "Mapeig", + "add-opc-ua-mapping-prompt": "Per favor afegir mapatge", + "opc-ua-mapping-type": "Tipus de mapatge", + "opc-ua-mapping-type-required": "Cal Tipus de mapatge", + "opc-ua-device-node-pattern": "Patró de Node del Dispositiu", + "opc-ua-device-node-pattern-required": "Cal Patró de Node del Dispositiu", + "opc-ua-namespace": "Namespace", + "opc-ua-add-map": "Afegir element de mapatge", + "kinesis-stream-name": "Nom del flux", + "kinesis-stream-name-required": "Cal nom del flux", + "kinesis-region": "Regió", + "kinesis-region-required": "Cal Regió", + "kinesis-access-key-id": "Id. de la clau d'accés", + "kinesis-access-key-id-required": "Cal Id. de la clau d'accés", + "kinesis-secret-access-key": "Clau d'accés secreta", + "kinesis-secret-access-key-required": "Cal clau d'accés secreta", + "kinesis-use-consumers-with-enhanced-fan-out": "Utilitzeu consumidors amb Fan-Out millorat", + "kinesis-use-credentials-from-instance-metadata": "Utilitzeu les credencials de l'Amazon EC2 Instance Metadata Service", + "kinesis-application-name": "Nom de l'aplicació (by default equals Stream name)", + "kinesis-initial-position-in-stream": "Posició inicial al corrent", + "kinesis-initial-position-in-stream-required": "Cal posició inicial al corrent", + "kinesis-max-records": "Màxim registres", + "kinesis-max-records-required": "Cal màxim registres", + "kinesis-max-records-length-range": "La longitud màxima dels registres hauria d'estar entre 1 i 10.000", + "kinesis-request-timeout": "Sol·licita el temps d'espera en segons", + "kinesis-request-timeout-required": "Cal el temps d'espera de la sol·licitud", + "other-properties": "Altres propietats", + "subscription-tags": "Etiquetes de subscripció", + "remove-subscription-tag": "Eliminar etiqueta de subscripció", + "add-subscription-tag": "Afegir etiqueta de suscripció", + "add-subscription-tag-prompt": "Per favor afegir etiqueta de suscripció", + "key": "Clau", + "path": "Trajecte", + "required": "Requerit", + "integration-key": "Clau d'integració", + "copy-integration-key": "Copiar clau d'integració", + "integration-key-copied-message": "La clau d'integració s'ha copiat al porta-retalls", + "integration-secret": "Secret d'integració", + "copy-integration-secret": "Copiar Secret d'integració", + "integration-secret-copied-message": "El secret d'integració s'ha copiat al porta-retalls", + "execute-remotely": "Executar a distància", + "handler-configuration": "Configuració del gestor", + "handler-configuration-type": "Tipus de comerciant", + "so-broadcast": "Habilita la difusió: la integració acceptarà paquets d'adreces de difusió", + "so-keepalive-option": "Habiliteu l'enviament de missatges de manteniment en els sòcols orientats a la connexió", + "so-reuse-addr": "Enllaçar el procés a un port", + "tcp-no-delay": "Força un sòcol a enviar les dades sense emmagatzemar la memòria intermèdia (desactiva l'algoritme de memòria intermèdia de Nagle)", + "fail-fast": "L'excepció llançada tan bon punt el descodificador noti que la longitud del fotograma superarà la mida màxima", + "strip-delimiter": "Delimitador de franges", + "length-field-offset": "Desplaçament de camp de longitud", + "length-field-offset-required": "Cal desplaçament de camp de longitud.", + "length-field-offset-range": "El desplaçament del camp de longitud ha d'estar en un interval de 0 a 8.", + "length-field-length": "Longitud Longitud del camp", + "length-field-length-required": "La longitud del camp és necessària.", + "length-field-length-range": "La longitud del camp ha d'estar en un interval de 0 a 8.", + "length-adjustment": "Ajust de longitud (el valor de compensació que cal afegir al valor del camp de longitud)", + "length-adjustment-required": "Cal un ajust de longitud.", + "length-adjustment-range": "L'ajust de longitud ha d'estar en un rang de 0 a 8.", + "byte-order": "Ordre de bytes del camp de longitud", + "initial-bytes-to-strip": "Nombre de primers bytes per eliminar del marc descodificat", + "initial-bytes-to-strip-required": "Cal el nombre de primers bytes per treure de la trama descodificada.", + "initial-bytes-to-strip-range": "El nombre de primers bytes per eliminar del marc descodificat hauria d'estar en un interval de 0 a 8.", + "so-backlog-option": "Nombre màxim de connexions pendents a la presa", + "so-backlog-option-required": "Cal el nombre màxim de connexions pendents al sòcol.", + "so-backlog-option-range": "El nombre màxim de connexions pendents a l'endoll hauria d'estar entre 1 i 65535.", + "so-rcv-buf": "Mida de la memòria intermèdia per al sòcol d'entrada (en KB)", + "so-rcv-buf-required": "La mida de la memòria intermèdia per al sòcol d'entrada (en KB) és necessària.", + "so-rcv-buf-range": "La mida de la memòria intermèdia per al sòcol d'entrada (en KB) hauria d'estar en un interval d'1 a 65535.", + "so-snd-buf": "Mida de la memòria intermèdia per al sòcol de sortida (en KB)", + "so-snd-buf-required": "Cal la mida de la memòria intermèdia per al sòcol de sortida (en KB).", + "so-snd-buf-range": "La mida de la memòria intermèdia per al sòcol de sortida (en KB) hauria d'estar en un interval d'1 a 65535.", + "charset-name": "Nom del conjunt de caràcters", + "charset-name-required": "Cal nom del conjunt de caràcters.", + "message-separator": "Separador de missatges", + "message-separator-required": "Cal separador de missatges.", + "character-sequence": "Seqüència de caràcters", + "character-sequence-required": "Cal seqüència de caràcters.", + "max-frame-length": "Longitud màxima del fotograma (en bytes)", + "max-frame-length-required": "Cal longitud màxima del fotograma (en bytes).", + "max-frame-length-range": "La longitud màxima del fotograma (en bytes) hauria d'estar en un interval d'1 a 65535.", + "handler-type": "Tipus de comerciant", + "message-size": "Mida del missatge", + "message-size-required": "La mida del missatge és necessària.", + "type-apache-pulsar": "Apache Pulsar", + "service-url": "URL del servei", + "service-url-required": "Cal URL del servei.", + "subscription-name": "Nom de la subscripció", + "subscription-name-required": "Cal nom de la subscripció.", + "max-num-messages": "Nombre màxim de missatges", + "max-num-messages-required": "Cal nombre màxim de missatges.", + "max-num-bytes": "Nombre màxim de bytes", + "max-num-bytes-required": "Cal nombre màxim de bytes.", + "timeout-in-ms": "Temps d'espera en mil·lisegons", + "timeout-in-ms-required": "Temps d'espera en mil·lisegons.", + "user-id": "ID d'usuari", + "user-id-required": "Cal ID d'usuari.", + "token": "Token", + "token-required": "Cal Token.", + "project-id": "ID del projecte", + "project-id-required": "Cal ID del projecte.", + "subscription-id": "Identificador de subscripció", + "subscription-id-required": "Cal identificador de subscripció.", + "service-account-key": "Fitxer de claus del compte de servei", + "service-account-key-required": "Cal fitxer de claus del compte de servei.", + "tcp": { + "system-line-separator": "Separador de línies del sistema", + "nul-delimiter": "Delimitador nul", + "byte-order-little-endian": "Petit Endian", + "byte-order-big-endian": "Big Endian" + }, + "cache-size": "Mida de la memòria cau", + "cache-time-to-live": "Temps de la memòria cau per viure en minuts", + "min-cache-size": "La mida de la memòria cau no pot ser inferior a 0", + "min-cache-time-to-live": "El temps de vida de la memòria cau no pot ser inferior a 0", + "max-cache-time-to-live": "El temps de la memòria cau en directe no és vàlid, seleccioneu entre 0 i 525600", + "coap-security-mode": "Mode de seguretat", + "coap-security-mode-required": "Cal el mode de seguretat CoAP", + "coap-security-mode-no-secure": "NO SEGUR", + "coap-security-mode-dtls": "DTLS", + "coap-security-mode-mixed": "MIXTES", + "coap-endpoint": "URL del punt final CoAP", + "coap-endpoint-url-copied-message": "L'URL del punt final CoAP s'ha copiat al porta-retalls", + "copy-coap-endpoint-url": "Copia l'URL del punt final CoAP", + "copy-coap-dtls-endpoint-url": "Copia l'URL del punt final de CoAP DTLS", + "coap-dtls-base-url": "URL base DTLS", + "coap-dtls-base-url-required": "Cal URL base DTLS", + "coap-dtls-endpoint": "URL del punt final de CoAP DTLS", + "coap-dtls-endpoint-url-copied-message": "L'URL del punt final de CoAP DTLS s'ha copiat al porta-retalls", + "type-ffb": "FFB" + }, + "item": { + "selected": "Seleccionat" + }, + "js-func": { + "no-return-error": "La funció ha de retornar un valor!", + "return-type-mismatch": "La funció ha de retornar un valor de tipus: '{{type}}'!", + "tidy": "Endreçat", + "mini": "Mini" + }, + "key-val": { + "key": "Clau", + "value": "Valor", + "remove-entry": "Esborrar entrada", + "add-entry": "Afegir entrada", + "no-data": "Sense dades" + }, + "layout": { + "layout": "Disseny", + "manage": "Administrar Dissenys", + "settings": "Configuració de disseny", + "color": "Color", + "main": "Principal", + "right": "Dret", + "select": "Seleccionar Disseny de destí" + }, + "legend": { + "direction": "Direcció de la llegenda", + "position": "Posició de la llegenda", + "sort-legend": "Ordenar claus en llegenda", + "show-max": "Mostrar valor màxim", + "show-min": "Mostrar valor mínim", + "show-avg": "Mostrar valor mitjà", + "show-total": "Mostrar valor total", + "settings": "Configuració de la llegenda", + "min": "mínim", + "max": "màxim", + "avg": "mitjana", + "total": "total", + "comparison-time-ago": { + "previousInterval": "(interval anterior)", + "customInterval": "(interval personalitzat)", + "days": "(Fa un dia)", + "weeks": "(Fa una setmana)", + "months": "(Fa un mes)", + "years": "(Fa un any)" + } + }, + "login": { + "login": "Entrar", + "request-password-reset": "Sol·licitar restablir contrasenya", + "reset-password": "Restablir contrasenya", + "create-password": "Crear contrasenya", + "passwords-mismatch-error": "¡Les contraseñas introduïdes han de ser iguals!", + "password-again": "Repetiu la contrasenya de nou", + "sign-in": "Per favor, inicieu sessió", + "username": "Nom d'usuari (correu electrònic)", + "remember-me": "Recordar-me", + "forgot-password": "Ha oblidat la contrasenya?", + "password-reset": "Restablir contrasenya", + "expired-password-reset-message": "Les teves credencials han expirat! Si us plau, crea una nova contrasenya.", + "new-password": "Nova contrasenya", + "new-password-again": "Repetiu la nova contrasenya", + "password-link-sent-message": "S'ha enviat el enllaç de restabliment de contrasenya amb èxit!", + "email": "Correu electrònic", + "no-account": "No té un compte?", + "create-account": "Crear un compte", + "login-with": "Iniciar sessió amb {{name}}", + "or": "o", + "error": "Error d'inici de sessió", + "verify-your-identity": "Verificar identitat", + "select-way-to-verify": "Seleccioneu el mode de verificació", + "resend-code": "Reenviar codi", + "resend-code-wait": "Reenviar codi a { time, plural, 1 {1 segundo} other {# segundos} }", + "try-another-way": "Altres modes de verificació", + "totp-auth-description": "Si us plau, introduïu el codi de seguretat de la vostra aplicació d'autenticació.", + "totp-auth-placeholder": "Codi", + "sms-auth-description": "S'ha enviat un codi de verificació al vostre número: {{contact}} proporcionat.", + "sms-auth-placeholder": "Codi SMS", + "email-auth-description": "S'ha enviat un codi de verificació del correu electrònic {{contact}} proporcionat.", + "email-auth-placeholder": "Codi correu electrònic", + "backup-code-auth-description": "Por favor, introduce el código de backup.", + "backup-code-auth-placeholder": "Codi de Backup" + }, + "signup": { + "firstname": "Nom", + "lastname": "Cognom", + "email": "Correu electrònic", + "signup": "Registra't", + "create-password": "Crea una contrassenya", + "repeat-password": "Repetiu la vostra contrasenya", + "have-account": "Ja tens un compte?", + "signin": "Inicia sessió", + "no-captcha-message": "Heu de confirmar que no sou un robot", + "password-length-message": "La vostra contrasenya ha de tenir almenys 6 caràcters", + "email-verification": "Correu electrònic verificació", + "email-verification-message": "S'ha enviat un correu electrònic amb les dades de verificació a l'adreça electrònica especificada.
              Seguiu les instruccions proporcionades al correu electrònic per completar el procediment d'inscripció.
              Nota: si fa temps que no consulteu el correu electrònic, si us plau comproveu la vostra carpeta 'spam' o proveu de tornar a enviar el correu electrònic fent clic al botó 'Torna a enviar'.", + "account-activation-title": "Activació del compte", + "account-activated": "El compte s'ha activat correctament!", + "account-activated-text": "Enhorabona!
              El vostre compte s'ha activat.", + "resend": "Reenviar", + "inactive-user-exists-title": "L'usuari inactiu ja existeix", + "inactive-user-exists-text": "Ja hi ha un usuari registrat amb una adreça electrònica no verificada.
              Feu clic al botó 'Torna a enviar' si voleu tornar a enviar el correu electrònic de verificació..", + "activating-account": "S'està activant el compte...", + "activating-account-text": "El teu compte s'està activant. Si us plau, espereu...", + "accept-privacy-policy": "Acceptar la política de privadesa", + "accept": "Acceptar", + "privacy-policy": "Política de privacitat", + "accept-privacy-policy-message": "Heu d'acceptar la nostra Política de privadesa", + "recaptcha-title": "reCAPTCHA", + "terms-of-use": "Condicions d'ús", + "accept-terms-of-use-message": "Heu d'acceptar les nostres Condicions d'ús" + }, + "ota-update": { + "add": "Afegeix el paquet", + "assign-firmware": "Firmware assignat", + "assign-firmware-required": "Cal firmware assignat", + "assign-software": "Programari assignat", + "assign-software-required": "Cal programari assignat", + "auto-generate-checksum": "Suma de comprovació generada automàticament", + "cant-applied-group-all": "No es pot sol·licitar per al grup Tots", + "checksum": "Suma de control", + "checksum-hint": "Si la suma de comprovació està buida, es generarà automàticament", + "checksum-algorithm": "Algorisme de suma de control", + "checksum-copied-message": "La suma de comprovació del paquet s'ha copiat al porta-retalls", + "change-firmware": "El canvi del firmware pot provocar l'actualització { count, plural, 1 {1 device} other {# devices} }.", + "change-software": "El canvi del programari pot provocar l'actualització { count, plural, 1 {1 device} other {# devices} }.", + "chose-compatible-device-profile": "El paquet penjat només estarà disponible per als dispositius amb el perfil escollit.", + "chose-firmware-distributed-device": "Trieu el firmware que es distribuirà als dispositius", + "chose-software-distributed-device": "Trieu el programari que es distribuirà als dispositius", + "content-type": "Tipus de contingut", + "copy-checksum": "Copia la suma de verificació", + "copy-direct-url": "Copia l'URL directe", + "copyId": "Copia l'identificador del paquet", + "copied": "Copiat!", + "delete": "Esborra el paquet", + "delete-ota-update-text": "Aneu amb compte, després de la confirmació, l'actualització OTA serà irrecuperable.", + "delete-ota-update-title": "Confirmes que vols suprimir l'actualització de l'OTA '{{title}}'?", + "delete-ota-updates-text": "Aneu amb compte, després de la confirmació, totes les actualitzacions OTA seleccionades s'eliminaran.", + "delete-ota-updates-title": "Esteu segur que voleu suprimir { count, plural, 1 {1 OTA update} other {# OTA updates} }?", + "description": "Descripció", + "direct-url": "URL directe", + "direct-url-copied-message": "L'URL directe del paquet s'ha copiat al porta-retalls", + "direct-url-required": "Cal un URL directe", + "download": "Descarrega el paquet", + "drop-file": "Deixeu anar un fitxer de paquet o feu clic per seleccionar un fitxer per carregar.", + "file-name": "Nom de l'arxiu", + "file-size": "Mida de l'arxiu", + "file-size-bytes": "Mida del fitxer en bytes", + "idCopiedMessage": "L'identificador del paquet s'ha copiat al porta-retalls", + "no-firmware-matching": "No coincideix cap paquet d'actualització de firmware OTA compatible '{{entity}}' els van trobar.", + "no-firmware-text": "No s'ha subministrat cap paquet d'actualització de firmware OTA compatible.", + "no-packages-text": "No s'han trobat paquets", + "no-software-matching": "No coincideix cap paquet d'actualització de programari OTA compatible '{{entity}}' els van trobar.", + "no-software-text": "No s'ha subministrat cap paquet d'actualització de programari OTA compatible.", + "ota-update": "Actualització OTA", + "ota-update-details": "Detalls actualització OTA", + "ota-updates": "Actualitzacions de l'OTA", + "package-type": "Tipus de paquet", + "packages-repository": "Repositori de paquets", + "search": "Cerca paquets", + "selected-package": "{ count, plural, 1 {1 package} other {# packages} } seleccionat", + "title": "Títol", + "title-required": "Cal títol.", + "title-max-length": "El títol ha de ser inferior a 256", + "types": { + "firmware": "Firmware", + "software": "Programari" + }, + "upload-binary-file": "Carregueu un fitxer binari", + "use-external-url": "Utilitzeu un URL extern", + "version": "Versió", + "version-required": "Cal versió.", + "version-tag": "Etiqueta de versió", + "version-tag-hint": "L'etiqueta personalitzada hauria de coincidir amb la versió del paquet informada pel vostre dispositiu.", + "version-max-length": "La versió hauria de ser inferior a 256", + "warning-after-save-no-edit": "Un cop carregat el paquet, no podreu modificar el títol, la versió, el perfil del dispositiu i el tipus de paquet." + }, + "position": { + "top": "Superior", + "bottom": "Inferior", + "left": "Esquerra", + "right": "Dreta" + }, + "profile": { + "profile": "Perfil", + "last-login-time": "Darrer accés", + "change-password": "Canviar contrasenya", + "current-password": "Contrasenya actual", + "copy-jwt-token": "Copia el testimoni JWT", + "jwt-token": "Tóken JWT", + "valid-till": "Vàlid per a {{expirationData}}", + "tokenCopiedSuccessMessage": "El testimoni JWT s'ha copiat al porta-retalls", + "tokenCopiedWarnMessage": "El testimoni JWT ha caducat! Si us plau, actualitzeu la pàgina." + }, + "security": { + "security": "Seguretat", + "2fa": { + "2fa": "Autenticació de doble factor (2FA)", + "2fa-description": "L'autenticació de dos factors protegeix el vostre compte de l'accés no autoritzat. Tot el que heu de fer és introduir un codi de seguretat en iniciar sessió.", + "authenticate-with": "Pots autenticarte amb:", + "disable-2fa-provider-text": "Desactivar {{name}} farà el teu compte menys segur", + "disable-2fa-provider-title": "Estàs segur de desactivar {{name}}?", + "get-new-code": "Obtenir un nou codi", + "main-2fa-method": "Usar com a mètode d'autenticació de doble factor principal", + "dialog": { + "activation-step-description-email": "La propera vegada que facis log-in, caldrà introduir el codi de seguretat que s'enviarà a la teva adreça de correu electrònic.", + "activation-step-description-sms": "La propera vegada que feu log-in, caldrà introduir el codi de seguretat que s'enviarà al vostre número de telèfon.", + "activation-step-description-totp": "La propera vegada que facis log-in, caldrà introduir el codi de seguretat de doble factor.", + "activation-step-label": "Activació", + "backup-code-description": "Imprimeix els codis i guarda'ls en un lloc segur, es necessitaran per fer login al teu compte. Pots utilitzar cada codi de còpia de seguretat només una vegada.", + "backup-code-warn": "Quan surtis d'aquesta pàgina, aquests codis no es tornaran a mostrar. Desa'ls en un lloc segur usant les opcions a continuació.", + "download-txt": "Descarregar (txt)", + "email-step-description": "Introdueix el teu correu electrònic per utilitzar com a autenticador.", + "email-step-label": "Correu electrònic", + "enable-email-title": "Activar autenticador per correu electrònic", + "enable-sms-title": "Activar autenticador per SMS", + "enable-totp-title": "Activar autenticador per app", + "enter-verification-code": "Entra el codi de 6-dígits", + "get-backup-code-title": "Obtenir còpia de seguretat", + "next": "Següent", + "scan-qr-code": "Escaneja el codi QR amb la teva aplicació d'autenticació", + "send-code": "Enviar codi", + "sms-step-description": "Introdueix el teu número de telèfon per utilitzar com a autenticador.", + "sms-step-label": "Número de telèfon", + "success": "Èxit!", + "totp-step-description-install": "Podeu instal·lar l'aplicació Google Authenticator, Authy, o Duo.", + "totp-step-description-open": "Obre l'aplicació d'autenticació al telèfon mòbil.", + "totp-step-label": "Obtenir app", + "verification-code": "Codi de 6-dígits", + "verification-code-invalid": "Formát de codi invàlid", + "verification-code-incorrect": "El codi de verificació és incorrecte", + "verification-code-many-request": "Massa sol·licituds, revisa el codi de verificació", + "verification-step-description": "Introdueix el codi de 6-dígits que acabem d'enviar a {{address}}", + "verification-step-label": "Verificació" + }, + "provider": { + "email": "Correu electrònic", + "email-description": "Usar un codi de seguretat enviat al teu email per autenticar-te.", + "email-hint": "Els codis d'autenticació s'han enviat per correu electrònic a {{ info }}", + "sms": "SMS", + "sms-description": "Usar el teu telèfon per autenticar-te. Enviarem un codi de seguretat via SMS.", + "sms-hint": "Els codis d'autenticació s'han enviat per missatge de text SMS a {{ info }}", + "totp": "App d'autenticació", + "totp-description": "Utilitzeu aplicacions com Google Authenticator, Authy o Duo al vostre telèfon per autenticar-vos. Es generarà un codi de seguretat per iniciar sessió.", + "totp-hint": "L'aplicació d'autenticació s'ha configurat al vostre compte", + "backup_code": "Codi Backup", + "backup-code-description": "Aquests codis de seguretat imprimibles són d'un sol ús, et permeten identificar quan no tinguis el telèfon a mà, útil quan es viatja.", + "backup-code-hint": "{{ info }} codis d'un sol ús actius en aquest moment" + } + }, + "password-requirement": { + "at-least": "Al menys:", + "character": "{ count, plural, 1 {1 caracter} other {# caracteres} }", + "digit": "{ count, plural, 1 {1 dígito} other {# dígitos} }", + "incorrect-password-try-again": "Contrasenya incorrecta. Prova una altra vegada", + "lowercase-letter": "{ count, plural, 1 {1 minúscula} other {# mínusculas} }", + "new-passwords-not-match": "Les contrasenyes no coincideixen", + "password-should-not-contain-spaces": "La contrasenya no pot contenir espais", + "password-not-meet-requirements": "La contrasenya no reuneix els requisits necessaris", + "password-requirements": "Requisits de contrasenya", + "password-should-difference": "La nova contrasenya ha de ser diferent de l'actual", + "special-character": "{ count, plural, 1 {1 caracter especial} other {# caracteres especiales} }", + "uppercase-letter": "{ count, plural, 1 {1 mayúscula} other {# mayúsculas} }" + } + }, + "relation": { + "relations": "Relacions", + "direction": "Direcció", + "search-direction": { + "FROM": "Des de", + "TO": "Cap a" + }, + "direction-type": { + "FROM": "des de", + "TO": "cap a" + }, + "from-relations": "Relacions salientes (outbound)", + "to-relations": "Relacions entrantes (inbound)", + "selected-relations": "{ count, plural, 1 {1 relación} other {# relaciones} } seleccionades", + "type": "Tipus", + "to-entity-type": "Cap a tipus d'entitat", + "to-entity-name": "Cap a nom d'entitat", + "from-entity-type": "Des de tipus d'entitat", + "from-entity-name": "Des de nom d'entitat", + "to-entity": "Cap a entitat", + "from-entity": "Des d'entitat", + "delete": "Esborrar relació", + "relation-type": "Tipus de relació", + "relation-type-required": "Cal tipus de relació.", + "relation-type-max-length": "El tipus de relació ha de ser inferior a 256", + "any-relation-type": "Qualsevol tipus", + "add": "Afegir relació", + "edit": "Editar relació", + "view": "Veure relació", + "delete-to-relation-title": "Vols eliminar la relació amb l'entitat '{{entityName}}'?", + "delete-to-relation-text": "Atenció, després de la confirmació l'entitat '{{entityName}}' no estarà relacionada amb l'entitat actual.", + "delete-to-relations-title": "Vols eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", + "delete-to-relations-text": "Atenció, després de la confirmació totes les relacions seleccionades s'eliminaran i les seves entitats corresponents no estaran relacionades amb l'entitat actual.", + "delete-from-relation-title": "Vols eliminar la relació amb l'entitat '{{entityName}}'?", + "delete-from-relation-text": "Atenció, després de la confirmació l'entitat actual no estarà relacionada amb l'entitat '{{entityName}}'.", + "delete-from-relations-title": "Vols eliminar { count, plural, 1 {1 relación} other {# relaciones} }?", + "delete-from-relations-text": "Atenció, després de la confirmació totes les relacions seleccionades s'eliminaran i les seves entitats corresponents no estaran relacionades amb les entitats corresponents.", + "remove-relation-filter": "Treure filtre de relació", + "add-relation-filter": "Afegir filtre de relació", + "any-relation": "Qualsevol relació", + "relation-filters": "Filtre de relació", + "additional-info": "Informació adicional (JSON)", + "invalid-additional-info": "Error al analitzar el fitxer JSON de informació adicional.", + "no-relations-text": "No s'han trobar relacions" + }, + "resource": { + "add": "Afegeix un recurs", + "copyId": "Copia l'identificador del recurs", + "delete": "Suprimeix el recurs", + "delete-resource-text": "Aneu amb compte, després de la confirmació el recurs es tornarà irrecuperable.", + "delete-resource-title": "Esteu segur que voleu suprimir el recurs '{{resourceTitle}}'?", + "delete-resources-action-title": "Suprimeix { count, plural, 1 {1 resource} other {# resources} }", + "delete-resources-text": "Tingueu en compte que els recursos seleccionats, encara que s'utilitzin en perfils de dispositius, se suprimiran.", + "delete-resources-title": "Esteu segur que voleu suprimir { count, plural, 1 {1 resource} other {# resources} }?", + "download": "Descarrega el recurs", + "drop-file": "Deixeu anar un fitxer de recursos o feu clic per seleccionar un fitxer per carregar.", + "drop-resource-file-or": "Arrossegar i deixar anar un fitxer o", + "empty": "El recurs està buit", + "file-name": "Nom de l'arxiu", + "idCopiedMessage": "L'identificador del recurs s'ha copiat al porta-retalls", + "no-resource-matching": "No hi ha coincidència de recursos '{{widgetsBundle}}' els van trobar.", + "no-resource-text": "No s'han trobat recursos", + "open-widgets-bundle": "Obre el paquet de ginys", + "resource": "Recurs", + "resource-library-details": "Detalls de recurs", + "resource-type": "Tipus de recurs", + "resources-library": "Biblioteca de recursos", + "search": "Cerca recursos", + "selected-resources": "{ count, plural, 1 {1 resource} other {# resources} } seleccionat", + "system": "Sistema", + "title": "Títol", + "title-required": "Cal títol.", + "title-max-length": "El títol ha de ser inferior a 256" + }, + "rulechain": { + "rulechain": "Cadena de Regla", + "rulechains": "Cadenes de Regles", + "root": "Arrel", + "delete": "Esborrar cadena de regles", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "description": "Descripció", + "add": "Afegir Cadena", + "set-root": "Fer la cadena de regles arrel", + "set-root-rulechain-title": "Voleu fer la cadena de regles '{{ruleChainName}}' de tipus arrel?", + "set-root-rulechain-text": "Després de la confirmació, la cadena de regles es tornarà arrel i manejarà tots els missatges de transport entrants.", + "delete-rulechain-title": "Vols eliminar la cadena de regles '{{ruleChainName}}'?", + "delete-rulechain-text": "Atenció, després de la confirmació la cadena de regles i totes les dades seran irrecuperables.", + "delete-rulechains-title": "Està segur que vols eliminar { count, plural, 1 {1 cadena de regles} other {# cadenes de regles} }?", + "delete-rulechains-action-title": "Eliminar { count, plural, 1 {1 cadena de regles} other {# cadenes de regles} }", + "delete-rulechains-text": "Atenció, després de la confirmació totes les cadena de regles seleccionades i totes les dades seran irrecuperables.", + "add-rulechain-text": "Afegir nova cadena de regles", + "no-rulechains-text": "Cadenes de regles no trobades", + "rulechain-details": "Detalls de la cadena de regles", + "details": "Detalls", + "events": "Esdeveniments", + "system": "Sistema", + "import": "Importar cadena de regles", + "export": "Exportar cadena de regles", + "export-failed-error": "No es pot exportar la cadena de regles: {{error}}", + "create-new-rulechain": "Crear nova cadena de regles", + "rulechain-file": "Fitxer de cadena de regles", + "invalid-rulechain-file-error": "No es pot importar la cadena de regles: Estructura de dades de la cadena de regles invàlida.", + "copyId": "Copiar ID de la cadena de regles", + "idCopiedMessage": "ID de la cadena de regles ha estat copiada al porta-retalls", + "select-rulechain": "Seleccionar cadena de regles", + "no-rulechains-matching": "No s'han trobar cadenes de regles que coincideixin amb '{{entity}}' .", + "rulechain-required": "Cal cadena de regles", + "management": "Gestió de regles", + "debug-mode": "Manera de Depuració", + "search": "Buscar cadenes de regles", + "selected-rulechains": "{ count, plural, 1 {1 cadena de regles} other {# cadenes de regles} } seleccionades", + "open-rulechain": "Obrir cadena de regles", + "edge-template-root": "Arrel de plantilla", + "assign-to-edge": "Assignar a Edge", + "edge-rulechain": "Cadena de regla de vora", + "unassign-rulechain-from-edge-text": "Després de la confirmació, la cadena de regles quedará sense assignar i la vora no podrà accedir a ella", + "unassign-rulechains-from-edge-title": "Esteu segur que voleu anul·lar l'assignació { count, plural, 1 {1 rulechain} other {# rulechains} }?", + "unassign-rulechains-from-edge-text": "Després de la confirmació, totes les cadenes de regles seleccionades quedaran sense assignar i la vora no podrà accedir a ellas", + "assign-rulechain-to-edge-title": "Assignar cadena (s) de regles a vora", + "assign-rulechain-to-edge-text": "Selecciona les cadenes de regles per assignar a la vora", + "set-edge-template-root-rulechain": "Fer arrel de plantilla de vora de cadena de regles", + "set-edge-tscheduler-eventemplate-root-rulechain": "Feu una cadena de regles com a arrel de plantilla de vora", + "set-edge-template-root-rulechain-title": "Està segur de que desitja que la cadena de regles '{{ruleChainName}}' sigui l'arrel de la plantilla de vora?", + "set-edge-template-root-rulechain-text": "Després de la confirmació, la cadena de regles es convertirá en l'arrel de la plantilla de vora i serà la cadena de regles arrel per les vores recent creats.", + "invalid-rulechain-type-error": "No es pot importar la cadena de regles: Tipus de cadena de regles no vàlid. El tipus esperat és {{expectedRuleChainType}}", + "set-auto-assign-to-edge": "Assignar cadena de regles a les vores en la creació", + "set-auto-assign-to-edge-title": "Està segur de que desitja assignar automàticament la cadena de regles de vora '{{ruleChainName}}' a les vores en la creació?", + "set-auto-assign-to-edge-text": "Després de la confirmació, la cadena de regles de vora s'assignarà automàticament a les vores en la creació.", + "unset-auto-assign-to-edge": "Desmarcar assignar cadena de regles a les vores en la creació", + "unset-auto-assign-to-edge-title": "Està segur de que desitja anul·lar l'assignació de la cadena de regles de vora '{{ruleChainName}}' a les vores en la creació?", + "unset-auto-assign-to-edge-text": "Després de la confirmació, la cadena de regles de vora ja no s'assignarà automàticament a les vores en la creació.", + "unassign-rulechain-title": "Està segur de que desitja desassignar la cadena de regles '{{ruleChainName}}'?", + "unassign-rulechains": "Anul·lar assignació de cadenes de regles", + "assign-rulechains": "Assignar cadenes de regles", + "delete-rulechains": "Eliminar cadenes de regles", + "unassign-rulechain": "Anul·lar assignació de cadena de regles", + "unassign-rulechains-from-edge-action-title": "Anul·lar assignació {count, plural, 1 {1 cadena de regles} other {# cadenes de regles} } des vores", + "assign-new-rulechain": "Assignar nova cadena de regles" + }, + "rulenode": { + "details": "Detalls", + "events": "Esdeveniments", + "search": "Buscar nodes", + "open-node-library": "Obrir llibreria de nodes", + "add": "Afegir node de regles", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "type": "Tipus", + "description": "Descripció", + "delete": "Eliminar node de regles", + "select-all-objects": "Seleccionar tots els nodes i conexions", + "deselect-all-objects": "Desfer selecció de tots els nodes i conexions", + "delete-selected-objects": "Eliminar nodes i conexions seleccionats", + "delete-selected": "Eliminar seleccionat", + "create-nested-rulechain": "Crea una cadena de regles imbricades", + "select-all": "Seleccionar tots", + "copy-selected": "Copiar seleccionat", + "deselect-all": "Desfer selecció de tots", + "rulenode-details": "Detalls del node de regles", + "debug-mode": "Manera Depuració", + "configuration": "Configuració", + "link": "Enllaç", + "link-details": "Detalls del enllaç del node de regles", + "add-link": "Afegir enllaç", + "link-label": "Etiqueta del enllaç", + "link-label-required": "Cal l'etiqueta del enllaç.", + "custom-link-label": "Etiqueta del enllaç personalitzada", + "custom-link-label-required": "Cal l'etiqueta del enllaç personalitzat.", + "link-labels": "Etiquetes del enllaç", + "link-labels-required": "Cal les etiquetes del enllaç.", + "no-link-labels-found": "Etiquetes d'enllaços no trobades", + "no-link-label-matching": "'{{label}}' no trobada.", + "create-new-link-label": "Crear una nova!", + "type-filter": "Filtre", + "type-filter-details": "Filtrar missatges entrantes amb les condicions configurades", + "type-enrichment": "Enriquiment", + "type-enrichment-details": "Afegir informació adicional en missatges de metadades", + "type-transformation": "Transformació", + "type-transformation-details": "Canviar carga útil del Missatge i Metadades", + "type-action": "Acció", + "type-action-details": "Ejecutar acció especial", + "type-analytics": "Analítica", + "type-analytics-details": "Ejecutar análisis de dades transmesos o persistents", + "type-external": "Extern", + "type-external-details": "Interactuar amb sistemas externs", + "type-rule-chain": "Cadena de regles", + "type-rule-chain-details": "Reenviar els missatges entrantes a la cadena de regles especificada", + "type-flow": "Flow", + "type-flow-details": "Organitza el flow de missatges", + "type-input": "Entrada", + "type-input-details": "Entrada lògica de la Cadena de Regles, reenviar els missatges entrants al següent node de regla relacionat.", + "type-unknown": "Desconegut", + "type-unknown-details": "Regla de node no resolta", + "directive-is-not-loaded": "La directiva de configuració definida '{{directiveName}}' no está disponible.", + "ui-resources-load-error": "Error al carregar els recursos de configuració UI.", + "invalid-target-rulechain": "No es pot resoldre la cadena de regles objetiu!", + "test-script-function": "Prova Script de funció", + "message": "Missatge", + "message-type": "Tipus de missatge", + "select-message-type": "Seleccionar tipus de missatge", + "message-type-required": "Cal e tipus de missatge", + "metadata": "Metadades", + "metadata-required": "Les entrades de metadades no poden estar buides.", + "output": "Sortida", + "test": "Test", + "help": "Ajuda", + "reset-debug-mode": "Restablir el mode de depuració a tots els nodes" + }, + "role": { + "role": "Rol", + "roles": "Rols", + "management": "Gestió de rols", + "view-roles": "Veure rols", + "no-roles-matching": "No coincideixen els rols '{{entity}}' els van trobar.", + "role-list": "Llista de rols", + "add": "Afegeix un rol", + "view": "Mostra el rol", + "search": "Cerca rols", + "selected-roles": "{ count, plural, 1 {1 role} other {# roles} } seleccionat", + "no-roles-text": "No s'han trobat rols", + "role-details": "Detalls del rol", + "add-role-text": "Afegeix un paper nou", + "delete": "Suprimeix la funció", + "delete-roles": "Suprimir rols", + "delete-role-title": "Esteu segur que voleu suprimir la funció '{{roleName}}'?", + "delete-role-text": "Aneu amb compte, després de la confirmació, la funció i totes les dades relacionades es tornaran irrecuperables.", + "delete-roles-title": "Esteu segur que voleu suprimir { count, plural, 1 {1 role} other {# roles} }?", + "delete-roles-action-title": "Suprimeix { count, plural, 1 {1 role} other {# roles} }", + "delete-roles-text": "Aneu amb compte, després de la confirmació, tots els rols seleccionats s'eliminaran i totes les dades relacionades seran irrecuperables.", + "role-type": "Tipus de rol", + "role-type-required": "Cal tipus de rol.", + "select-role-type": "Seleccioneu el tipus de rol", + "enter-role-type": "Introduïu el tipus de rol", + "any-role": "Qualsevol paper", + "no-role-types-matching": "No coincideix cap tipus de rol '{{entitySubtype}}' els van trobar.", + "role-type-list-empty": "No s'ha seleccionat cap tipus de rol.", + "role-types": "Tipus de rols", + "created-time": "Temps creat", + "name": "Nom", + "name-required": "Cal el nom.", + "name-max-length": "El nom ha de ser inferior a 256", + "description": "Descripció", + "events": "Esdeveniments", + "details": "Detalls", + "copyId": "Copia l'identificador del rol", + "idCopiedMessage": "L'identificador de funció s'ha copiat al porta-retalls", + "permissions": "Permisos", + "role-required": " Cal rol", + "roles-required": "Cal rols", + "display-type": { + "GENERIC": "Genèric", + "GROUP": "Grup" + } + }, + "group-permission": { + "user-group-roles": "Rols del grup d'usuaris", + "entity-group-permissions": "Permisos del grup d'entitats", + "role-type": "Tipus de rol", + "role-name": "Nom del rol", + "group-type": "Tipus de grup", + "group-name": "Nom del grup", + "group-owner": "Propietari del grup", + "user-group-name": "Nom del grup d'usuaris", + "user-group-owner": "Propietari del grup d'usuaris", + "edit": "Edita els permisos", + "delete": "Suprimeix els permisos", + "selected-group-permissions": "{ count, plural, 1 {1 group permission} other {# group permissions} } seleccionat", + "delete-group-permission-title": "Esteu segur que voleu suprimir el permís del grup '{{roleName}}'?", + "delete-group-permission-text": "Aneu amb compte, després de la confirmació, el permís del grup i totes les dades relacionades es tornaran irrecuperables.", + "delete-group-permission": "Suprimeix el permís de grup", + "delete-group-permissions-title": "Esteu segur que voleu suprimir { count, plural, 1 {1 group permission} other {# group permission} }?", + "delete-group-permissions-text": "Aneu amb compte, després de la confirmació s'eliminaran tots els permisos de grup seleccionats i els usuaris corresponents perdran l'accés als recursos especificats.", + "delete-group-permissions": "Suprimeix els permisos del grup", + "add-group-permission": "Afegeix permís de grup", + "edit-group-permission": "Edita el permís del grup", + "entity-group": "Grup d'entitats", + "user-group": "Grup d'usuaris", + "no-owners-matching": "No hi ha cap propietari que coincideixi '{{owner}}' els van trobar.", + "target-owner-required": "El propietari del grup d'entitats és obligatori.", + "target-user-group-owner-required": "El propietari del grup d'usuaris és obligatori.", + "no-group-permissions-text": "No s'han trobat permisos de grup" + }, + "permission": { + "permissions-required": "S'ha d'especificar almenys una entrada de permís.", + "remove-permission": "Elimina l'entrada de permís", + "add-permission": "Afegeix una entrada de permís", + "other": "Altres", + "resource": { + "resource": "Recurs", + "select-resource": "Seleccioneu el recurs", + "resource-required": "Cal un recurs", + "no-resources-matching": "No hi ha recursos coincidents '{{resource}}' els van trobar.", + "display-type": { + "ALL": "Tots", + "PROFILE": "Perfil", + "ADMIN_SETTINGS": "Configuració d'administrador", + "ALARM": "Alarma", + "DEVICE": "Dispositiu", + "DEVICE_PROFILE": "Perfil del dispositiu", + "ASSET": "Actiu", + "CUSTOMER": "Client", + "DASHBOARD": "Panell", + "ENTITY_VIEW": "Vista d'entitat", + "EDGE": "Edge", + "TENANT": "Llogater", + "TENANT_PROFILE": "Perfil del llogater", + "RULE_CHAIN": "Cadena de regles", + "USER": "Usuari", + "WIDGETS_BUNDLE": "Paquet de widgets", + "WIDGET_TYPE": "Tipus de widget", + "CONVERTER": "Convertidor", + "INTEGRATION": "Integració", + "SCHEDULER_EVENT": "Agenda d'esdeveniments", + "BLOB_ENTITY": "Entitat Blob", + "CUSTOMER_GROUP": "Grup de clients", + "DEVICE_GROUP": "Grup de dispositius", + "ASSET_GROUP": "Grup d'actius", + "USER_GROUP": "Grup d'usuaris", + "ENTITY_VIEW_GROUP": "Grup de visualització d'entitats", + "DASHBOARD_GROUP": "Grup de Dashboard", + "ROLE": "Rol", + "GROUP_PERMISSION": "Permís de grup", + "WHITE_LABELING": "Etiquetat blanc", + "AUDIT_LOG": "Registre d'auditoria", + "API_USAGE_STATE": "Estat d'ús de l'API", + "TB_RESOURCE": "Recurs", + "EDGE_GROUP": "Grup Edge", + "OTA_PACKAGE": "Paquet Ota" + } + }, + "operation": { + "operation": "Operació", + "operations": "Operacions", + "operations-required": "S'ha d'especificar almenys una operació.", + "enter-operation": "Entra en funcionament", + "no-operations-matching": "No coincideix cap operació '{{operation}}' els van trobar.", + "display-type": { + "ALL": "Tots", + "CREATE": "Crear", + "READ": "Llegeix", + "WRITE": "Escriu", + "DELETE": "Suprimeix", + "ASSIGN_TO_CUSTOMER": "Assign to Customer", + "UNASSIGN_FROM_CUSTOMER": "Cancel·la l'assignació del client", + "RPC_CALL": "Trucada RPC", + "READ_CREDENTIALS": "Llegeix credencials", + "WRITE_CREDENTIALS": "Escriu credencials", + "READ_ATTRIBUTES": "Llegeix els atributs", + "WRITE_ATTRIBUTES": "Escriu atributs", + "READ_TELEMETRY": "Llegeix Telemetria", + "WRITE_TELEMETRY": "Escriu telemetria", + "CLAIM_DEVICES": "Dispositius de reclamació", + "IMPERSONATE": "Suplantar la identitat", + "CHANGE_OWNER": "Canvia de propietari", + "ADD_TO_GROUP": "Afegeix al grup", + "REMOVE_FROM_GROUP": "Elimina del grup", + "SHARE_GROUP": "Comparteix el grup", + "ASSIGN_TO_TENANT": "Assigna a l'arrendatari" + } + } + }, + "scheduler": { + "scheduler": "Planificador", + "scheduler-event": "Planificador d'esdeveniment", + "select-scheduler-event": "Seleccionar planificador d'esdeveniment", + "no-scheduler-events-matching": "Planificadors d'esdeveniments que coincideixin amb '{{entity}}' no van ser trobats.", + "scheduler-event-required": "Cal planificador d'esdeveniment", + "management": "Gestió del pla", + "scheduler-events": "Planificador d'esdeveniment", + "add-scheduler-event": "Afegir planificador d'esdeveniment", + "search-scheduler-events": "Buscar planificador d'esdeveniment", + "created-time": "Temps de creació", + "name": "Nom", + "name-required": "Cal nom", + "name-max-length": "El nom ha de ser inferior a 256.", + "type": "Tipus", + "created_customer": "Creat pel client", + "edit-scheduler-event": "Editar planificador d'esdeveniment", + "view-scheduler-event": "Mostra l'esdeveniment del programador", + "delete-scheduler-event": "Eliminar planificador d'esdeveniment", + "no-scheduler-events": "Planificador d'esdeveniment no trobat", + "selected-scheduler-events": "{ count, plural, 1 {1 planificador de esdeveniments} other {# planificadors de esdeveniments} } seleccionat", + "delete-scheduler-event-title": "Està segur que desitja eliminar el planificador d'esdeveniments '{{schedulerEventName}}'?", + "delete-scheduler-event-text": "Anar amb compte, després de la confirmació, el planificador d'esdeveniments i totes les dades relacionades és tornaran irrecuperables.", + "delete-scheduler-events-title": "Està segur que desitja eliminar { count, plural, 1 {1 planificador de esdeveniments} other {# planificadors de esdeveniments} }?", + "delete-scheduler-events-text": "Anar amb compte, després de la confirmació s'eliminaran totes els planificadors d'esdeveniments seleccionats i totes les dades relacionades és tornaran irrecuperables.", + "create": "Crear planificador d'esdeveniment", + "edit": "Editar planificador d'esdeveniment", + "view": "Mostra l'esdeveniment del programador", + "configuration": "Configuració", + "schedule": "Planificar", + "start-time": "Hora d'inici", + "repeat": "Repetició", + "repeats": "Repeticions", + "daily": "Diarament", + "weekly": "Setmanalment", + "monthly": "Mensualment", + "yearly": "Anual", + "timer": "Basat en temporitzador", + "repeats-required": "Repeticions són requerides.", + "repeat-on": "Repetir en", + "repeat-every": "Repeteix cada", + "ends-on": "Acabar en", + "sunday-label": "Dg", + "monday-label": "Dl", + "tuesday-label": "Dm", + "wednesday-label": "Dc", + "thursday-label": "Dj", + "friday-label": "Dv", + "saturday-label": "Ds", + "repeat-on-sunday": "Repetir el Diumenge", + "repeat-on-monday": "Repetir el Dilluns", + "repeat-on-tuesday": "Repetir el Dimarts", + "repeat-on-wednesday": "Repetir el Dimecres", + "repeat-on-thursday": "Repetir el Dijous", + "repeat-on-friday": "Repetir el Divendres", + "repeat-on-saturday": "Repetir el Dissabte", + "event-type": "Tipus d'esdeveniments", + "select-event-type": "Seleccionar tipus d'esdeveniment", + "event-type-required": "Tipus d'esdeveniment és requerit.", + "event-type-max-length": "El tipus d'esdeveniment ha de ser inferior a 256.", + "list-mode": "Vista de la llista", + "calendar-mode": "Vista del calendari", + "calendar-view-type": "Tipus de vista del calendari", + "month": "Mes", + "week": "Setmana", + "day": "Dia", + "agenda-week": "Agenda Setmanal", + "agenda-day": "Agenda Diaria", + "list-year": "Llista Anual", + "list-month": "Llista Mensual", + "list-week": "Llista Setmanal", + "list-day": "Llista Diaria", + "today": "Avui", + "navigate-before": "Navegar Abans de", + "navigate-next": "Navegar després de", + "starting-from": "Inician des de", + "until": "fins a", + "on": "encesa", + "sunday": "Diumenge", + "monday": "Dilluns", + "tuesday": "Dimarts", + "wednesday": "Dimecres", + "thursday": "Dijous", + "friday": "Divendres", + "saturday": "Dissabte", + "originator": "Creador", + "single-entity": "Entitat única", + "group-of-entities": "Grup d'entitats", + "entities-group-owner": "Propietari del grup d'entitats", + "single-device": "Dispositiu únic", + "group-of-devices": "Grup de dispositius", + "devices-group-owner": "Propietari del grup de dispositius", + "message-body": "Cos del missatge", + "target": "Objectiu", + "rpc-method": "Mètode", + "rpc-method-required": "Cal Mètode", + "rpc-method-white-space": "No és permet l'espai en blanc.", + "rpc-params": "Paràmetres", + "select-dashboard-state": "Seleccionar estat del panell", + "hours": "Hores", + "minutes": "Minuts", + "seconds": "Segons", + "time-interval-required": "Cal un interval de temps", + "time-unit-required": "Es requereix una unitat de temps", + "every-hour": "cada { count, plural, 1 {hour} other {# hours} }", + "every-minute": "cada { count, plural, 1 {minute} other {# minutes} }", + "every-second": "cada { count, plural, 1 {second} other {# seconds} }", + "invalid-time": "Hora no vàlida", + "assigned_customer": "Client assignat" + }, + "report": { + "report-config": "Configuració de l'informe", + "email-config": "Configuració del correu electrònic", + "dashboard-state-param": "Valor del parámetro d'estat del panell", + "base-url": "URL base", + "base-url-required": "Cal URL base.", + "use-dashboard-timewindow": "Utilitzar la finestra del temps del panell", + "timewindow": "Finestra del temps", + "name-pattern": "Report de patró de nom", + "name-pattern-required": "Cal el report de patró de nom.", + "type": "Tipus d'informe", + "use-current-user-credentials": "Utilizar credencials d'usuari actuals", + "customer-user-credentials": "Credencials d'usuari client", + "customer-user-credentials-required": "Cal credencials d'usuari client", + "generate-test-report": "Generar informe de proves", + "send-email": "Enviar correu electrònic", + "from": "Des de", + "from-required": "Cal des de.", + "to": "Per", + "to-required": "Cal per.", + "cc": "Amb copia", + "bcc": "Amb copia oculta", + "subject": "Assumpte", + "subject-required": "Cal assumpte.", + "body": "Cos", + "body-required": "Cal cos." + }, + "blob-entity": { + "blob-entity": "Entitat blob", + "select-blob-entity": "Seleccionar entitat blob", + "no-blob-entities-matching": "Entitats blob que coincideixin amb '{{entity}}' no han estat trobades.", + "blob-entity-required": "Cal entitat blob.", + "files": "Fitxers", + "search": "Buscar Fitxers", + "clear-search": "Esborrar cerca", + "no-blob-entities-prompt": "Fitxers no trobats", + "report": "Report", + "created-time": "Temps de creació", + "name": "Nom", + "type": "Tipus", + "created_customer": "Creat pel client", + "selected-blob-entities": "{ count, plural, 1 {1 file} other {# files} } seleccionat", + "download-blob-entity": "Descarregar arxiu", + "delete-blob-entity": "Eliminar arxiu", + "delete-blob-entity-title": "Està segur de que desitja eliminar l'arxiu '{{blobEntityName}}'?", + "delete-blob-entity-text": "Aneu amb compte, després de la confirmació, l'arxiu de dades es tornara irrecuperable.", + "delete-blob-entities-title": "Esteu segur que voleu suprimir { count, plural, 1 {1 file} other {# files} }?", + "delete-blob-entities-text": "Aneu amb compte, després de la confirmació, tots els fitxers seleccionats s'eliminaran i totes les dades relacionades es tornaran irrecuperables.", + "assigned_customer": "Client assignat" + }, + "timezone": { + "timezone": "Zona Horària", + "select-timezone": "Seleccionar zona horària", + "no-timezones-matching": "No hi ha zones horàries que coincideixin amb '{{timezone}}'.", + "timezone-required": "Cal zona horària.", + "browser-time": "Hora del navegador" + }, + "queue": { + "queue-name": "Cua", + "no-queues-matching": "No es van trobar cues que coincideixin amb '{{queue}}'.", + "select_name": "Seleccioneu el nom de la cua", + "name": "Nom Cua", + "name_required": "Cal especificar el nom de cua", + "name-unique": "El nom de cua ja existeix!", + "queue-required": "Cal cua!", + "topic-required": "Cal topic cua!", + "poll-interval-required": "Cal interval d'obtenció!", + "poll-interval-min-value": "L'interval no ha de ser inferior a 1", + "partitions-required": "Cal particions!", + "partitions-min-value": "El valor de partició no ha de ser inferior a 1", + "pack-processing-timeout-required": "Temps d'espera del processament", + "pack-processing-timeout-min-value": "El temps d'espera de processament no pot ser inferior a 1", + "batch-size-required": "Cal grandària del lot!", + "batch-size-min-value": "El valor de mida de lot no pot ser inferior a 1", + "retries-required": "Cal Reintents!", + "retries-min-value": "El valor dels reintents no pot ser negatiu", + "failure-percentage-required": "Cal percentatge de fallades!", + "failure-percentage-min-value": "Percentatge de fallades no pot ser inferior a 0", + "failure-percentage-max-value": "Percentatge de fallades no pot ser més gran de 100", + "pause-between-retries-required": "Cal pausa entre reintents!", + "pause-between-retries-min-value": "Pausa mínima entre reintents no pot ser inferior a 1", + "max-pause-between-retries-required": "Cal pausa màxima entre reintents!", + "max-pause-between-retries-min-value": "Pausa màxima entre reintents no pot ser inferior a 1", + "submit-strategy-type-required": "Cal estratègia d'enviament!", + "processing-strategy-type-required": "Cal estratègia de processament!", + "queues": "Cues", + "selected-queues": "{ count, plural, 1 {1 cola} other {# colas} } seleccionades", + "delete-queue-title": "Estàs segur d'esborrar la cua '{{queueName}}'?", + "delete-queues-title": "Estàs segur d'esborrar { count, plural, 1 {1 cola} other {# colas} }?", + "delete-queue-text": "Atenció, després de la confirmació la cua i totes les seves dades relacionades seran irrecuperables.", + "delete-queues-text": "Atenció, després de la confirmació totes les cues s'esborraran i no seran accessibles.", + "search": "Buscar cua", + "add": "Afegir cua", + "details": "Detalls cua", + "topic": "Tema", + "submit-strategy": "Estratègia d'enviament", + "processing-strategy": "Estratègia de processament", + "poll-interval": "Interval d'obtenció", + "partitions": "Particions", + "consumer-per-partition": "Consumidors per partició", + "consumer-per-partition-hint": "Activar consumidors separats per a cada partició", + "processing-timeout": "Timeout de processament, ms", + "batch-size": "Grandària de lot", + "retries": "Reintents (0 - ilimitados)", + "failure-percentage": "Percentatge de fallades", + "pause-between-retries": "Pausa entre reintents", + "max-pause-between-retries": "Pausa màxima entre reintents", + "delete": "Borrar cua", + "copyId": "Copiar Id de la cua", + "idCopiedMessage": "La Id de la cua s'ha copiat al porta-retalls", + "description": "Descripció", + "description-hint": "Aquest text es mostrarà a la descripció de la cua, en lloc de l'estratègia seleccionada", + "alt-description": "Estratègia d'enviament: {{submitStrategy}}, Estratègia de processament: {{processingStrategy}}", + "strategies": { + "sequential-by-originator-label": "Seqüencial per iniciador", + "sequential-by-originator-hint": "El nou missatge per exemple dispositiu A no s'enviarà fins que el missatge anterior del dispositiu A sigui admès/processat", + "sequential-by-tenant-label": "Seqüencial per propietari", + "sequential-by-tenant-hint": "El missatge nou, per exemple Propietari A, no s'enviarà fins que el missatge anterior del Propietari A sigui admès/processat", + "sequential-label": "Seqüencial", + "sequential-hint": "El missatge nou no s'enviarà fins que el missatge anterior sigui admès/processat", + "burst-label": "Ràfega (Burst)", + "burst-hint": "Tots els missatges s'enviaran cap a les cadenes de regles a l'ordre que arribin", + "batch-label": "Lots (Batch)", + "batch-hint": "El nou lot, no s'enviarà fins que l'anterior lot sigui admès/processat", + "skip-all-failures-label": "Skip to fallades", + "skip-all-failures-hint": "Ignorar tots els errors", + "skip-all-failures-and-timeouts-label": "Skip to fallades i temps morts", + "skip-all-failures-and-timeouts-hint": "Ignorar tots els errors i temps morts", + "retry-all-label": "Reintentar tots", + "retry-all-hint": "Reintentar tots els missatges del lot de processament", + "retry-failed-label": "Reintentar fallits", + "retry-failed-hint": "Reintentar tots els missatges fallits del lot de processament", + "retry-timeout-label": "Timeout de reintents", + "retry-timeout-hint": "Reintentar tots els missatges que donin timeout del lot de processament", + "retry-failed-and-timeout-label": "Reintentar fallits i timeouts", + "retry-failed-and-timeout-hint": "Reintentar tots els missatges fallits i que donin timeout del lot de processament" + } + }, + "tenant": { + "tenant": "Propietari", + "tenants": "Propietaris", + "management": "Gestió de Propietaris", + "add": "Afegir propietari", + "admins": "Admins", + "manage-tenant-admins": "Gestionar administradors del propietari", + "delete": "Eliminar propietari", + "add-tenant-text": "Afegir nou propietari", + "no-tenants-text": "Cap propietari trobat", + "tenant-details": "Detalls del propietari", + "title-max-length": "El títol ha de ser inferior a 256", + "delete-tenant-title": "Vols eliminar el propietari '{{tenantTitle}}'?", + "delete-tenant-text": "Atenció, després de la confirmació el propietari serà eliminat i la informació relacionada serà irrecuperable.", + "delete-tenants-title": "Vols eliminar { count, plural, 1 {1 propietario} other {# propietarios} }?", + "delete-tenants-action-title": "Eliminar { count, plural, 1 {1 propietario} other {# propietarios} }", + "delete-tenants-text": "Atenció, després de la confirmació els propietaris seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "title": "Títol", + "title-required": "Cal títol.", + "description": "Descripció", + "details": "Detalls", + "events": "Esdeveniments", + "copyId": "Copiar ID de propietari", + "idCopiedMessage": "El ID de propietari s'ha copiat al porta-retalls", + "select-tenant": "Seleccionar propietari", + "no-tenants-matching": "No hi ha propietaris que coincideixin amb '{{entity}}' .", + "tenant-required": "Propietari", + "selected-tenants": "{ count, plural, 1 {1 propietario} other {# propietarios} } seleccionats", + "search": "Buscar propietaris", + "allow-white-labeling": "Permet l'etiqueta blanca", + "allow-customer-white-labeling": "Permet l'etiqueta blanca del client", + "isolated-tb-core": "Processant en contenidor aïllat", + "isolated-tb-rule-engine": "Processant en contenidor Motor de Regles aïllat", + "isolated-tb-core-details": "Requereix microserveis separats per propietari aïllat", + "isolated-tb-rule-engine-details": "Requereix microserveis separats per propietari aïllat" + }, + "tenant-profile": { + "tenant-profile": "Perfil de propietari", + "tenant-profiles": "Perfils de propietarios", + "add": "Afegir perfil de propietari", + "edit": "Editar perfil de propietari", + "tenant-profile-details": "Detalls perfil de propietari", + "no-tenant-profiles-text": "No s'han trobar perfils de propietari", + "name-max-length": "El nom ha de ser inferior a 256", + "search": "Buscar perfils de propietari", + "selected-tenant-profiles": "{ count, plural, 1 {1 perfil de propietario} other {# perfils de propietario} } seleccionats", + "no-tenant-profiles-matching": "No s'han trobat perfils del propietari que coincideixin amb '{{entity}}'.", + "tenant-profile-required": "Cal perfil de propietari", + "idCopiedMessage": "El ID de perfil de propietari s'ha copiat al porta-retalls", + "set-default": "Fer perfil propietari per defecte", + "delete": "Esborrar perfil", + "copyId": "Copiar ID de perfil", + "name": "Nom", + "name-required": "Cal nom.", + "data": "Dades de perfil", + "profile-configuration": "Configuració de perfil", + "description": "Descripció", + "default": "Defecte", + "delete-tenant-profile-title": "Eliminar el perfil propietari '{{tenantProfileName}}'?", + "delete-tenant-profile-text": "Atenció, després de la confirmació, el perfil de propietari serà borrat i la seva informació relacionada serà irrecuperable.", + "delete-tenant-profiles-title": "Eliminar { count, plural, 1 {1 perfil propietario} other {# perfils propietarios} }?", + "delete-tenant-profiles-text": "Atenció, després de la confirmació, els perfils seleccionats s'eliminaran i la seva informació relacionada serà irrecuperable.", + "set-default-tenant-profile-title": "Vols fer el perfil propietari '{{tenantProfileName}}' per defecte?", + "set-default-tenant-profile-text": "Després de la confirmació, el perfil propietari serà marcat per defecte i serà utilitzat pels nous perfils propietaris que no tinguin perfil específic.", + "no-tenant-profiles-found": "No s'han trobar perfils de propietari.", + "create-new-tenant-profile": "Crear un nou perfil!", + "create-tenant-profile": "Crea un perfil d'inquilí nou", + "import": "Importa el perfil d'inquilí", + "export": "Exporta el perfil d'inquilí", + "export-failed-error": "No es pot exportar el perfil d'inquilí: {{error}}", + "tenant-profile-file": "Fitxer de perfil de llogater", + "invalid-tenant-profile-file-error": "No es pot importar el perfil d'inquilí: l'estructura de dades del perfil d'inquilí no és vàlida.", + "maximum-devices": "Nº Màxim de dispositius (0 - sense límit)", + "maximum-devices-required": "Cal Nº Màxim de dispositius.", + "maximum-devices-range": "Nº Màxim de dispositius no pot ser negatiu", + "maximum-assets": "Nº Màxim d'actius (0 - sense límits)", + "maximum-assets-required": "Cal Nº Màxim d'actius.", + "maximum-assets-range": "Nº Màxim d'actius no pot ser negatiu", + "maximum-customers": "Nº Màxim de clients (0 - sense límit)", + "maximum-customers-required": "Cal Nº Màxim de clients.", + "maximum-customers-range": "Nº Màxim de clients no pot ser negatiu", + "maximum-users": "Nº Màxim d'usuaris (0 - sense límit)", + "maximum-users-required": "Cal Nº Màxim d'usuaris.", + "maximum-users-range": "Nº Màxim d'usuaris no pot ser negatiu", + "maximum-dashboards": "Nº Màxim de panells (0 - sense límit)", + "maximum-dashboards-required": "Cal Nº Màxim de panells.", + "maximum-dashboards-range": "Nº Màxim de panells no pot ser negatiu", + "maximum-rule-chains": "Nº Màxim de cadenes de regles (0 - sense límit)", + "maximum-rule-chains-required": "Cal Nº Màxim de cadenes de regles.", + "maximum-rule-chains-range": "Nº Màxim de cadenes de regles no pot ser negatiu", + "maximum-integrations": "Nombre màxim d'integracions (0 - il·limitat)", + "maximum-integrations-required": "Cal nombre màxim d'integracions.", + "maximum-integrations-range": "Nombre màxim d'integracions no pot ser negatiu", + "maximum-converters": "Nombre màxim de convertidors (0 - il·limitat)", + "maximum-converters-required": "Cal nombre màxim de convertidors.", + "maximum-converters-range": "Nombre màxim de convertidors no pot ser negatiu", + "maximum-scheduler-events": "Nombre màxim d'esdeveniments del programador (0 - il·limitat)", + "maximum-scheduler-events-required": "Cal nombre màxim d'esdeveniments del programador.", + "maximum-scheduler-events-range": "Nombre màxim d'esdeveniments del programador no pot ser negatiu", + "maximum-resources-sum-data-size": "Suma màxima de la mida dels fitxers de recursos en bytes (0 - il·limitat)", + "maximum-resources-sum-data-size-required": "Cal suma màxima de la mida dels fitxers de recursos.", + "maximum-resources-sum-data-size-range": "Suma màxima de la mida dels fitxers de recursos no pot ser negatiu", + "maximum-ota-packages-sum-data-size": "Suma màxima de la mida dels fitxers del paquet ota en bytes (0 - il·limitat)", + "maximum-ota-package-sum-data-size-required": "Cal suma màxima de la mida dels fitxers del paquet ota.", + "maximum-ota-package-sum-data-size-range": "Suma màxima de la mida dels fitxers del paquet ota no pot ser negatiu", + "transport-tenant-msg-rate-limit": "Taxa de missatges de transport per propietari.", + "transport-tenant-telemetry-msg-rate-limit": "Taxa de missatges de telemetria per propietari.", + "transport-tenant-telemetry-data-points-rate-limit": "Taxa de punts de dades per propietari.", + "transport-device-msg-rate-limit": "Taxa de missatges de dispositiu.", + "transport-device-telemetry-msg-rate-limit": "Taxa de missatges de telemetria de dispositiu.", + "transport-device-telemetry-data-points-rate-limit": "Taxa de punts de dades de telemetria de dispositiu.", + "max-transport-messages": "Nº Màxim de missatges de transport (0 - sense límit)", + "max-transport-messages-required": "Cal Nº Màxim de missatges de transport.", + "max-transport-messages-range": "Nº Màxim de missatges de transport no pot ser negatiu", + "max-transport-data-points": "Nº Màxim de punts de dades transport (0 - sense límit)", + "max-transport-data-points-required": "Cal Nº Màxim de punts de dades transport.", + "max-transport-data-points-range": "Nº Màxim de punts de dades transport no pot ser negatiu", + "max-r-e-executions": "Nº Màxim de execucions de motor de regles (0 - sense límit)", + "max-r-e-executions-required": "Cal Nº Màxim de execucions de motor de regles.", + "max-r-e-executions-range": "Nº Màxim de execucions de motor de regles no pot ser negatiu", + "max-j-s-executions": "Nº Màxim de execucions JavaScript (0 - sense límit)", + "max-j-s-executions-required": "Cal Nº Màxim de execucions JavaScript.", + "max-j-s-executions-range": "Nº Màxim de execucions JavaScript no pot ser negatiu", + "max-d-p-storage-days": "Nº Màxim de dies a gravar en punts de dades (0 - sense límit)", + "max-d-p-storage-days-required": "Cal Nº Màxim de dies.", + "max-d-p-storage-days-range": "Nº Màxim de dies no pot ser negatiu", + "default-storage-ttl-days": "Dies per defecte gravats TTL (0 - sense límit)", + "default-storage-ttl-days-required": "Cal dies per defecte TTL.", + "default-storage-ttl-days-range": "Dies per defecte TTL no pot ser negatiu", + "alarms-ttl-days": "Alarmes TTL dies (0 - il·limitat)", + "alarms-ttl-days-required": "Cal alarmes TTL dies", + "alarms-ttl-days-days-range": "Alarmes TTL dies no pot ser negatiu", + "rpc-ttl-days": "RPC TTL days (0 - il·limitat)", + "rpc-ttl-days-required": "Cal RPC TTL dies", + "rpc-ttl-days-days-range": "RPC TTL days no pot ser negatiu", + "max-rule-node-executions-per-message": "Nº Màxim de execucions (cadena de regles) per missatge (0 - sense límit)", + "max-rule-node-executions-per-message-required": "Cal Nº Màxim de execucions per missatge.", + "max-rule-node-executions-per-message-range": "Nº Màxim de execucions per missatge no pot ser negatiu", + "max-correus electrònics": "Nº Màxim de correus electrònics (0 - sense límit)", + "max-correus electrònics-required": "Cal Nº Màxim de correus electrònics.", + "max-correus electrònics-range": "Nº Màxim de correus electrònics no pot ser negatiu", + "max-sms": "Nº Màxim de missatges SMS (0 - sense límit)", + "max-sms-required": "Cal Nº Màxim de missatges SMS.", + "max-sms-range": "Nº Màxim de missatges SMS no pot ser negatiu", + "max-created-alarms": "Nombre màxim d'alarmes creades (0 - il·limitat)", + "max-created-alarms-required": "Cal nombre màxim d'alarmes creades.", + "max-created-alarms-range": "Nombre màxim d'alarmes creades no pot ser negatiu", + "no-queue": "No s'ha configurat cap cua", + "add-queue": "Afegeix cua", + "queues-with-count": "Cues ({{count}})", + "tenant-rest-limits": "Límit de tarifa per a les sol·licituds REST per a llogaters", + "customer-rest-limits": "Límit de tarifa per a sol·licituds REST per al client", + "incorrect-pattern-for-rate-limits": "El format és parells separats per comes de capacitat i punt (in seconds) amb dos punts entre, p. 100:1,2000:60", + "too-small-value-zero": "El valor ha de ser més gran que 0", + "too-small-value-one": "El valor ha de ser més gran que 1", + "cassandra-tenant-limits-configuration": "Límit de taxa de consultes de Cassandra per al llogater", + "ws-limit-max-sessions-per-tenant": "Nombre màxim de sessions de WS per inquilí", + "ws-limit-max-sessions-per-customer": "Nombre màxim de sessions de WS per client", + "ws-limit-max-sessions-per-public-user": "Nombre màxim de sessions de WS per usuari públic", + "ws-limit-queue-per-session": "Mida màxima de la cua de missatges de WS per sessió", + "ws-limit-max-subscriptions-per-tenant": "Nombre màxim de subscripcions de WS per inquilí", + "ws-limit-max-subscriptions-per-customer": "Nombre màxim de subscripcions de WS per client", + "ws-limit-max-subscriptions-per-regular-user": "Nombre màxim de subscripcions de WS per usuari habitual", + "ws-limit-max-subscriptions-per-public-user": "Nombre màxim de subscripcions de WS per usuari públic", + "ws-limit-updates-per-session": "Límit de tarifa per a les actualitzacions de WS per sessió" + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segons} }", + "minutes-interval": "{ minutes, plural, 1 {1 minuto} other {# minutos} }", + "hours-interval": "{ hours, plural, 1 {1 hora} other {# horas} }", + "days-interval": "{ days, plural, 1 {1 día} other {# dies} }", + "days": "Dies", + "hours": "Hores", + "minutes": "Minuts", + "seconds": "Segons", + "advanced": "Avançat", + "predefined": { + "yesterday": "Ahir", + "day-before-yesterday": "Abans d'ahir", + "this-day-last-week": "Aquest dia de la setmana passada", + "previous-week": "Setmana anterior (dg - ds)", + "previous-week-iso": "Setmana anterior (dl-dg)", + "previous-month": "Mes anterior", + "previous-year": "Any anterior", + "current-hour": "Hora actual", + "current-day": "Dia actual", + "current-day-so-far": "Dia actual fins ara", + "current-week": "Setmana actual (dg - ds)", + "current-week-iso": "Setmana actual (dl-dg)", + "current-week-so-far": "La setmana actual fins ara (dg - ds)", + "current-week-iso-so-far": "La setmana actual fins al moment (dl - dg)", + "current-month": "Aquest mes", + "current-month-so-far": "Mes actual fins ara", + "current-year": "Aquest any", + "current-year-so-far": "Any en curs fins ara" + } + }, + "timeunit": { + "milliseconds": "Mil·lisegons", + "seconds": "Segons", + "minutes": "Minuts", + "hours": "Hores", + "days": "Dies" + }, + "timewindow": { + "days": "{ days, plural, 1 { día } other {# dies } }", + "hours": "{ hours, plural, 0 { horas } 1 {1 hora } other {# horas } }", + "minutes": "{ minutes, plural, 0 { minutos } 1 {1 minuto } other {# minutos } }", + "seconds": "{ seconds, plural, 0 { segons } 1 {1 segundo } other {# segons } }", + "realtime": "Temps-real", + "history": "Històric", + "last-prefix": "últim(s)", + "period": "Des de {{ startTime }} fins a {{ endTime }}", + "edit": "Editar finestra del temps", + "date-range": "Rang de dates", + "last": "Últims(s)", + "time-period": "Període del temps", + "hide": "Amagar", + "interval": "Interval" + }, + "user": { + "user": "Usuari", + "users": "Usuaris", + "management": "Gestió d'usuaris", + "customer-users": "Usuaris del Client", + "tenant-admins": "Admins propietaris", + "sys-admin": "Administrador del Sistema", + "tenant-admin": "Administrador del Propietari", + "customer": "Client", + "anonymous": "Anònim", + "add": "Afegir usuari", + "delete": "Eliminar usuari", + "add-user-text": "Afegir nou usuari", + "no-users-text": "Ningun usuari trobat", + "user-details": "Detalls de l'usuari", + "delete-users": "Eliminar usuaris", + "delete-user-title": "Eliminar l'usuari '{{userEmail}}'?", + "delete-user-text": "Atenció, després de la confirmació l'usuari seleccionar serà eliminat i la informació relacionada serà irrecuperable.", + "delete-users-title": "Eliminar { count, plural, 1 {1 usuario} other {# usuaris} }?", + "delete-users-action-title": "Esborrar { count, plural, 1 {1 usuario} other {# usuaris} }", + "delete-users-text": "Atenció, després de la confirmació dels usuaris seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "activation-email-sent-message": "Correu d'activació enviat amb èxit!", + "resend-activation": "Reenviar activació", + "email": "Correu", + "email-required": "Cal correu.", + "invalid-email-format": "Format del correu no vàlid.", + "first-name": "Nom", + "last-name": "Cognom", + "description": "Descripció", + "default-dashboard": "Panell per defecte", + "always-fullscreen": "Sempre en pantalla completa", + "select-user": "Seleccionar usuari", + "no-users-matching": "No s'han trobat usuaris coincidint amb '{{entity}}' .", + "user-required": "Cal usuari", + "activation-method": "Mètode d'activació", + "display-activation-link": "Mostrar l'enllaç d'activació", + "send-activation-mail": "Enviar correu d'activació", + "activation-link": "Enllaç d'activació d'usuari", + "activation-link-text": "Per activar l'usuari, utilitza el següent enllaç: Activar Usuari :", + "copy-activation-link": "Copiar enllaç d'activació", + "activation-link-copied-message": "L'enllaç d'activació s'ha copiat al porta-retalls", + "selected-users": "{ count, plural, 1 {1 usuario} other {# usuaris} } seleccionats", + "search": "Buscar usuaris", + "details": "Detalls", + "login-as-tenant-admin": "Iniciar sessió com a Administrador Propietari", + "login-as-customer-user": "Iniciar sessió com a Usuari Client", + "select-group-to-add": "Seleccioneu el grup objectiu per afegir usuaris seleccionats", + "select-group-to-move": "Seleccioneu el grup objectiu per moure els usuaris seleccionats", + "remove-users-from-group": "Esteu segur que voleu eliminar-lo { count, plural, 1 {1 user} other {# users} } del grup '{{entityGroup}}'?", + "group": "Grup d'usuaris", + "list-of-groups": "{ count, plural, 1 {One user group} other {List of # user groups} }", + "group-name-starts-with": "Grups d'usuaris els noms dels quals comencen per '{{prefix}}'", + "disable-account": "Deshabilitar compte d'usuari", + "enable-account": "Habilitar compte d'usuari", + "enable-account-message": "El compte d'usuari s'ha habilitat correctament!", + "disable-account-message": "El compte d'usuari s'ha deshabilitat correctament!!", + "copyId": "Copia l'ID de l'usuari", + "idCopiedMessage": "L'identificador d'usuari s'ha copiat al porta-retalls" + }, + "value": { + "type": "Tipus de valor", + "string": "Cadena de text", + "string-value": "Valor de cadena de text", + "string-value-required": "Cal valor de cadena de text", + "integer": "Número enter", + "integer-value": "Valor del número enter", + "integer-value-required": "Cal valor enter", + "invalid-integer-value": "Valor de enter invàlid", + "double": "Número decimal", + "double-value": "Valor número decimal", + "double-value-required": "Cal valor número decimal", + "boolean": "Booleà", + "boolean-value": "Valor booleà", + "false": "Fals", + "true": "Verdader", + "long": "Número llarg", + "json": "JSON", + "json-value": "Valor JSON", + "json-value-invalid": "El valor JSON té un format invàlid", + "json-value-required": "Cal valor JSON" + }, + "version-control": { + "version-control": "Control de versió", + "management": "Administrador de versions", + "branch": "Branca", + "default": "Per defecte", + "select-branch": "Seleccionar branca", + "branch-required": "Cal branca", + "create-entity-version": "Versió creació important", + "version-name": "Nom de versió", + "version-name-required": "Cal nom de versió", + "author": "Autor", + "export-relations": "Exportar relacions", + "export-attributes": "Exportar atributs", + "export-credentials": "Exportar credencials", + "entity-versions": "Versions d'entitat", + "versions": "Versions", + "created-time": "Hora de creació", + "version-id": "ID de versió", + "no-entity-versions-text": "No s'han trobat versions d'entitat", + "no-versions-text": "No s'han trobat versions", + "copy-full-version-id": "Copiar el ID de versió", + "create-version": "Crear versió", + "nothing-to-commit": "No hi ha canvis a publicar", + "restore-version": "Restaurar versió", + "restore-entity-from-version": "Restaurar entitat des de versió '{{versionName}}'", + "load-relations": "Cargar relacions", + "load-attributes": "Cargar atributs", + "load-credentials": "Cargar credencials", + "diff-entity-with-version": "Diff de la versió de entitat '{{versionName}}'", + "previous-difference": "Anterior diferència", + "next-difference": "Següent diferència", + "current": "Actual", + "differences": "{ count, plural, 1 {1 diferencia} other {# diferencias} }", + "create-entities-version": "Crear versió d'entitats", + "default-sync-strategy": "Estratègia de sincronització per defecte", + "sync-strategy-merge": "Fusionar (Merge)", + "sync-strategy-overwrite": "Sobreescriure", + "entities-to-export": "Entitats a exportar", + "entities-to-restore": "Entitats a restaurar", + "sync-strategy": "Estratègia de sincronizació", + "all-entities": "Totes les entitats", + "no-entities-to-export-prompt": "Si us plau, especifica les entitats a exportar", + "no-entities-to-restore-prompt": "Si us plau, especifica les entitats a restaurar", + "add-entity-type": "Afegir tipus d'entitat", + "remove-all": "Borrar tot", + "version-create-result": "{ added, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } afegides.
              { modified, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } modificades.
              { removed, plural, 0 {Ninguna entidad} 1 {1 entidad} other {# entidades} } esborrades.", + "remove-other-entities": "Esborrar altres entitats", + "find-existing-entity-by-name": "Buscar entitat existent per nom", + "restore-entities-from-version": "Restaurar entitats des de la versió '{{versionName}}'", + "no-entities-restored": "No es van restaurar entitats", + "created": "{{created}} creades", + "updated": "{{updated}} actualitzades", + "deleted": "{{deleted}} esborrades", + "remove-other-entities-confirm-text": "Atenció! Aquesta acció esborrarà permanentment todas les entitats actuals
              no presents a la versió a restaurar.

              Escriu eliminar altres entitats per confirmar.", + "auto-commit-to-branch": "autopublicar a la branca {{ branch }}", + "default-create-entity-version-name": "{{entityName}} actualizació", + "sync-strategy-merge-hint": "Crea o actualitza les entitats seleccionades al repositori. Les altres entitats no seran modificades.", + "sync-strategy-overwrite-hint": "Crea o actualitza les entitats seleccionades al repositori. Les altres entitats seran esborrades.", + "device-credentials-conflict": "Fallada en carregar el dispositiu amb ID extern {{entityId}}
              pel fet que les mateixes credencials estan ja presents a la base de dades per a un altre dispositiu.
              Si us plau, considereu desactivar l'ajustament carregar credencials al formulari de restauració.", + "missing-referenced-entity": "Fallada en carregar {{sourceEntityTypeName}} amb ID extern {{sourceEntityId}}
              perquè fa referència al tipus d'entitat {{targetEntityTypeName}} amb el ID {{targetEntityId}}." + }, + "widget": { + "widget-library": "Bibloteca de Widgets", + "widget-bundle": "Paquets de Widgets", + "all-bundles": "Tots els paquets", + "select-widgets-bundle": "Seleccionar paquet de widgets", + "management": "Gestió de Widgets", + "editor": "Editor de widgets", + "widget-type-not-found": "Problema al carregar la configuració del widget.
              Probablement associat\n El tipus de widget ha estat eliminat.", + "widget-type-load-error": "El widget no ha estat carregat degut a aquests errors:", + "remove": "Eliminar widget", + "edit": "Editar widget", + "remove-widget-title": "Eliminar el widget '{{widgetTitle}}'?", + "remove-widget-text": "Atenció, després de la confirmació el widget serà eliminat i tota la informació relacionada serà irrecuperable.", + "timeseries": "Sèries del temps", + "search-data": "Buscar dades", + "no-data-found": "No s'han trobat dades", + "latest": "Últims valors", + "rpc": "Widget de control", + "alarm": "Widget d'alarma", + "static": "Widget estàtic", + "select-widget-type": "Seleccionar tipus de widget", + "missing-widget-title-error": "El titul del widget ha de ser especificat!", + "widget-saved": "Widget guardat", + "unable-to-save-widget-error": "Impossible guardar widget! Té errors!", + "save": "Guardar widget", + "saveAs": "Guardar widget com", + "save-widget-type-as": "Guardar tipus de widget com", + "save-widget-type-as-text": "Per favor, introduïu un nou títol i/o seleccioneu un paquet de destinació.", + "toggle-fullscreen": "Canviar a pantalla completa", + "run": "Ejecutar widget", + "title": "Títol", + "title-required": "Cal títol.", + "type": "Tipus", + "resources": "Recursos", + "resource-url": "URL JavaScript/CSS", + "resource-is-module": "És mòdul", + "remove-resource": "Eliminar recurs", + "add-resource": "Afegir recurs", + "html": "HTML", + "tidy": "Endreçat", + "css": "CSS", + "settings-schema": "Esquema de configuració", + "datakey-settings-schema": "Esquema de configuració de clau de dades", + "latest-datakey-settings-schema": "Esquema de darrers valors", + "widget-settings": "Configuració Widget", + "description": "Descripció", + "image-preview": "Vista prèvia de la imatge", + "settings-form-selector": "Selector de formulari de configuració", + "data-key-settings-form-selector": "Selector de formulari de configuració claus de dades", + "latest-data-key-settings-form-selector": "Selector formulari dels darrers valors", + "javascript": "Javascript", + "js": "JS", + "remove-widget-type-title": "Eliminar el tipus del widget '{{widgetName}}'?", + "remove-widget-type-text": "Atenció, després de la confirmació el tipus serà eliminat i la informació relacionada serà irrecuperable.", + "remove-widget-type": "Eliminar tipus de widget.", + "add-widget-type": "Afegir nou tipus de widget", + "widget-type-load-failed-error": "Error al carregar el tipus de widget!", + "widget-template-load-failed-error": "Error al carregar la plantilla del widget!", + "add": "Afegir Widget", + "undo": "Desfer canvis", + "export": "Exportar widget", + "export-data": "Exportar dades del widget", + "export-to-csv": "Exportar dades a CSV...", + "export-to-excel": "Exportar dades a XLS...", + "export-to-excel-xlsx": "Exportar dades a XLSX...", + "no-data": "No hi ha dades per mostrar en widget", + "data-overflow": "El widget mostra {{count}} de {{total}} entitats", + "alarm-data-overflow": "El widget mostra alarmes per {{allowedEntities}} entitats (màxim permès) de {{totalEntities}} entitats", + "search": "Cerca widget", + "filter": "Tipus de filtre Widget", + "loading-widgets": "S'estan carregant els widgets..." + }, + "widget-action": { + "header-button": "Botó d'encapçalats widget", + "open-dashboard-state": "Navegar a un nou estat de panell", + "update-dashboard-state": "Actualizar l'estat del panell actual", + "open-dashboard": "Navegar a un altre panell", + "custom": "Acció personalitzada", + "custom-pretty": "Acció personalitzada (amb plantilla HTML)", + "mobile-action": "Acció mòbil", + "target-dashboard-state": "Estat de panell de destí", + "target-dashboard-state-required": "Cal estat de panell de destí", + "set-entity-from-widget": "Establir entitat des de widget", + "target-dashboard": "Panell de destí", + "open-right-layout": "Obrir disseny de panell (Dret)(vista móvil)", + "state-display-type": "Opció de visualització de l'estat del tauler", + "open-normal": "Normal", + "open-in-separate-dialog": "Obrir en un diàleg separat", + "open-in-popover": "Obre en popover", + "dialog-title": "Títol del diàleg", + "dialog-hide-dashboard-toolbar": "Ocultar barra d'eines en el diàleg", + "dialog-width": "Ample de diàleg en percentatge relatiu a l'ample del viewport", + "dialog-height": "Alt de diàleg en percentatge relatiu a l'alt del viewport", + "dialog-size-range-error": "La grandària del diàleg ha de ser entre un rang de 1 a 100", + "popover-preferred-placement": "Col·locació popover preferida", + "popover-placement-top": "Superior", + "popover-placement-topLeft": "Superior esquerra", + "popover-placement-topRight": "Superior dret", + "popover-placement-right": "Dret", + "popover-placement-rightTop": "Dret superior", + "popover-placement-rightBottom": "Dret inferior", + "popover-placement-bottom": "Bottom", + "popover-placement-bottomLeft": "Bottom esquerra", + "popover-placement-bottomRight": "Bottom dret", + "popover-placement-left": "Esquerra", + "popover-placement-leftTop": "Esquerra superior", + "popover-placement-leftBottom": "Esquerra inferior", + "popover-hide-on-click-outside": "Amaga la finestra emergent al clic exterior", + "popover-hide-dashboard-toolbar": "Amaga la barra d'eines del tauler a la finestra emergent", + "popover-width": "Amplada emergent en unitats del navegador (p. ex. 100 píxels, 25 vw)", + "popover-height": "Alçada emergent en unitats del navegador (p. ex. 100px, 25vh)", + "popover-style": "Estil popover", + "open-new-browser-tab": "Obrir en una nova pestanya", + "mobile": { + "action-type": "Tipus d'acció mòbil", + "action-type-required": "Cal el tipus d'acció mòbil", + "take-picture-from-gallery": "Fer una foto de la galeria", + "take-photo": "Fer foto", + "map-direction": "Obriu les indicacions del mapa", + "map-location": "Obre la ubicació del mapa", + "scan-qr-code": "Escaneja el codi QR", + "make-phone-call": "Fes una trucada telefònica", + "get-location": "Obteniu la ubicació del telèfon", + "take-screenshot": "Fes una captura de pantalla" + } + }, + "widgets-bundle": { + "current": "Paquet actual", + "widgets-bundles": "Paquet de Widgets", + "add": "Afegir paquet de widgets", + "delete": "Eliminar paquet de widgets", + "title": "Títol", + "title-required": "Cal títol.", + "title-max-length": "El títol ha de ser inferior a 256", + "description": "Descripció", + "image-preview": "Vista prèvia de la imatge", + "add-widgets-bundle-text": "Afegir nou paquet de widgets", + "no-widgets-bundles-text": "Cap paquet de widgets trobat", + "empty": "Paquet de widgets buit.", + "details": "Detalls", + "widgets-bundle-details": "Detalls del paquet de Widgets", + "delete-widgets-bundle-title": "Eliminar el paquet de widgets '{{widgetsBundleTitle}}'?", + "delete-widgets-bundle-text": "Atenció, després de la confirmació tots els paquets seleccionats seran eliminats i la seva informació relacionada serà irrecuperable.", + "delete-widgets-bundles-title": "Eliminar { count, plural, 1 {1 paquet de widgets} other {# paquetes de widgets} }?", + "delete-widgets-bundles-action-title": "Eliminar { count, plural, 1 {1 paquet de widgets} other {# paquetes de widgets} }", + "delete-widgets-bundles-text": "Atenció, després de la confirmació tots els paquets seleccionats seran eliminats i la informació relacionada serà irrecuperable.", + "no-widgets-bundles-matching": "Cap paquet '{{widgetsBundle}}' trobat.", + "widgets-bundle-required": "Cal paquet de widget.", + "system": "Widget de Sistema", + "import": "Importar paquet de widgets", + "export": "Exportar paquet de widgets", + "export-failed-error": "Impossible exportar paquet de widgets: {{error}}", + "create-new-widgets-bundle": "Crear nou paquet de widgets", + "widgets-bundle-file": "Arxiu de paquet de widgets", + "invalid-widgets-bundle-file-error": "Impossible importar paquet de widgets: Estructura de dades invàlida.", + "search": "Buscar paquet de widgets", + "selected-widgets-bundles": "{ count, plural, 1 {1 paquet de widgets} other {# paquetes de widgets} } seleccionats", + "open-widgets-bundle": "Obrir paquet de widgets", + "loading-widgets-bundles": "S'estan carregant paquets de widgets..." + }, + "widget-config": { + "data": "Dades", + "settings": "Configuració", + "advanced": "Avançat", + "title": "Títol", + "title-tooltip": "Tooltip Títol", + "general-settings": "Configuració generals", + "display-title": "Mostrar títol", + "drop-shadow": "Ombra", + "enable-fullscreen": "Habilitar pantalla completa", + "enable-data-export": "Habilitar exportació de dades", + "background-color": "Color de fons", + "text-color": "Color del text", + "padding": "Farciment", + "margin": "Marge", + "widget-style": "Estil de widget", + "widget-css": "Widget CSS", + "title-style": "Estil de títol", + "mobile-mode-settings": "Configuració móvil.", + "order": "Orde", + "height": "Alçada", + "mobile-hide": "Amaga el widget en mode mòbil", + "units": "Caràcter especial a mostrar al següent valor", + "decimals": "Números de dígits després de la coma", + "timewindow": "Finestra del temps", + "use-dashboard-timewindow": "Utilitzar finestra del temps del panell", + "display-timewindow": "Mostrar finestra del temps", + "legend": "Llegenda", + "display-legend": "Mostrar llegenda", + "datasources": "Set de dades", + "maximum-datasources": "Un màxim de { count, plural, 1 {1 set de dades és permès.} other {# set de dades són permitidos} }", + "datasource-type": "Tipus", + "datasource-parameters": "Paràmetres", + "remove-datasource": "Eliminar set de dades", + "add-datasource": "Afegir set de dades", + "target-device": "Dispositiu destí", + "alarm-source": "Origen de alarmes", + "actions": "Accions", + "action": "Acció", + "add-action": "Afegir acció", + "search-actions": "Buscar accions", + "no-actions-text": "No s'han trobar accions", + "action-source": "Origen de acció", + "action-source-required": "Cal origen de acció.", + "action-name": "Nom", + "action-name-required": "Cal nom de acció.", + "action-name-not-unique": "Existe una acció amb el mateix nom.
              El nom d'acció ha de ser únic dins de la mateixa font d'acció (origen).", + "action-icon": "Icona", + "show-hide-action-using-function": "Mostra/amaga l'acció mitjançant la funció", + "action-type": "Tipus", + "action-type-required": "Cal tipus d'acció.", + "edit-action": "Editar acció", + "delete-action": "Esborrar acció", + "delete-action-title": "Esborrar acció de widget", + "delete-action-text": "Eliminar l'acció de widget amb el nom '{{actionName}}'?", + "title-icon": "Icona del títol", + "display-icon": "Mostrar icona del títol", + "icon-color": "Color de l'icona", + "icon-size": "Mida de l'icona", + "advanced-settings": "Configuració avançada", + "data-settings": "Configuració de dades", + "no-data-display-message": "\"No hi ha dades per mostrar\" missatge alternatiu", + "data-page-size": "Nombre màxim d'entitats per font de dades", + "settings-component-not-found": "Component de configuració no trobat per al selector '{{selector}}'" + }, + "widget-type": { + "import": "Importar tipus de widget", + "export": "Exportar tipus de widget", + "export-failed-error": "Impossible exportar tipus de widget: {{error}}", + "create-new-widget-type": "Crear nou tipus de widget", + "widget-type-file": "Arxiu de tipus de widget", + "invalid-widget-type-file-error": "No es pot importar tipus de widget: Estructura de dades del tipus de widget és invàlida." + }, + "solution-template": { + "solution-template": "Plantilla de solució", + "solution-templates": "Plantilles de solució", + "management": "Gestionar plantilles de solució", + "details": "Detalls", + "install": "Instal·lar", + "level": "Nivell", + "install-title": "La plantilla de solució s'ha instal·lat correctament", + "install-failed-title": "La instal·lació de la plantilla de solució ha fallat", + "instructions": "Instruccions", + "goto-main-dashboard": "Vés al tauler principal", + "delete": "Suprimeix", + "delete-solution-title": "Esteu segur que voleu suprimir la solució '{{solutionTitle}}'?", + "delete-solution-text": "Aneu amb compte, després de la confirmació, la solució i totes les dades relacionades es tornaran irrecuperables.", + "installing": "Instal·lació de la plantilla de solució..." + }, + "markdown": { + "edit": "Edita", + "preview": "Vista prèvia", + "copy-code": "Feu clic per copiar", + "copied": "Copiat!" + }, + "white-labeling": { + "white-labeling": "Etiquetatge Blanc", + "login-white-labeling": "Iniciar sessió de Etiquetado Blanco", + "preview": "Avanç", + "app-title": "Títol de l'aplicació", + "favicon": "Icona del lloc WEB", + "favicon-description": "Imatge *.ico, *.gif o *.png amb grandària màxima {{kbSize}} KBytes.", + "favicon-size-error": "Imatge del lloc web és molt gran. Mesura màxima permesa de la imatge del lloc web {{kbSize}} KBytes.", + "favicon-type-error": "Formato de arxiu de imagen de lloc WEB invàlid. Solamente es aceptan imágenes ICO, GIF o PNG.", + "drop-favicon-image": "Colocar la imagen del icona de un lloc WEB o haga clic per seleccionar un arxiu per carregar .", + "no-favicon-image": "Icona no seleccionat", + "logo": "Logo", + "logo-description": "Alguna imagen amb grandària màxima {{kbSize}} KBytes.", + "logo-size-error": "L'imatge del logo és molt gran. Mida màxima permesa de la imatge del logo {{kbSize}} KBytes.", + "logo-type-error": "Format darxiu del logotip invàlid. Només és accepten imatges.", + "drop-logo-image": "Colocar una imagen del logotipo o fes clic per seleccionar un arxiu per carregar .", + "no-logo-image": "Logo no seleccionat", + "logo-height": "Alçada del logo, píxel", + "primary-palette": "Paleta primària", + "accent-palette": "Paleta d'accents", + "customize-palette": "Personalitzar", + "advanced-css": "CSS avançat", + "edit-palette": "Editar paleta", + "save-palette": "Guardar paleta", + "primary-background": "Color de fons primari", + "secondary-background": "Color de fons secundari", + "hue1": "HUE 1", + "hue2": "HUE 2", + "hue3": "HUE 3", + "page-background-color": "Color de fons de la pàgina", + "dark-foreground": "Primer pla fosc", + "domain-name": "Nom del domini", + "base-url": "Base URL", + "base-url-required": "Cal la base URL.", + "prohibit-different-url": "Prohibir l'ús del nom d'amfitrió de les capçaleres de la sol·licitud del client", + "prohibit-different-url-hint": "Aquesta configuració s'hauria d'habilitar per als entorns de producció. Pot causar problemes de seguretat quan està desactivat", + "help-link-base-url": "URL base dels enllaços d'ajuda", + "ui-help-base-url": "URL de la base d'ajuda de la IU", + "enable-help-links": "Activa els enllaços d'ajuda", + "error-verification-url": "Un nom de domini no ha de contenir els símbols '/' i ':'. Exemple: thingsboard.io", + "show-platform-name-version": "Mostra el nom i la versió de la plataforma", + "platform-name": "Nom de la plataforma", + "platform-version": "Versió de plataforma", + "version-mask": "{{name}} v.{{version}}", + "position": { + "label": "Nom de la plataforma i posició de la versió", + "under-logo": "Sota el logotip", + "bottom": "Part inferior del formulari d'inici de sessió" + } + }, + "widgets": { + "chart": { + "common-settings": "Configuració comuna", + "enable-stacking-mode": "Activar mode d'apilament (stacking)", + "line-shadow-size": "Grandària d'ombra (línia)", + "display-smooth-lines": "Mostra línies suaus (curvas)", + "default-bar-width": "Ample de barra per defecte per a dades no agregades (millisegundos)", + "bar-alignment": "Alineació de barres", + "bar-alignment-left": "Esquerra", + "bar-alignment-right": "Dreta", + "bar-alignment-center": "Centre", + "default-font-size": "Grandaria de la font per defecte", + "default-font-color": "Color de la font per defecte", + "thresholds-line-width": "Ample de línia per defecte per a tots els llindars", + "tooltip-settings": "Ajustaments de suggeriments (tooltip)", + "show-tooltip": "Mostra suggeriments", + "hover-individual-points": "Passa el cursor sobre punts individuals", + "show-cumulative-values": "Mostrar valors acumulats en mode apilat", + "hide-zero-false-values": "Amagar valors zero/false en suggeriments", + "tooltip-value-format-function": "Funció de formateig de valors en suggeriments (tooltip)", + "grid-settings": "Configuració de la graella", + "show-vertical-lines": "Mostrar línies verticales", + "show-horizontal-lines": "Mostrar línies horizontales", + "grid-outline-border-width": "Ample de quadrícula/contorn a px", + "primary-color": "Color primari", + "background-color": "Color de fons", + "ticks-color": "Color de ticks", + "xaxis-settings": "Configuració eix X", + "axis-title": "Títol d'eix", + "xaxis-tick-labels-settings": "Configuració d'etiquetes en ticks eix X", + "show-tick-labels": "Mostrar etiquetes en ticks", + "yaxis-settings": "Configuració eix Y", + "min-scale-value": "Valor mínim en l'escala", + "max-scale-value": "Valor máxim en l'escala", + "yaxis-tick-labels-settings": "Configuració 'etiquetes en ticks eix Y", + "tick-step-size": "Grandaria de pas entre ticks", + "number-of-decimals": "Número de decimals", + "ticks-formatter-function": "Funció de formateig de ticks", + "comparison-settings": "Configuració de comparació", + "enable-comparison": "Activar comparació", + "time-for-comparison": "Període de comparació", + "time-for-comparison-previous-interval": "Interval anterior (per defecte)", + "time-for-comparison-days": "Fa un dia", + "time-for-comparison-weeks": "Fa una setmana", + "time-for-comparison-months": "Fa un mes", + "time-for-comparison-years": "Fa un any", + "time-for-comparison-custom-interval": "Interval personalitzat", + "custom-interval-value": "Valor d'interval personalitzat (ms)", + "comparison-x-axis-settings": "Configuració comparació de l'eix X", + "axis-position": "Posició eix", + "axis-position-top": "Superior (por defecto)", + "axis-position-bottom": "Inferior", + "custom-legend-settings": "Configuració llegenda", + "enable-custom-legend": "Activar llegenda personalitzada (permet poder utilitzar valors d'atributs/series temporals a les etiquetes)", + "key-name": "Nom clau", + "key-name-required": "Cal nom clau", + "key-type": "Tipus clau", + "key-type-attribute": "Atribut", + "key-type-timeseries": "Sèries temporals", + "label-keys-list": "Llista de claus per utilitzar a etiquetes", + "no-label-keys": "No hi ha claus configurades", + "add-label-key": "Afegir nova clau", + "line-width": "Ample de línia", + "color": "Color", + "data-is-hidden-by-default": "Ocultar dades per defecte", + "disable-data-hiding": "Desactivar ocultació de dades", + "remove-from-legend": "Treure clau de la llegenda", + "exclude-from-stacking": "Excloure del mode apilat(disponible en el mode \"Apilat\")", + "line-settings": "Configuració de línia", + "show-line": "Mostrar línia", + "fill-line": "Omplir línia", + "points-settings": "Configuració de punts", + "show-points": "Mostrar punts", + "points-line-width": "Ample de línia en punts", + "points-radius": "Radi dels punts", + "point-shape": "Forma del punt", + "point-shape-circle": "Cercle", + "point-shape-cross": "Creu", + "point-shape-diamond": "Diamant", + "point-shape-square": "Quadrat", + "point-shape-triangle": "Triangle", + "point-shape-custom": "Funció personalitzada", + "point-shape-draw-function": "Funció de forma del punt", + "show-separate-axis": "Mostrar eix separat", + "axis-position-left": "Esquerra", + "axis-position-right": "Dreta", + "thresholds": "Llindars", + "no-thresholds": "No hi ha llindars configurats", + "add-threshold": "Afegir nou llindar", + "show-values-for-comparison": "Mostrar valors històrics per la seva comparació", + "comparison-values-label": "Etiqueta de valors històrics", + "threshold-settings": "Configuració de llindars", + "use-as-threshold": "Usar valor de clau com a llindar", + "threshold-line-width": "Ample de línia (per a llindar)", + "threshold-color": "Color llindar", + "common-pie-settings": "Configuració comunes diagrama de sectors", + "radius": "Radi", + "inner-radius": "Radi interior", + "tilt": "Inclinació", + "stroke-settings": "Configuració de traç", + "width-pixels": "Ample (pixels)", + "show-labels": "Mostrar etiquetes", + "animation-settings": "Configuració de animació", + "animated-pie": "Activar animació (experimental)", + "border-settings": "Configuració de vores", + "border-width": "Ancho de la vora", + "border-color": "Color de la vora", + "legend-settings": "Configuració de llegenda", + "display-legend": "Mostrar llegenda", + "labels-font-color": "Color de text en llegenda" + }, + "dashboard-state": { + "dashboard-state-settings": "Configuració estat del panell", + "dashboard-state": "Id del estat del panell", + "autofill-state-layout": "Autoremplenar alçada per defecte (obtinguda de l'estat)", + "default-margin": "Marge entre widgets per defecte", + "default-background-color": "Color de fons per defecte", + "sync-parent-state-params": "Sincronitzar paràmetres d'estat amb el panell pare" + }, + "date-range-navigator": { + "date-range-picker-settings": "Ajustaments del selector de dates", + "hide-date-range-picker": "Esmagar el selector de dades", + "picker-one-panel": "Selector de dates per a un panell", + "picker-auto-confirm": "Auto-confirmar al selector de dates", + "picker-show-template": "Mostra plantilla de selector de dates", + "first-day-of-week": "Primer dia de la setmana", + "interval-settings": "Paràmetres d'interval", + "hide-interval": "Ocultar interval", + "initial-interval": "Interval inicial", + "interval-hour": "Hora", + "interval-day": "Dia", + "interval-week": "Setmana", + "interval-two-weeks": "2 setmanes", + "interval-month": "Mes", + "interval-three-months": "3 mesos", + "interval-six-months": "6 mesos", + "step-settings": "Paràmetres de pas", + "hide-step-size": "Amagar mida de pas", + "initial-step-size": "Mida de pas inicial", + "hide-labels": "Ocultar etiquetes", + "use-session-storage": "Utilitzar emmagatzematge de sessió", + "localizationMap": { + "Sun": "Dg.", + "Mon": "Dl.", + "Tue": "Dm.", + "Wed": "Dc.", + "Thu": "Dj.", + "Fri": "Dv.", + "Sat": "Ds.", + "Jan": "Gen.", + "Feb": "Feb.", + "Mar": "Mar.", + "Apr": "Abr.", + "May": "Mai.", + "Jun": "Jun.", + "Jul": "Jul.", + "Aug": "Ago.", + "Sep": "Sept.", + "Oct": "Oct.", + "Nov": "Nov.", + "Dec": "Des.", + "January": "Gener", + "February": "Febrer", + "March": "Març", + "April": "Abril", + "June": "Juny", + "July": "Juliol", + "August": "Agost", + "September": "Setembre", + "October": "Octubre", + "November": "Novembre", + "December": "Desembre", + "Custom Date Range": "Interval de dates personalitzat", + "Date Range Template": "Plantilla de rang de dates", + "Today": "Avui", + "Yesterday": "Ahir", + "This Week": "Aquesta setmana", + "Last Week": "La setmana passada", + "This Month": "Aquest mes", + "Last Month": "El mes passat", + "Year": "Any", + "This Year": "Aquest any", + "Last Year": "Últim", + "Date picker": "Selector de data", + "Hour": "Hora", + "Day": "Dia", + "Week": "Setmana", + "2 weeks": "2 Setmanes", + "Month": "Mes", + "3 months": "3 Mesos", + "6 months": "6 Mesos", + "Custom interval": "Interval personalitzat", + "Interval": "Interval", + "Step size": "Nombre de passos", + "Ok": "Ok" + } + }, + "entities-hierarchy": { + "hierarchy-data-settings": "Configuració de dades de jerarquia", + "relations-query-function": "Funció d'obtenció de relacions", + "has-children-function": "El node té una funció filla", + "node-state-settings": "Paràmetres estat node", + "node-opened-function": "Funció per defecte en obrir node", + "node-disabled-function": "Funció amb node desactivat", + "display-settings": "Mostrar ajustaments", + "node-icon-function": "Funció d'icona node", + "node-text-function": "Funció de text node", + "sort-settings": "Paràmetres d'ordenació", + "nodes-sort-function": "Funció d'ordenació" + }, + "edge": { + "display-default-title": "Mostrar títol per defecte" + }, + "gateway": { + "general-settings": "Ajustaments generals", + "widget-title": "Títol del widget", + "default-archive-file-name": "Nom del fitxer per defecte", + "device-type-for-new-gateway": "Tipus de dispositiu per a nou gateway", + "messages-settings": "Paràmetres de missatges", + "save-config-success-message": "Missatge d'èxit enregistrant la configuració", + "device-name-exists-message": "Missatge de text quan el nom del dispositiu ja existeixi", + "gateway-title": "Formulari Gateway", + "read-only": "Només lectura", + "events-title": "Títol del formulari d'esdeveniments", + "events-filter": "Filtre d'esdeveniments", + "event-key-contains": "La clau d'esdeveniment conté..." + }, + "gauge": { + "default-color": "Color per defecte", + "radial-gauge-settings": "Paràmetres d'indicador radial", + "ticks-settings": "Ajustaments de ticks", + "min-value": "Valor mínim", + "max-value": "Valor màxim", + "start-ticks-angle": "Angle d'inici ticks", + "ticks-angle": "Angle Ticks", + "major-ticks-count": "Nombre de ticks principals", + "major-ticks-color": "Color Núm. de ticks principals", + "minor-ticks-count": "Nombre de ticks secundaris", + "minor-ticks-color": "Color Núm. de ticks secundaris", + "tick-numbers-font": "Font del tick", + "unit-title-settings": "Paràmetres d'unitat (títol)", + "show-unit-title": "Mostra unitats (títol)", + "unit-title": "Títol d'unitat", + "title-font": "Font de text del títol", + "units-settings": "Ajustaments d'unitats", + "units-font": "Font de text de les unitats", + "value-box-settings": "Paràmetres de valor", + "show-value-box": "Mostrar valor", + "value-int": "Nombre de dígits per a la part sencera del valor", + "value-font": "Font de text del valor", + "value-box-rect-stroke-color": "Color del traç del rectangle (valor)", + "value-box-rect-stroke-color-end": "Color del traç del rectangle (valor) - gradient final", + "value-box-background-color": "Color de fons del valor", + "value-box-shadow-color": "Color d'ombra del valor", + "plate-settings": "Ajustaments de la placa", + "show-plate-border": "Mostra vora de la placa", + "plate-color": "Color de la placa", + "needle-settings": "Paràmetres de l'agulla", + "needle-circle-size": "Mida del cercle de l'agulla", + "needle-color": "Color de l'agulla", + "needle-color-end": "Color de l'agulla - gradient final", + "needle-color-shadow-up": "Color d'ombreig de la meitat superior de l'agulla", + "needle-color-shadow-down": "Color d'ombra de l'agulla", + "highlights-settings": "Ajustaments de ressalt", + "highlights-width": "Amplada del ressalt", + "highlights": "Resalts", + "highlight-from": "De", + "highlight-to": "A", + "highlight-color": "Color", + "no-highlights": "No hi ha ressalts configurats", + "add-highlight": "Afegir ressalt", + "animation-settings": "Paràmetres d'animació", + "enable-animation": "Activar animació", + "animation-duration": "Duració d'animació", + "animation-rule": "Regla d'animació", + "animation-linear": "Lineal", + "animation-quad": "Quad", + "animation-quint": "Quint", + "animation-cycle": "Cicle (cycle)", + "animation-bounce": "Rebot (bounce)", + "animation-elastic": "Elastic", + "animation-dequad": "Dequad", + "animation-dequint": "Dequint", + "animation-decycle": "Decycle", + "animation-debounce": "Debounce", + "animation-delastic": "Delastic", + "linear-gauge-settings": "Paràmetres d'indicador lineal", + "bar-stroke-width": "Amplada del traç", + "bar-stroke-color": "Color del traç", + "bar-background-color": "Color de fons de l'indicador", + "bar-background-color-end": "Color de fons de l'indicador - gradient final", + "progress-bar-color": "Color de la barra de progrés", + "progress-bar-color-end": "Color de la barra de progrés - gradient final", + "major-ticks-names": "Nom de ticks principals", + "show-stroke-ticks": "Mostrar traç de ticks", + "major-ticks-font": "Font de ticks principals", + "border-color": "Color de la vora", + "border-width": "Amplada de la vora", + "needle-circle-color": "Color del cercle de l'agulla", + "animation-target": "Destinació de l'animació", + "animation-target-needle": "Agulla", + "animation-target-plate": "Placa", + "common-settings": "Ajustaments comuns de l'indicador", + "gauge-type": "Tipus d'indicador", + "gauge-type-arc": "Arc", + "gauge-type-donut": "Donut", + "gauge-type-horizontal-bar": "Barra horitzontal", + "gauge-type-vertical-bar": "Barra vertical", + "donut-start-angle": "Angle d'inici", + "bar-settings": "Paràmetres de barra indicadora", + "relative-bar-width": "Amplada relativa", + "neon-glow-brightness": "Efecte brillantor de neó, (0-100), 0 - desactiva efecte", + "stripes-thickness": "Grossor de les ratlles, 0 - sense ratlles", + "rounded-line-cap": "Mostra tapa de línia arrodonida", + "bar-color-settings": "Paràmetres de color de barra", + "use-precise-level-color-values": "Usar nivells precisos de color", + "bar-colors": "Colors de la barra, del més baix al més alt", + "color": "Color", + "no-bar-colors": "No hi ha colors configurats", + "add-bar-color": "Afegir color", + "from": "De", + "to": "A", + "fixed-level-colors": "Colors de barra usant valors límit", + "gauge-title-settings": "Paràmetres de títol de l'indicador", + "show-gauge-title": "Mostra títol d'indicador", + "gauge-title": "Títol d'indicador", + "gauge-title-font": "Font del títol de l'indicador", + "unit-title-and-timestamp-settings": "Paràmetres del títol d'unitats i timestamp", + "show-timestamp": "Mostrar valor timestamp", + "timestamp-format": "Format timestamp", + "label-font": "Font de l'etiqueta que es mostra sota el valor", + "value-settings": "Paràmetres del valor", + "show-value": "Mostra text del valor", + "min-max-settings": "Etiqueta mínim/màxim", + "show-min-max": "Mostra valors mínims i màxims", + "min-max-font": "Font dels valors mínim i màxim", + "show-ticks": "Mostrar ticks", + "tick-width": "Amplada de tick", + "tick-color": "Color de tick", + "tick-values": "Valors de tick", + "no-tick-values": "No hi ha valors configurats", + "add-tick-value": "Afegir valor de tick" + }, + "gpi": { + "pin": "Pin", + "label": "Etiqueta", + "row": "Fila", + "column": "Columna", + "color": "Color", + "panell-settings": "Paràmetres de panell", + "background-color": "Color de fons", + "gpio-switches": "switches GPIO", + "no-gpio-switches": "No hi ha switches GPIO configurats", + "add-gpio-switch": "Afegeix switch GPIO", + "gpio-status-request": "Sol·licitud estat GPIO", + "method-name": "Nom del mètode RPC", + "method-body": "Cos del mètode RPC", + "gpio-status-change-request": "Sol·licitud de canvi d'estat GPIO", + "parse-gpio-status-function": "Funció de parsejat d'estat GPIO", + "gpio-leds": "Leds GPIO", + "no-gpio-leds": "No hi ha Leds GPIO configurats", + "add-gpio-led": "Afegir led GPIO" + }, + "html-card": { + "html": "HTML", + "css": "CSS" + }, + "input-widgets": { + "attribute-not-allowed": "El paràmetre d'atribut no es pot utilitzar aquest widget", + "blocked-location": "La funció de geolocalització està bloquejada al vostre navegador", + "claim-device": "Reclamar dispositiu", + "claim-failed": "Error al reclamar dispositiu!", + "claim-not-found": "Dispositiu no trobat!", + "claim-successful": "Dispositiu reclamat correctament!", + "date": "Data", + "device-name": "Nom del dispositiu", + "device-name-required": "Cal nom de dispositiu", + "discard-changes": "Descartar els canvis", + "entity-attribute-required": "Cal atribut d'entitat", + "entity-coordinate-required": "Cal tots dos camps (latitud i longitud)", + "entity-timeseries-required": "Cal la sèrie del temps de l'entitat", + "get-location": "Obtenir localització actual", + "invalid-date": "Data invàlida", + "latitude": "Latitud", + "longitude": "Longitud", + "min-value-error": "El valor mínim és {{value}}", + "max-value-error": "El valor màxim és {{value}}", + "not-allowed-entity": "La entitat seleccionada no pot tenir atributs compartits", + "no-attribute-selected": "No s'ha seleccionat cap atribut", + "no-datakey-selected": "No s'ha seleccionar cap clau de dades", + "no-coordinate-specified": "No s'ha especificat la clau per latitud/longitud", + "no-entity-selected": "Ninguna entitat seleccionada", + "no-image": "Sense imatge", + "no-support-geolocation": "El teu navegador no suporta geolocalització", + "no-support-web-camera": "No hi ha càmera web compatible", + "enable-https-use-widget": "Per favor, activa HTTPS per poder utilitzar aquest widget", + "no-found-your-camera": "No és possible trobar la càmera", + "no-permission-camera": "Permís denegat per l'usuari / Aquesta pàgina no té permisos per utilitzar la càmera", + "no-timeseries-selected": "No hi ha series del temps seleccionades", + "secret-key": "Clau", + "secret-key-required": "Cal clau", + "switch-attribute-value": "Canviar el valor de l'atribut d'entitat", + "switch-camera": "Canviar de càmera", + "switch-timeseries-value": "Canviar el valor de la sèrie del temps de l'entitat", + "take-photo": "Prendre foto", + "time": "Temps", + "timeseries-not-allowed": "El paràmetre Sèries temporals no es pot utilitzar en aquest widget", + "update-failed": "Actualizació fallida", + "update-successful": "Actualizació exitosa", + "update-attribute": "Actualizar atribut", + "update-timeseries": "Actualizar series del temps", + "general-settings": "Ajustaments Generals", + "widget-title": "Títol del giny", + "claim-button-label": "Etiqueta del botó de reclamar", + "show-secret-key-field": "Mostrar el camp 'Clave Secreta'", + "labels-settings": "Paràmetres d'etiquetes", + "show-labels": "Mostrar etiquetes", + "device-name-label": "Etiqueta per al camp d'entrada 'Nom de dispositiu'", + "secret-key-label": "Etiqueta per al camp d'entrés 'Clave Secreta'", + "messages-settings": "Paràmetres de missatges", + "claim-device-success-message": "Missatge a mostrar quan el dispositiu s'hagi reclamat ok", + "claim-device-not-found-message": "Missatge a mostrar quan el dispositiu no estigui", + "claim-device-failed-message": "Missatge a mostrar quan es produeixi un error reclamant el dispositiu", + "claim-device-name-required-message": "Missatge d'error a mostrar amb 'Nom de dispositiu requerit'", + "claim-device-secret-key-required-message": "Missatge d'error a mostrar amb 'Clave Secreta requerida'", + "show-label": "Mostrar etiqueta", + "label": "Etiqueta", + "required": "Requerit", + "required-error-message": "Error a mostrar amb camp 'Requerit'", + "show-result-message": "Missatge per mostrar resultat", + "integer-field-settings": "Paràmetres de camps sencers", + "min-value": "Valor Mínim", + "max-value": "Valor Màxim", + "double-field-settings": "Paràmetres de camps tipus double", + "text-field-settings": "Paràmetres de camp tipus text", + "min-length": "Longitud mínima", + "max-length": "Longitud màxima", + "checkbox-settings": "Paràmetres de camp tipus checkbox", + "true-label": "Etiqueta checked", + "false-label": "Etiqueta unchecked", + "image-input-settings": "Paràmetres de camp tipus d'imatge", + "display-preview": "Mostrar previsualització", + "display-clear-button": "Mostrar botó d'esborrar", + "display-apply-button": "Mostrar botó d'aplicar", + "display-discard-button": "Mostrar botó de descartar", + "datetime-field-settings": "Paràmetres de camp tipus Data/Hora", + "display-time-input": "Mostra l'entrada d'hora", + "latitude-key-name": "Nom clau latitud", + "longitude-key-name": "Nom clau longitud", + "show-get-location-button": "Mostrar botó 'Obtenir localització actual'", + "use-high-accuracy": "Usar alta precisió", + "location-fields-settings": "Paràmetres de camps de localització", + "latitude-label": "Etiqueta per a latitud", + "longitude-label": "Etiqueta per a longitud", + "input-fields-alignment": "Alineat de camps d'entrada", + "input-fields-alignment-column": "Columna (per defecte)", + "input-fields-alignment-row": "Fila", + "latitude-field-required": "Camp latitud requerit", + "longitude-field-required": "Camp longitud requerit", + "attribute-settings": "Paràmetres d'atributs", + "widget-mode": "Mode del giny", + "widget-mode-update-attribute": "Actualitzar atribut", + "widget-mode-update-timeseries": "Actualitzar timeseries", + "attribute-scope": "Abast d'atributs", + "attribute-scope-server": "Atributs de servidor", + "attribute-scope-shared": "Atributs compartits", + "value-required": "Valor requerit", + "image-settings": "Paràmetres d'imatge", + "image-format": "Format d'imatge", + "image-format-jpeg": "JPEG", + "image-format-png": "PNG", + "image-format-webp": "WEBP", + "image-quality": "Qualitat d'imatge que utilitza compressió amb pèrdua com jpeg i webp", + "max-image-width": "Màxim ample d'imatge", + "max-image-height": "Màxim alt d'imatge", + "action-buttons": "Botons d'acció", + "show-action-buttons": "Mostra botons d'acció", + "update-all-values": "Actualitzar tots els valors, no només els modificats", + "save-button-label": "Etiqueta de botó 'GRAVAR'", + "reset-button-label": "Etiqueta de botó 'DESFER'", + "group-settings": "Paràmetres de grup", + "show-group-title": "Mostrar títol per al grup de camps relacionats amb diferents entitats", + "group-title": "Títol del grup", + "fields-alignment": "Alineat de camps", + "fields-alignment-row": "Fila (per defecte)", + "fields-alignment-column": "Columna", + "fields-in-row": "Nombre de camps a la fila", + "option-value": "Valor (escriu 'null' per crear una opció buida)", + "option-label": "Etiqueta", + "hide-input-field": "Amagar camp d'entrada", + "datakey-type": "Tipus de clau de dades", + "datakey-type-server": "Atribut de servidor (per defecte)", + "datakey-type-shared": "Atribut compartit", + "datakey-type-timeseries": "Timeseries", + "datakey-value-type": "Tipus de valor de la clau de dades", + "datakey-value-type-string": "String", + "datakey-value-type-double": "Double", + "datakey-value-type-integer": "Enter", + "datakey-value-type-boolean-checkbox": "Boolean (Checkbox)", + "datakey-value-type-boolean-switch": "Boolean (Switch)", + "datakey-value-type-date-time": "Data & Hora", + "datakey-value-type-date": "Data", + "datakey-value-type-time": "Hora", + "datakey-value-type-select": "Selecció", + "value-is-required": "Valor requerit", + "ability-to-edit-attribute": "Possibilitat d'editar atribut", + "ability-to-edit-attribute-editable": "Editable (per defecte)", + "ability-to-edit-attribute-disabled": "Desactivat", + "ability-to-edit-attribute-readonly": "Només lectura", + "disable-on-datakey-name": "Desactivar quan una altra clau de dades sigui false (especifiqueu el nom de clau de dades)", + "slide-toggle-settings": "Configuració del botó lliscant", + "slide-toggle-label-position": "Posició d'etiqueta", + "slide-toggle-label-position-after": "Després", + "slide-toggle-label-position-before": "Abans", + "select-options": "Seleccionar opcions", + "no-select-options": "No hi ha opcions configurades", + "add-select-option": "Afegir opció", + "numeric-field-settings": "Paràmetres de camps numèrics", + "step-interval": "Passos entre valors (interval)", + "error-messages": "Missatges d'erro", + "min-value-error-message": "Missatge d'error de 'Valor Mínim'", + "max-value-error-message": "Missatge d'error de 'Valor Màxim'", + "invalid-date-error-message": "Missatge d'error de 'Data Invàlida'", + "icon-settings": "Configuració d'icones", + "use-custom-icon": "Usar icona personalitzada", + "input-cell-icon": "Icona a mostrar abans del camp d'entrada", + "value-conversion-settings": "Paràmetres de conversió de valor", + "get-value-settings": "Paràmetres d'obtenció de valors", + "use-get-value-function": "Fer servir getValue", + "get-value-function": "Funció getValue", + "set-value-settings": "Paràmetres d'establiment de valors", + "use-set-value-function": "Usar funció setValue", + "set-value-function": "Funció setValue" + }, + "qr-code": { + "use-qr-code-text-function": "Utilitzar funció de text QR", + "qr-code-text-pattern": "Patró del codi QR (per ex. '${entityName} | ${keyName} - text addicional.')", + "qr-code-text-pattern-required": "Es requereix patró del codi QR.", + "qr-code-text-function": "Funció del codi QR" + }, + "label-widget": { + "label-pattern": "Patró", + "label-pattern-hint": "Ajuda: ex. 'Text ${keyName} unitats.' o ${#<key index>} ; unitats'", + "label-pattern-required": "Es requereix patró", + "label-position": "Posició (Percentatge relatiu al fons)", + "x-pos": "X", + "i-pos": "Y", + "background-color": "Color de fons", + "font-settings": "Paràmetres de font", + "background-image": "Imatge de fons", + "labels": "Etiquetes", + "no-labels": "No hi ha etiquetes configurades", + "add-label": "Afegir etiqueta" + }, + "navigation": { + "title": "Títol", + "navigation-path": "Ruta de navegació", + "filter-type": "Tipus de filtre", + "filter-type-all": "Tots els objectes", + "filter-type-include": "Incloure objectes", + "filter-type-exclude": "Excloure objectes", + "items": "Objectes", + "enter-urls-to-filter": "Especificar URLs a filtrar..." + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "Tipus de missatge", + "method": "Mètode", + "params": "Paràmetres", + "created-time": "Temps creat", + "expiration-time": "Temps de caducitat", + "retries": "Reintents", + "status": "Estat", + "filter": "Filtre", + "refresh": "Actualització", + "add": "Cal afegeix RPC ", + "details": "Detalls", + "delete": "Suprimeix", + "delete-request-title": "Cal suprimir RPC persistent", + "delete-request-text": "Esteu segur que voleu suprimir la sol·licitud?", + "details-title": "Detalls RPC ID: ", + "additional-info": "Informació addicional", + "response": "Resposta", + "any-status": "Qualsevol estat", + "rpc-status-list": "Llista d'estats RPC", + "no-request-prompt": "No hi ha cap sol·licitud per mostrar", + "send-request": "Enviar sol·licitud", + "add-title": "Crea una sol·licitud RPC persistent", + "method-error": "Cal mètode.", + "timeout-error": "El valor mínim de temps d'espera és 5000 (5 segons).", + "white-space-error": "No es permet l'espai en blanc.", + "rpc-status": { + "QUEUED": "A LA CUA", + "SENT": "ENVIAT", + "DELIVERED": "LLIURAT", + "SUCCESSFUL": "ÈXIT", + "TIMEOUT": "TEMPS D'EXPLORACIÓ", + "EXPIRED": "CADUCAT", + "FAILED": "FALLADA" + }, + "rpc-search-status-all": "TOTS", + "message-types": { + "false": "Bidireccional", + "true": "Una direcció" + }, + "general-settings": "Ajustaments Generals", + "enable-filter": "Activar filtre", + "enable-sticky-header": "Mostrar encapçalat mentre es fa scroll", + "enable-sticky-action": "Mostra columna d'accions mentre es fa scroll", + "display-request-details": "Mostrar detalls de petició", + "allow-send-request": "Permetre enviar petició RPC", + "allow-delete-request": "Permetre esborrar petició", + "columns-settings": "Paràmetres de columnes", + "display-columns": "Columnes per mostrar", + "column": "Columna", + "no-columns-found": "No s'han trobat columnes", + "no-columns-matching": "'{{column}}' no trobada." + }, + "rpc": { + "value-settings": "Paràmetres de valor", + "initial-value": "Valor inicial", + "retrieve-value-settings": "Obtenir ajustaments valors on/off", + "retrieve-value-method": "Obtenir valor usant mètode", + "retrieve-value-method-none": "No obtenir", + "retrieve-value-method-rpc": "Mètode per a anomenada RPC d'obtenció de valor", + "retrieve-value-method-attribute": "Subscriure per atribut", + "retrieve-value-method-timeseries": "Subscriure per timeseries", + "attribute-value-key": "Clau d'atribut", + "timeseries-value-key": "Clau de timeseries", + "get-value-method": "Mètode per obtenir valor via RPC", + "parse-value-function": "Funció de parseig de valor", + "update-value-settings": "Paràmetres d'actualització de valor", + "set-value-method": "Mètode per establir valor via RPC", + "convert-value-function": "Funció de conversió", + "rpc-settings": "Paràmetres RPC", + "request-timeout": "Timeout de petició RPC (ms)", + "persistent-rpc-settings": "Paràmetres de RPC persistent", + "request-persistent": "Petició RPC persistent", + "persistent-polling-interval": "Interval de sondeig (ms) per obtenir resposta de l'ordre RPC persistent", + "common-settings": "Ajustaments comuns", + "switch-title": "Títol del switch", + "show-on-off-labels": "Mostrar etiquetes on/off", + "slide-toggle-label": "Etiqueta d'interruptor lliscant", + "label-position": "Posició d'etiqueta", + "label-position-before": "Abans", + "label-position-after": "Després", + "slider-color": "Color del botó lliscant", + "slider-color-primary": "Primari", + "slider-color-accent": "Accent", + "slider-color-warn": "Avís", + "button-style": "Estil de botó", + "button-raised": "Botó aixecat", + "button-primary": "Color primari", + "button-background-color": "Color de fons", + "button-text-color": "Color de text", + "widget-title": "Títol del giny", + "button-label": "Etiqueta del botó", + "device-attribute-scope": "Abast d'atributs del dispositiu", + "server-attribute": "Atributs de servidor", + "shared-attribute": "Atributs compartits", + "device-attribute-parameters": "Paràmetres d'atributs del dispositiu", + "is-one-way-command": "És una ordre d'una via (one way)", + "rpc-method": "Mètode RPC", + "rpc-method-params": "Paràmetres mètode RPC", + "show-rpc-error": "Mostra errors d'execució de RPC", + "led-title": "Títol LED", + "led-color": "Color LED", + "check-status-settings": "Paràmetres de comprovació d'estat", + "perform-rpc-status-check": "Realitzar comprovació del dispositiu RPC", + "retrieve-led-status-value-method": "Obtenir estat del led usant mètode", + "led-status-value-attribute": "Atribut del dispositiu que conté el valor de l'estat del led", + "led-status-value-timeseries": "Timeseries del dispositiu que conté el valor de l'estat del led", + "check-status-method": "Mètode RPC per revisar l'estat del dispositiu", + "parse-led-status-value-function": "Funció de parseig per a l'estat del led", + "knob-title": "Títol de comandament", + "min-value": "Valor mínim", + "max-value": "Valor màxim" + }, + "maps": { + "select-entity": "Seleccioneu l'entitat", + "select-entity-hint": "Consell: després de la selecció, feu clic al mapa per establir la posició", + "tooltips": { + "placeMarker": "Feu clic per col·locar-lo '{{entityName}}' entitat", + "firstVertex": "Polígon per '{{entityName}}': feu clic per col·locar el primer punt", + "firstVertex-cut": "Click to place first point", + "continueLine": "Polígon per '{{entityName}}': feu clic per continuar dibuixant", + "continueLine-cut": "Feu clic per continuar dibuixant", + "finishLine": "Feu clic a qualsevol marcador existent per acabar", + "finishPoly": "Polígon per '{{entityName}}': feu clic al primer marcador per acabar i desar", + "finishPoly-cut": "Feu clic al primer marcador per acabar i desar", + "finishRect": "Polígon per '{{entityName}}': feu clic per acabar i desar", + "startCircle": "Cercle per '{{entityName}}': feu clic per col·locar el centre del cercle", + "finishCircle": "Cercle per '{{entityName}}': feu clic per acabar el cercle", + "placeCircleMarker": "Feu clic per col·locar el marcador de cercle" + }, + "actions": { + "finish": "Acabar", + "cancel": "Cancel·lar", + "removeLastVertex": "Elimina l'últim punt" + }, + "buttonTitles": { + "drawMarkerButton": "Entitat de lloc", + "drawPolyButton": "Crea un polígon", + "drawLineButton": "Crear polilínia", + "drawCircleButton": "Crea un cercle", + "drawRectButton": "Crea un rectangle", + "editButton": "Mode d'edició", + "dragButton": "Mode arrossegar i deixar anar", + "cutButton": "Retalla l'àrea del polígon", + "deleteButton": "Eliminar", + "drawCircleMarkerButton": "Crea un marcador de cercle", + "rotateButton": "Gira el polígon" + }, + "map-provider-settings": "Paràmetres proveïdor de mapes", + "map-provider": "Proveïdor de mapes", + "map-provider-google": "Google maps", + "map-provider-openstreet": "OpenStreet maps", + "map-provider-here": "HERE maps", + "map-provider-image": "Mapa d'imatge", + "map-provider-tencent": "Tencent maps", + "openstreet-provider": "Proveïdor OpenStreet map", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (Default)", + "openstreet-provider-hot": "OpenStreetMap.HOT", + "openstreet-provider-esri-street": "Esri.WorldStreetMap", + "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-cartodb-positron": "CartoDB.Positron", + "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", + "use-custom-provider": "Usar proveïdor personalitzat", + "custom-provider-tile-url": "URL de proveïdor personalitzat", + "google-maps-api-key": "API Key Google Maps", + "default-map-type": "Tipus de mapa per defecte", + "google-map-type-roadmap": "Carretera", + "google-map-type-satelite": "Satelite", + "google-map-type-hybrid": "Híbrid", + "google-map-type-terrain": "Terreny", + "map-layer": "Capa de mapa", + "here-map-normal-day": "HERE.normalDay (Defecte)", + "here-map-normal-night": "HERE.normalNight", + "here-map-hybrid-day": "HERE.hybridDay", + "here-map-terrain-day": "HERE.terrainDay", + "credentials": "Credencials", + "here-app-id": "HERE app id", + "here-app-code": "HERE app code", + "tencent-maps-api-key": "API Key Tencent Maps", + "tencent-map-type-roadmap": "Carretera", + "tencent-map-type-satelite": "Satelite", + "tencent-map-type-hybrid": "Híbrid", + "image-map-background": "Fons de mapa d'imatge", + "image-map-background-from-entity-attribute": "Obtenir imatge de fons des d'un atribut de l'entitat", + "image-url-source-entity-alias": "Àlies importants per a URL d'imatge", + "image-url-source-entity-attribute": "Atribut d'entitat per a URL d'imatge", + "common-map-settings": "Paràmetres comuns de mapes", + "x-pos-key-name": "Clau per a posició X", + "y-pos-key-name": "Clau per a posició I", + "latitude-key-name": "Clau per a latitud", + "longitude-key-name": "Clau per a longitud", + "default-map-zoom-level": "Nivell de zoom per defecte (0 - 20)", + "default-map-center-position": "Posició central del mapa per defecte (0,0)", + "disable-scroll-zooming": "Desactivar zoom a scroll", + "disable-zoom-control-buttons": "Desactivar botons de zoom", + "fit-map-bounds": "Ajustar els límits del mapa per cobrir tots els marcadors", + "use-default-map-center-position": "Usar posició central per defecte", + "entities-limit": "Límit d'entitats a carregar", + "markers-settings": "Paràmetres dels marcadors", + "marker-offset-x": "Offset X relatiu a la posició multiplicada per l'amplada del marcador", + "marker-offset-y": "Offset I relatiu a la posició multiplicat per l'alt del marcador", + "position-function": "Funció de conversió de posició, ha de retornar coordenades x,i com a valor double de 0 a 1", + "draggable-marker": "Marcador arrossegable", + "label": "Etiqueta", + "show-label": "Mostrar etiqueta", + "use-label-function": "Usar funció d'etiqueta", + "label-pattern": "Etiqueta (Exemples de patró: '${entityName}', '${entityName}: (Text ${keyName} unitats.)' )", + "label-function": "Funció d'etiqueta", + "tooltip": "Suggeriments (tooltip)", + "show-tooltip": "Mostrar suggeriments", + "show-tooltip-action": "Acció per mostrar els suggeriments", + "show-tooltip-action-click": "Mostrar suggeriments tooltip a click (per defecte)", + "show-tooltip-action-hover": "Mostrar suggeriments on hover", + "auto-close-tooltips": "Auto-tancar suggeriments", + "use-tooltip-function": "Funció de suggeriments", + "tooltip-pattern": "Suggeriment (per ex. 'Text ${keyName} unitats.' o Text Link')", + "tooltip-function": "Funció de suggeriment", + "tooltip-offset-x": "Offset X relatiu a l'àncora del marcador multiplicat per l'amplada", + "tooltip-offset-y": "Offset I relatiu a l'àncora del marcador multiplicat per l'alçada", + "color": "Color", + "use-color-function": "Utilitzar funció de color", + "color-function": "Funció de color", + "marker-image": "Imatge de marcador", + "use-marker-image-function": "Usar funció d'imatge de marcador", + "custom-marker-image": "Imatge de marcador personalitzada", + "custom-marker-image-size": "Mida d'imatge personalitzada (px)", + "marker-image-function": "Funció d'imatge de marcador", + "marker-images": "Imatges de marcador", + "polygon-settings": "Paràmetres de polígon", + "show-polygon": "Mostrar polígon", + "polygon-key-name": "Clau del polígon", + "enable-polygon-edit": "Polígon editabli", + "polygon-label": "Etiqueta del polígon", + "show-polygon-label": "Mostra etiqueta del polígon", + "use-polygon-label-function": "Utilitzar funcions d'etiqueta al polígon", + "polygon-label-pattern": "Etiqueta del polígon (Exemples de patró: '${entityName}', '${entityName}: (Text ${keyName} unitats.)' )", + "polygon-label-function": "Funció d'etiqueta del polígon", + "polygon-tooltip": "Suggeriment polígon", + "show-polygon-tooltip": "Mostrar suggeriments", + "auto-close-polygon-tooltips": "Auto-tancar suggeriments polígon", + "use-polygon-tooltip-function": "Utilitzar funció de suggeriments al polígon", + "polygon-tooltip-pattern": "Suggeriments (per ex. 'Text ${keyName} unitats.' o Text Link')", + "polygon-tooltip-function": "Funció de suggeriment de polígon", + "polygon-color": "Color de polígon", + "polygon-opacity": "Opacitat de polígon", + "use-polygon-color-function": "Utilitzar funció de color al polígon", + "polygon-color-function": "Funció de color de polígon", + "polygon-stroke": "Traç de polígon", + "stroke-color": "Color de traç", + "stroke-opacity": "Opacitat de traç", + "stroke-weight": "Pes de traç", + "use-polygon-stroke-color-function": "Utilitzar funció de color de traç al polígon", + "polygon-stroke-color-function": "Funció de color de traç", + "circle-settings": "Ajustaments de cercle", + "show-circle": "Mostrar cercle", + "circle-key-name": "Clau de cercle", + "enable-circle-edit": "Activar edició de cercle", + "circle-label": "Etiqueta de cercle", + "show-circle-label": "Mostra etiqueta de cercle", + "use-circle-label-function": "Utilitzar funció per a l'etiqueta de cercle", + "circle-label-pattern": "Etiqueta de cercle (Exemples patró: '${entityName}', '${entityName}: (Text ${keyName} unitats.)' )", + "circle-label-function": "Funció d'etiqueta de cercle", + "cercle-tooltip": "Suggeriments de cercle", + "show-circle-tooltip": "Mostrar suggeriments de cercle", + "auto-close-circle-tooltips": "Auto-tancar suggeriments", + "use-circle-tooltip-function": "Utilitzar funció de suggeriments en cercle", + "circle-tooltip-pattern": "Suggeriment (per ex. 'Text ${keyName} unitats.' o Text Link')", + "circle-tooltip-function": "Funció de suggeriment cercle", + "cercle-fill-color": "Color de farciment cercle", + "circle-fill-color-opacity": "Opacitat color de farciment", + "use-circle-fill-color-function": "Fer servir funció de color de farciment", + "circle-fill-color-function": "Funció de color de farciment", + "circle-stroke": "Traç del cercle", + "use-circle-stroke-color-function": "Fer servir funció de color de traç", + "circle-stroke-color-function": "Funció de color de traç", + "markers-clustering-settings": "Paràmetres d'agrupació de marcadors", + "use-map-markers-clustering": "Usar agrupació de marcadors al mapa", + "zoom-on-cluster-click": "Zoom quan es faci clic en un grup", + "max-cluster-zoom": "Nivell màxim de zoom en què un marcador pot ser part d'un grup (0 - 18)", + "max-cluster-radius-pixels": "Ràdio màxim que un grup cobreix en píxels", + "cluster-zoom-animation": "Mostrar animació en marcadors quan es faci zoom", + "show-markers-bounds-on-cluster-mouse-over": "Mostrar els límits dels marcadors quan el ratolí passi per sobre d'un grup", + "spiderfy-max-zoom-level": "Spiderfy al màxim nivell de zoom (per veure tots els marcadors)", + "load-optimization": "Optimització de càrrega", + "cluster-chunked-loading": "Fer servir fragments per afegir marcadors perquè la pàgina no es congeli", + "cluster-markers-lazy-load": "Utilitzeu lazy load en afegir marcadors", + "editor-settings": "Paràmetres de l'editor", + "enable-snapping": "Habilitar ajustament a altres vèrtexs per dibuixar amb precisió", + "init-draggable-mode": "Inicialitzar mapa en mode arrossegament", + "hide-all-edit-buttons": "Amagar tots els botons d'edició", + "hide-draw-buttons": "Ocultar botons de dibuix", + "hide-edit-buttons": "Amagar botons d'edició", + "hide-remove-button": "Amagar botons d'esborrat", + "route-map-settings": "Paràmetres de mapa de ruta", + "trip-animation-settings": "Paràmetres d'animació de ruta", + "normalization-step": "Passos de normalització (ms)", + "tooltip-background-color": "Color de fons del suggeriment", + "tooltip-font-color": "Color de font dels suggeriments", + "tooltip-opacity": "Opacitat dels suggeriments (0-1)", + "auto-close-tooltip": "Auto-tancar suggeriments", + "rotation-angle": "Angle de rotació addicional per al marcador (graus)", + "path-settings": "Paràmetres de ruta", + "path-color": "Color de ruta", + "use-path-color-function": "Utilitzar funció de color de ruta", + "path-color-function": "Funció de color de ruta", + "path-decorator": "Decorador de ruta", + "use-path-decorator": "Utilitzar decorador de ruta", + "decorator-symbol": "Símbol del decorador", + "decorator-symbol-arrow-head": "Fletxa", + "decorator-symbol-dash": "Estrella", + "decorator-symbol-size": "Mida del decorador (px)", + "use-path-decorator-custom-color": "Usar color personalitzat al decorador", + "decorator-custom-color": "Color personalitzat del decorador", + "decorator-offset": "Offset decorador", + "end-decorator-offset": "Offset final del decorador", + "decorator-repeat": "Repetició del decorador", + "points-settings": "Ajustaments de punts", + "show-points": "Mostrar punts", + "point-color": "Color de punts", + "point-size": "Mida de punts (px)", + "use-point-color-function": "Utilitzar funció de color de punts", + "point-color-function": "Funció de color de punts", + "use-point-as-anchor": "Usar punt com àncora", + "point-as-anchor-function": "Funció de punt com a àncora", + "independent-point-tooltip": "Suggeriment independent en punt" + }, + "markdown": { + "use-markdown-text-function": "Fer servir markdown/HTML", + "markdown-text-function": "Funció de valor Markdown/HTML", + "markdown-text-pattern": "Patró de Markdown/HTML (markdown o HTML amb variables, per ex. '${entityName} o ${keyName} - text.')", + "markdown-css": "Markdown/HTML CSS" + }, + "simple-card": { + "label-position": "Posició etiqueta", + "label-position-left": "Esquerra", + "label-position-top": "Superior" + }, + "table": { + "common-table-settings": "Ajustaments comuns en taules", + "enable-search": "Activar cerca", + "enable-sticky-header": "Mostrar sempre la capçalera", + "enable-sticky-action": "Mostra sempre la columna d'accions", + "hidden-cell-button-display-mode": "Visualització de botons d'acció oculta", + "show-empty-space-hidden-action": "Mostrar espai buit en lloc de cel·la oculta", + "dont-reserve-space-hidden-action": "No reserveu espai per als botons en cel·la oculta", + "display-timestamp": "Mostra columna timestamp", + "display-milliseconds": "Mostrar mil·lisegons", + "display-pagination": "Mostrar pàgines", + "default-page-size": "Mida de pàgina per defecte", + "use-entity-label-tab-name": "Usar etiqueta important al nom de la taula", + "hide-empty-lines": "Ocultar línies buides", + "row-style": "Estil de fila", + "use-row-style-function": "Utilitzar funció d'estil de fila", + "row-style-function": "Funció d'estil de fila", + "cell-style": "Estil de cel·la", + "use-cell-style-function": "Utilitzar funció d'estil de cel·la", + "cell-style-function": "Funció d'estil de cel·la", + "cell-content": "Contingut de cel·la", + "use-cell-content-function": "Utilitzar funció de contingut de cel·la", + "cell-content-function": "Funció de contingut de cel·la", + "show-latest-data-column": "Mostra columna de darreres dades", + "latest-data-column-order": "Ordre de columna d'últimes dades", + "entities-table-title": "Títol de taula d'entitats", + "enable-select-column-display": "Activar possibilitat de seleccionar columnes a mostrar", + "display-entity-name": "Mostra columna de nom important", + "entity-name-column-title": "Títol de columna en nom d'entitat", + "display-entity-label": "Mostra columna d'etiqueta important", + "entity-label-column-title": "Títol de columna a l'etiqueta important", + "display-entity-type": "Mostra columna de tipus important", + "default-sort-order": "Ordenació per defecte", + "column-width": "Amplada de columna (px o %)", + "default-column-visibility": "Visibilitat per defecte a columna", + "column-visibility-visible": "Visible", + "column-visibility-hidden": "Oculta", + "column-selection-to-display": "Selecció de columnes a 'Columnes a Mostra'", + "column-selection-to-display-enabled": "Activada", + "column-selection-to-display-disabled": "Desactivada", + "alarms-table-title": "Títol de taula d'alarmes", + "enable-alarms-selection": "Activar selecció d'alarmes", + "enable-alarms-search": "Activar cerca d'alarmes", + "enable-alarm-filter": "Activar filtre d'alarmes", + "display-alarm-details": "Mostra detalls d'alarma", + "allow-alarms-ack": "Permetre reconeixement d'alarmes", + "allow-alarms-clear": "Permetre esborrat d'alarmes" + }, + "value-source": { + "value-source": "Origen valor", + "predefined-value": "Valor predefinit", + "entity-attribute": "Valor pres d'un atribut important", + "value": "Valor", + "source-entity-alias": "Àlies entitat d'origen", + "source-entity-attribute": "Atribut entitat d'origen" + }, + "widget-font": { + "font-family": "Família (font family)", + "size": "Mida", + "relative-font-size": "Mida font relativa (percentatge)", + "font-style": "Estil", + "font-style-normal": "Normal", + "font-style-italic": "Cursiva", + "font-style-oblique": "Subratllada", + "font-weight": "Pes", + "font-weight-normal": "Normal", + "font-weight-bold": "Negreta", + "font-weight-bolder": "Negreta+", + "font-weight-lighter": "Lighter", + "color": "Color", + "shadow-color": "Color ombra" + }, + "subscription": { + "entity-limit-text": "Tanmateix, podeu actualitzar el vostre pla de subscripció per augmentar els vostres límits.", + "upgrade-your-plan": "Actualitza el pla de subscripció", + "white-labeling-feature": "Característica d'etiqueta blanca", + "white-labeling-text-full": "Canvia la marca de la interfície web de la plataforma ThingsBoard amb el logotip i l'esquema de colors de la teva empresa o producte en 2 minuts.

              Elimineu 'Powered By' al peu de pàgina del tauler.
              No cal codificar ni reiniciar el servei. Permet als vostres clients també marcar en blanc la seva interfície.", + "enable-white-labeling": "Activa ara la funció d'etiqueta blanca actualitzant el teu pla de subscripció!", + "read-more": "Read more", + "white-labeling-video-text": "Vegeu el vídeo tutorial a continuació per veure com funciona aquesta funció!" + }, + "subscription-error": { + "title": "Incompliment de la subscripció", + "warning-title": "Avís de subscripció", + "upgrade-subscription-plan": "Si us plau, actualitzeu el vostre pla de subscripció", + "upgrade-subscription-plan-to-install-solution-template": "Per tal d'instal·lar {{solutionTemplateName}} solució, heu d'actualitzar la vostra subscripció almenys al {{planName}} pla!", + "limit-reached": { + "device-count": "Heu arribat al màxim de dispositius ({{value}}) permisos per al vostre pla de subscripció!", + "asset-count": "Heu assolit el màxim d'actius ({{value}}) permisos per al vostre pla de subscripció!" + } + } + }, + "icon": { + "icon": "Icona", + "select-icon": "Seleccionar icones", + "material-icons": "Icones material-disseny", + "show-all": "Mostrar totes les icones" + }, + "phone-input": { + "phone-input-label": "Número de telèfon", + "phone-input-required": "Cal número de telèfon", + "phone-input-validation": "El número és invàlid o erroni", + "phone-input-pattern": "Número invàlid. Ha de cumplir el format E.164, ej. {{phoneNumber}}", + "phone-input-hint": "Número en el format E.164, ej. {{phoneNumber}}" + }, + "custom": { + "widget-action": { + "action-cell-button": "Acció botó de cel·la", + "row-click": "En clic de fila", + "polygon-click": "Clic al polígon", + "marker-click": "En clic de marcador", + "circle-click": "Al cercle clic", + "tooltip-tag-action": "Acció de l'etiqueta Tooltip", + "node-selected": "Clic en el node seleccionat", + "element-click": "Clic en el element HTML", + "pie-slice-click": "Clic en la porció", + "row-double-click": "Doble clic en la fila" + } + }, + "language": { + "language": "Llenguatge" + } +} diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json new file mode 100644 index 0000000000..6200b26ce7 --- /dev/null +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -0,0 +1,4002 @@ +{ + "access": { + "unauthorized": "Uautoriseret", + "unauthorized-access": "Uautoriseret adgang", + "unauthorized-access-text": "Du skal logge ind for at få adgang til denne ressource!", + "access-forbidden": "Adgang forbudt", + "access-forbidden-text": "Du har ikke adgangsrettigheder til denne placering!
              Prøv at logge ind med en anden bruger, hvis du stadig ønsker at få adgang til denne placering.", + "refresh-token-expired": "Sessionen er udløbet", + "refresh-token-failed": "Kunne ikke opdatere session", + "permission-denied": "Tilladelse nægtet", + "permission-denied-text": "Du har ikke tilladelse til at udføre denne handling!" + }, + "action": { + "activate": "Aktivér", + "suspend": "Udsæt", + "save": "Gem", + "saveAs": "Gem som", + "cancel": "Annuller", + "ok": "Okay", + "delete": "Slet", + "add": "Tilføj", + "yes": "Ja", + "no": "Nej", + "update": "Opdatering", + "remove": "Fjern", + "search": "Søg", + "clear-search": "Ryd søgning", + "assign": "Tildel", + "unassign": "Fjern tildeling", + "share": "Del", + "make-private": "Gør privat", + "make-public": "Gør offentlig", + "apply": "Anvend", + "apply-changes": "Anvend ændringer", + "edit-mode": "Redigeringstilstand", + "enter-edit-mode": "Gå til redigeringstilstand", + "decline-changes": "Afvis ændringer", + "open": "Åbn", + "close": "Tæt", + "back": "Tilbage", + "run": "Kør", + "sign-in": "Log på!", + "edit": "Rediger", + "view": "Vis", + "create": "Opret", + "drag": "Træk", + "refresh": "Genopfrisk", + "undo": "Fortryd", + "copy": "Kopiér", + "paste": "Sæt ind", + "copy-reference": "Kopiér reference", + "paste-reference": "Indsæt reference", + "import": "Importér", + "export": "Eksportér", + "share-via": "", + "move": "Flyt", + "select": "Vælg", + "continue": "Fortsæt", + "discard-changes": "Kassér ændringer", + "download": "Download", + "next-with-label": "", + "read-more": "Læs mere", + "hide": "Skjul" + }, + "aggregation": { + "aggregation": "Opsamling", + "function": "Dataopsamlingsfunktion", + "limit": "Maks.-værdier", + "group-interval": "Grupperingsinterval", + "min": "Min", + "max": "Maks", + "avg": "Gennemsnit", + "sum": "I alt", + "count": "Sammentælling", + "none": "Ingen" + }, + "admin": { + "general": "Generelt", + "general-settings": "Generelle indstillinger", + "home-settings": "Hjem-indstillinger", + "outgoing-mail": "Mailserver", + "outgoing-mail-settings": "Udgående mailserverindstillinger", + "system-settings": "Systemindstillinger", + "test-mail-sent": "Test-e-mail blev sendt!", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL er påkrævet.", + "prohibit-different-url": "Det er ikke tilladt at bruge værtsnavn fra overskrifterne for klientanmodninger", + "prohibit-different-url-hint": "Denne indstilling skal aktiveres for produktionsmiljøer. Kan forårsage sikkerhedsproblemer ved deaktivering", + "mail-from": "Afsender", + "mail-from-required": "Afsender er påkrævet.", + "smtp-protocol": "SMTP-protokol", + "smtp-host": "SMTP-vært", + "smtp-host-required": "SMTP-vært er påkrævet.", + "smtp-port": "SMTP-port", + "smtp-port-required": "Du skal angive en smtp-port.", + "smtp-port-invalid": "Det ligner ikke en gyldig smtp-port.", + "timeout-msec": "Timeout (msek.)", + "timeout-required": "Timeout er påkrævet.", + "timeout-invalid": "Det ser ikke ud til at være en gyldig timeout.", + "enable-tls": "Aktivér TLS", + "tls-version": "TLS-version", + "enable-proxy": "Aktivér proxy", + "proxy-host": "Proxy-vært", + "proxy-host-required": "Proxy-vært er påkrævet.", + "proxy-port": "Proxy-port", + "proxy-port-required": "Proxy-port er påkrævet.", + "proxy-port-range": "Proxy-porten skal ligge i området fra 1 til 65535.", + "proxy-user": "Proxy-bruger", + "proxy-password": "Proxy-adgangskode", + "send-test-mail": "Send testmail", + "use-system-mail-settings": "Brug systemets mailserverindstillinger", + "mail-templates": "Mailskabeloner", + "mail-template-settings": "Indstillinger for mailskabeloner", + "use-system-mail-template-settings": "Brug systemmailskabeloner", + "mail-template": { + "mail-template": "Mailskabelon", + "test": "Test-e-mailmeddelelse", + "activation": "Meddelelse om aktivering af konto", + "account-activated": "Meddelelse om aktiveret konto", + "account-lockout": "Meddelelse om kontospærring", + "reset-password": "Meddelelse om nulstilling af adgangskode", + "password-was-reset": "Meddelelse om nulstillet adgangskode", + "user-activated": "Brugeraktiveret-meddelelse", + "user-registered": "Brugerregistreret-meddelelse", + "api-usage-state-enabled": "Api-brugstilstand aktiveret", + "api-usage-state-warning": "Advarsel om Api-brugstilstand", + "api-usage-state-disabled": "Api-brugstilstand deaktiveret" + }, + "mail-subject": "Mailens emne", + "mail-body": "Mailens brødtekst", + "sms-provider": "SMS-udbyder", + "sms-provider-settings": "Indstillinger for SMS-udbyder", + "use-system-sms-settings": "Anvend systemets indstillinger for SMS-udbyder", + "sms-provider-type": "SMS-udbydertype", + "sms-provider-type-required": "SMS-udbydertype er påkrævet.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "aws-access-key-id": "AWS-adgangsnøgle-id", + "aws-access-key-id-required": "AWS-adgangsnøgle-id er påkrævet", + "aws-secret-access-key": "AWS hemmelig adgangsnøgle", + "aws-secret-access-key-required": "AWS hemmelig adgangsnøgle er påkrævet", + "aws-region": "AWS-region", + "aws-region-required": "AWS-region er påkrævet", + "number-from": "Telefonnummer fra", + "number-from-required": "Telefonnummer fra er påkrævet.", + "number-to": "Telefonnummer til", + "number-to-required": "Telefonnummer til er påkrævet.", + "phone-number-hint": "Telefonnummer i E.164-format, f.eks. +19995550123", + "phone-number-hint-twilio": "Telefonnummer i E.164-format/Telefonnummers SID/Meddelelsesservice SID, f.eks. +19995550123/PNXXX/MGXXX", + "phone-number-pattern": "Ugyldigt telefonnummer. Skal være i E.164-format, f.eks. +19995550123.", + "phone-number-pattern-twilio": "Ugyldigt telefonnummer. Skal være i E.164-format/Telefonnummers SID/Meddelelsesservice SID, f.eks. +19995550123/PNXXX/MGXXX.", + "sms-message": "SMS-besked", + "sms-message-required": "SMS-besked er påkrævet.", + "sms-message-max-length": "SMS-beskeden må ikke være længere end 1600 tegn", + "twilio-account-sid": "Twilio-konto SID", + "twilio-account-sid-required": "Twilio-konto SID er påkrævet", + "twilio-account-token": "Twilio-konto-token", + "twilio-account-token-required": "Twilio-konto-token er påkrævet", + "send-test-sms": "Send test-SMS", + "test-sms-sent": "Test-SMS'en blev sendt!", + "security-settings": "Sikkerhedsindstillinger", + "password-policy": "Adgangskodepolitik", + "minimum-password-length": "Min. adgangskodelængde", + "minimum-password-length-required": "Min. adgangskodelængde er påkrævet", + "minimum-password-length-range": "Min. adgangskodelængde skal være mellem 5 og 50", + "minimum-uppercase-letters": "Min. antal store bogstaver", + "minimum-uppercase-letters-range": "Min. antal store bogstaver kan ikke være negativt", + "minimum-lowercase-letters": "Min. antal små bogstaver", + "minimum-lowercase-letters-range": "Min. antal små bogstaver kan ikke være negativt", + "minimum-digits": "Min. antal cifre", + "minimum-digits-range": "Minimum antal cifre kan ikke være negativt", + "minimum-special-characters": "Minimum antal specialtegn", + "minimum-special-characters-range": "Minimum antal specialtegn kan ikke være negativt", + "password-expiration-period-days": "Adgangskodens udløbsperiode i dage", + "password-expiration-period-days-range": "Adgangskodens udløbsperiode i dage kan ikke være negativ", + "password-reuse-frequency-days": "Hyppighed af genbrug af adgangskode i dage", + "password-reuse-frequency-days-range": "Hyppigheden af genbrug af adgangskode i dage kan ikke være negativ", + "general-policy": "Generelle retningslinjer", + "max-failed-login-attempts": "Maks. antal mislykkede loginforsøg, før kontoen spærres", + "minimum-max-failed-login-attempts-range": "Maks. antal mislykkede loginforsøg kan ikke være negativt", + "user-lockout-notification-email": "Hvis brugerkontoen spærres, sendes en meddelelse til e-mail", + "domain-name": "Domænenavn", + "domain-name-unique": "Domænenavn og protokol skal være entydige.", + "error-verification-url": "Et domænenavn må ikke indeholde symbolerne '/' og ':'. Eksempel: thingsboard.io", + "oauth2": { + "access-token-uri": "Adgangstoken URI", + "access-token-uri-required": "Adgangstoken URI er påkrævet.", + "activate-user": "Aktivér bruger", + "add-domain": "Tilføj domæne", + "delete-domain": "Slet domæne", + "add-provider": "Tilføj udbyder", + "delete-provider": "Slet udbyder", + "allow-user-creation": "Tillad brugeroprettelse", + "always-fullscreen": "Altid fuld skærm", + "authorization-uri": "Godkendelses-URI", + "authorization-uri-required": "Godkendelses-URI er påkrævet.", + "client-authentication-method": "Klientgodkendelsesmetode", + "client-id": "Klient-id", + "client-id-required": "Klient-id er påkrævet.", + "client-secret": "Kunde hemmelig", + "client-secret-required": "Kunde hemmelig er påkrævet.", + "custom-setting": "Brugerdefinerede indstillinger", + "customer-name-pattern": "Kundenavnsmønster", + "parent-customer-name-pattern": "Overordnet kundenavnsmønster", + "user-groups-name-pattern": "Mønster for brugergruppenavn", + "default-dashboard-name": "Standard dashboardnavn", + "delete-domain-text": "Vær forsigtig. Efter bekræftelsen vil et domæne og alle udbyderdata være utilgængelige.", + "delete-domain-title": "", + "delete-registration-text": "Vær forsigtig. Efter bekræftelsen vil udbyderdata være utilgængelige.", + "delete-registration-title": "", + "email-attribute-key": "E-mailattributnøgle", + "email-attribute-key-required": "E-mailattributnøgle er påkrævet.", + "first-name-attribute-key": "Fornavn attributnøgle", + "general": "Generelt", + "jwk-set-uri": "JSON webnøgle-URI", + "last-name-attribute-key": "Efternavn attributnøgle", + "login-button-icon": "Logon-knapikon", + "login-button-label": "Udbyder etiket", + "login-button-label-placeholder": "Log ind med $(Udbyder etiket)", + "login-button-label-required": "Etiket er påkrævet.", + "login-provider": "Log ind udbyder", + "mapper": "Kortlægger", + "new-domain": "Nyt domæne", + "oauth2": "OAuth2", + "redirect-uri-template": "Omdiriger URI-skabelon", + "copy-redirect-uri": "Kopiér omdirigering af URI", + "registration-id": "Registrerings-id", + "registration-id-required": "Registrerings-id er påkrævet.", + "registration-id-unique": "Registrerings-id skal være entydigt for systemet.", + "scope": "Omfang", + "scope-required": "Omfang er påkrævet.", + "tenant-name-pattern": "Mønster for lejernavn", + "tenant-name-pattern-required": "Mønster for lejernavn er påkrævet.", + "tenant-name-strategy": "Strategi for lejernavn", + "type": "Kortlæggertype", + "uri-pattern-error": "Ugyldigt URI-format.", + "url": "URL", + "url-pattern": "Ugyldigt URL-format.", + "url-required": "URL er påkrævet.", + "user-info-uri": "Brugerinfo URI", + "user-info-uri-required": "Brugerinfo URI er påkrævet.", + "user-name-attribute-name": "Attributnøgle for brugernavn", + "user-name-attribute-name-required": "Attributnøgle for brugernavn er påkrævet", + "protocol": "Protokol", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "Aktivér OAuth2-indstillinger" + } + }, + "alarm": { + "alarm": "Alarm", + "alarms": "Alarmer", + "select-alarm": "Vælg alarm", + "no-alarms-matching": "", + "alarm-required": "Alarm er påkrævet", + "alarm-status": "Alarmstatus", + "alarm-status-list": "Alarmstatusliste", + "any-status": "Enhver status", + "search-status": { + "ANY": "Enhver", + "ACTIVE": "Aktiv", + "CLEARED": "Ryddet", + "ACK": "Kvitteret", + "UNACK": "Ikke kvitteret" + }, + "display-status": { + "ACTIVE_UNACK": "Aktiv Ikke-kvitteret", + "ACTIVE_ACK": "Aktiv Kvitteret", + "CLEARED_UNACK": "Ryddet Ikke-kvitteret", + "CLEARED_ACK": "Ryddet Kvitteret" + }, + "no-alarms-prompt": "Ingen alarmer fundet", + "created-time": "Oprettelsestidspunkt", + "type": "Type", + "severity": "Alvorsgrad", + "originator": "Ophavsmand", + "originator-type": "Ophavsmandtype", + "details": "Oplysninger", + "status": "Status", + "alarm-details": "Alarmoplysninger", + "start-time": "Starttid", + "end-time": "Sluttid", + "ack-time": "Tidspunkt for Kvitteret", + "clear-time": "Tidspunkt for Ryddet", + "alarm-severity-list": "Liste over alvorsgrad for alamer", + "any-severity": "Enhver alvorsgrad", + "severity-critical": "Kritisk", + "severity-major": "Stor", + "severity-minor": "Mindre", + "severity-warning": "Advarsel", + "severity-indeterminate": "Ubestemt", + "acknowledge": "Kvittér", + "clear": "Klar", + "search": "Søg efter alarmer", + "selected-alarms": "", + "no-data": "Ingen data at vise", + "polling-interval": "Alarmer undersøgelsesinterval (sek.)", + "polling-interval-required": "Alarmer undersøgelsesinterval er påkrævet.", + "min-polling-interval-message": "Mindst 1 sek. undersøgelsesinterval er tilladt.", + "aknowledge-alarms-title": "", + "aknowledge-alarms-text": "", + "aknowledge-alarm-title": "Kvittér for alarm", + "aknowledge-alarm-text": "Er du sikker på, du ønsker at kvittere for alarm?", + "clear-alarms-title": "", + "clear-alarms-text": "", + "clear-alarm-title": "Ryd alarm", + "clear-alarm-text": "Er du sikker på, at du vil slette Alarm?", + "alarm-status-filter": "Filter for alarmstatus", + "alarm-filter": "Alarmfilter", + "max-count-load": "Maks. antal alarmer, der skal indlæses (0 – ubegrænset)", + "max-count-load-required": "Maks. antal alarmer, der skal indlæses, er påkrævet.", + "max-count-load-error-min": "Minimumværdien er 0.", + "fetch-size": "Hent størrelse", + "fetch-size-required": "Hent størrelse er påkrævet.", + "fetch-size-error-min": "Minimumværdien er 10.", + "alarm-type-list": "Liste over alarmtyper", + "any-type": "Enhver type", + "search-propagated-alarms": "Søg efter overførte alarmer" + }, + "alias": { + "add": "Tilføj alias", + "edit": "Rediger alias", + "name": "Aliasnavn", + "name-required": "Aliasnavn er påkrævet", + "duplicate-alias": "Alias med samme navn findes allerede.", + "filter-type-single-entity": "Enkelt entitet", + "filter-type-entity-group": "Gruppeentiteter", + "filter-type-entity-list": "Entitetsliste", + "filter-type-entity-name": "Entitetsnavn", + "filter-type-entity-type": "Entitetstype", + "filter-type-entity-group-list": "Entitetsgruppeliste", + "filter-type-entity-group-name": "Entitetsgruppenavn", + "filter-type-entities-by-group-name": "Entiteter efter gruppenavn", + "filter-type-state-entity": "Entitet fra dashboardtilstand", + "filter-type-state-entity-description": "Entitet taget fra dashboardtilstandsparametre", + "filter-type-state-entity-owner": "Ejer af entitet fra dashboardtilstand", + "filter-type-state-entity-owner-description": "Ejer af entitet taget fra dashboardtilstandsparametre", + "filter-type-asset-type": "Aktivtype", + "filter-type-asset-type-description": "", + "filter-type-asset-type-and-name-description": "", + "filter-type-device-type": "Enhedstype", + "filter-type-device-type-description": "", + "filter-type-device-type-and-name-description": "", + "filter-type-entity-view-type": "Entitetsvisningstype", + "filter-type-entity-view-type-description": "", + "filter-type-entity-view-type-and-name-description": "", + "filter-type-relations-query": "Relationsforespørgsel", + "filter-type-relations-query-description": "", + "filter-type-asset-search-query": "Aktivsøgningsforespørgsel", + "filter-type-asset-search-query-description": "", + "filter-type-device-search-query": "Enhedssøgningsforespørgsel", + "filter-type-device-search-query-description": "", + "filter-type-entity-view-search-query": "Entitetsvisning for søgningsforespørgsel", + "filter-type-entity-view-search-query-description": "", + "filter-type-apiUsageState": "Api-brugstilstand", + "entity-filter": "Entitetsfilter", + "resolve-multiple": "Løs som flere entiteter", + "filter-type": "Filtertype", + "filter-type-required": "Filtertype er påkrævet.", + "entity-filter-no-entity-matched": "Der blev ikke fundet nogen entiteter, der matcher det angivne filter.", + "no-entity-filter-specified": "Intet entitetsfilter angivet", + "root-state-entity": "Brug dashboardtilstandsentitet som rod", + "group-state-entity": "Brug dashboardtilstandsentitet som entitetsgruppe", + "group-state-entity-owner": "Brug dashboardtilstandsentitet som entitetsgruppeejer", + "last-level-relation": "Hent kun sidste niveaurelation", + "root-entity": "Rodentitet", + "state-entity-parameter-name": "Parameternavn for tilstandsentitet", + "default-state-entity": "Standard tilstandsentitet", + "default-state-entity-group": "Standard tilstandsentitetsgruppe", + "default-entity-parameter-name": "Som standard", + "max-relation-level": "Maks. niveaurelation", + "unlimited-level": "Ubegrænset niveau", + "state-entity": "Dashboardtilstandsentitet", + "entities-of-group-state-entity": "Entiteter fra dashboardtilstandsentitetsgruppe", + "all-entities": "Alle entiteter", + "any-relation": "enhver" + }, + "asset": { + "asset": "Aktiv", + "assets": "Aktiver", + "management": "Styring af aktiver", + "view-assets": "Vis aktiver", + "add": "Tilføj aktiv", + "assign-to-customer": "Tildel til kunde", + "assign-asset-to-customer": "Tildel aktiv(er) til kunde", + "assign-asset-to-customer-text": "Vælg de aktiver, der skal tildeles til kunden", + "no-assets-text": "Ingen aktiver fundet", + "assign-to-customer-text": "Vælg den kunde, der skal tildeles aktivet/aktiverne", + "public": "Offentlig", + "assignedToCustomer": "Tildelt til kunde", + "make-public": "Gør aktiv offentligt", + "make-private": "Gør aktiv privat", + "unassign-from-customer": "Fjern tildeling fra kunde", + "delete": "Slet aktiv", + "asset-public": "Aktiv er offentligt", + "asset-type": "Aktivtype", + "asset-type-required": "Aktivtype er påkrævet.", + "select-asset-type": "Vælg aktivtype", + "enter-asset-type": "Indtast aktivtype", + "any-asset": "Ethvert aktiv", + "no-asset-types-matching": "", + "asset-type-list-empty": "Ingen aktivtyper valgt.", + "asset-types": "Aktivtyper", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "type": "Type", + "type-required": "Type er påkrævet.", + "details": "Oplysninger", + "events": "Begivenheder", + "add-asset-text": "Tilføj nyt aktiv", + "asset-details": "Oplysninger om aktiv", + "assign-assets": "Tildel aktiver", + "assign-assets-text": "", + "delete-assets": "Slet aktiver", + "unassign-assets": "Fjern tildeling af aktiver", + "unassign-assets-action-title": "", + "assign-new-asset": "Tildel nyt aktiv", + "delete-asset-title": "", + "delete-asset-text": "Vær forsigtig. Efter bekræftelsen vil aktivet og alle relaterede data være uoprettelige.", + "delete-assets-title": "", + "delete-assets-action-title": "", + "delete-assets-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte aktiver blive fjernet, og alle relaterede data vil være uoprettelige.", + "make-public-asset-title": "", + "make-public-asset-text": "Efter bekræftelsen vil aktivet og alle dets data blive gjort offentlige og tilgængelige for andre.", + "make-private-asset-title": "", + "make-private-asset-text": "Efter bekræftelsen vil aktivet og alle dets data blive gjort private og vil ikke være tilgængelige for andre.", + "unassign-asset-title": "", + "unassign-asset-text": "Efter bekræftelsen fjernes tildelingen af aktivet og vil ikke være tilgængeligt for kunden.", + "unassign-asset": "Fjern tildeling af aktiv", + "unassign-assets-title": "", + "unassign-assets-text": "Efter bekræftelsen vil alle valgte aktiver få fjernet tildelingen og ikke være tilgængelige for kunden.", + "copyId": "Kopiér aktiv-id", + "idCopiedMessage": "Aktiv-id er blevet kopieret til udklipsholder", + "select-asset": "Vælg aktiv", + "no-assets-matching": "", + "asset-required": "Aktiv er påkrævet", + "name-starts-with": "Aktivnavn starter med", + "selected-assets": "", + "search": "Søg efter aktiver", + "select-group-to-add": "Vælg målgruppe for at tilføje valgte aktiver", + "select-group-to-move": "Vælg målgruppe for at flytte valgte aktiver", + "remove-assets-from-group": "", + "group": "Aktivgruppe", + "list-of-groups": "", + "group-name-starts-with": "", + "import": "Importér aktiver", + "asset-file": "Aktivfil", + "label": "Mærkning" + }, + "attribute": { + "attributes": "Attributter", + "latest-telemetry": "Seneste telemetri", + "attributes-scope": "Omfang af entitetsattributter", + "scope-latest-telemetry": "Seneste telemetri", + "scope-client": "Klientattributter", + "scope-server": "Serverattributter", + "scope-shared": "Delte attributter", + "add": "Tilføj attribut", + "add-attribute-prompt": "Tilføj venligst attribut", + "key": "Nøgle", + "last-update-time": "Seneste opdateringstid", + "key-required": "Attributnøgle er påkrævet.", + "value": "Værdi", + "value-required": "Attributværdi er påkrævet.", + "delete-attributes-title": "", + "delete-attributes-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte attributter blive fjernet.", + "delete-attributes": "Slet attributter", + "enter-attribute-value": "Indtast attributværdi", + "show-on-widget": "Vis på widget", + "widget-mode": "Widget-tilstand", + "next-widget": "Næste widget", + "prev-widget": "Forrige widget", + "add-to-dashboard": "Føj til dashboard", + "add-widget-to-dashboard": "Føj widget til dashboard", + "selected-attributes": "", + "selected-telemetry": "", + "no-attributes-text": "Ingen attributter fundet", + "no-telemetry-text": "Ingen telemetri fundet" + }, + "api-usage": { + "api-usage": "Api-brug", + "data-points": "Datapunkter", + "data-points-storage-days": "Lagringsdage for datapunkter", + "email": "E-mail", + "email-messages": "E-mailbeskeder", + "email-messages-daily-activity": "Daglig aktivitet for e-mailbeskeder", + "email-messages-hourly-activity": "Timeaktivitet for e-mailbeskeder", + "email-messages-monthly-activity": "Månedlig aktivitet for e-mailbeskeder", + "exceptions": "Undtagelser", + "executions": "Udførelser", + "javascript": "JavaScript", + "javascript-executions": "JavaScript-udførelser", + "javascript-functions": "JavaScript-funktioner", + "javascript-functions-daily-activity": "JavaScript-funktioners daglige aktivitet", + "javascript-functions-hourly-activity": "JavaScript-funktioners timeaktivitet", + "javascript-functions-monthly-activity": "JavaScript-funktioners månedlige aktivitet", + "latest-error": "Seneste fejl", + "messages": "Beskeder", + "permanent-failures": "${entityName} Permanente fejl", + "permanent-timeouts": "${entityName} Permanente timeouts", + "processing-failures": "${entityName} Behandling af fejl", + "processing-failures-and-timeouts": "Behandling af fejl og timeouts", + "processing-timeouts": "${entityName} Behandling af timeouts", + "queue-stats": "Køstatistikker", + "rule-chain": "Regelkæde", + "rule-engine": "Regelprogram", + "rule-engine-daily-activity": "Regelmotors daglige aktivitet", + "rule-engine-executions": "Regelmotorudførelser", + "rule-engine-hourly-activity": "Regelmotors timeaktivitet", + "rule-engine-monthly-activity": "Regelmotors månedlige aktivitet", + "rule-engine-statistics": "Statistik for regelmotor", + "rule-node": "Regelknude", + "sms": "SMS", + "sms-messages": "SMS-beskeder", + "sms-messages-daily-activity": "Daglig aktivitet for SMS-beskeder", + "sms-messages-hourly-activity": "Timeaktivitet for SMS-beskeder", + "sms-messages-monthly-activity": "Månedlig aktivitet for SMS-beskeder", + "successful": "${entityName} Vellykket", + "telemetry": "Telemetri", + "telemetry-persistence": "Telemetri-vedholdenhed", + "telemetry-persistence-daily-activity": "Daglig aktivitet for telemetri-vedholdenhed", + "telemetry-persistence-hourly-activity": "Timeaktivitet for telemetri-vedholdenhed", + "telemetry-persistence-monthly-activity": "Månedlig aktivitet for telemetri-vedholdenhed", + "transport": "Transport", + "transport-daily-activity": "Daglig aktivitet for transport", + "transport-data-points": "Transportdatapunkter", + "transport-hourly-activity": "Timeaktivitet for transport", + "transport-messages": "Transportmeddelelser", + "transport-monthly-activity": "Månedlig aktivitet for transport", + "view-details": "Vis oplysninger", + "view-statistics": "Vis statistik" + }, + "audit-log": { + "audit": "Audit", + "audit-logs": "Auditlogs", + "timestamp": "Tidsstempel", + "entity-type": "Entitetstype", + "entity-name": "Entitetsnavn", + "user": "Bruger", + "type": "Type", + "status": "Status", + "details": "Oplysninger", + "type-added": "Tilføjet", + "type-deleted": "Slettet", + "type-updated": "Opdateret", + "type-attributes-updated": "Attributter opdateret", + "type-attributes-deleted": "Attributter slettet", + "type-rpc-call": "RPC-opkald", + "type-credentials-updated": "Brugeroplysninger opdateret", + "type-assigned-to-customer": "Tildelt til kunde", + "type-unassigned-from-customer": "Tildeling fjernet fra kunde", + "type-activated": "Aktiveret", + "type-suspended": "Indstillet", + "type-credentials-read": "Brugeroplysninger læst", + "type-attributes-read": "Attributter læst", + "type-added-to-entity-group": "Tilføjet til gruppe", + "type-removed-from-entity-group": "Fjernet fra gruppe", + "type-relation-add-or-update": "Relation opdateret", + "type-relation-delete": "Relation slettet", + "type-relations-delete": "Alle relationer slettet", + "type-alarm-ack": "Kvitteret", + "type-alarm-clear": "Ryddet", + "type-rest-api-rule-engine-call": "Regelmotor REST API-opkald", + "type-made-public": "Gjort offentligt", + "type-made-private": "Gjort privat", + "type-login": "Log på", + "type-logout": "Log af", + "type-lockout": "Spærring", + "status-success": "Succes", + "status-failure": "Fejl", + "audit-log-details": "Oplysninger om auditlog", + "no-audit-logs-prompt": "Ingen logs fundet", + "action-data": "Handlingsdata", + "failure-details": "Fejloplysninger", + "search": "Søg efter auditlogfiler", + "clear-search": "Ryd søgning", + "type-assigned-from-tenant": "Tildelt fra lejer", + "type-assigned-to-tenant": "Tildelt til lejer", + "type-provision-success": "Enhed klargjort", + "type-provision-failure": "Enhed klargjort mislykkedes", + "type-timeseries-updated": "Telemetri opdateret", + "type-timeseries-deleted": "Telemetri slettet", + "type-owner-changed": "Ejer ændret" + }, + "confirm-on-exit": { + "message": "Du har ikke-gemte ændringer. Er du sikker på, at du vil forlade denne side?", + "html-message": "Du har ikke-gemte ændringer.
              Er du sikker på, at du vil forlade denne side?", + "title": "Ugemte ændringer" + }, + "contact": { + "country": "Land", + "city": "By", + "state": "Region", + "postal-code": "Postnummer", + "postal-code-invalid": "Ugyldigt postnummerformat.", + "address": "Adresse", + "address2": "Adresse 2", + "phone": "Telefon", + "email": "E-mail", + "no-address": "Ingen adresse" + }, + "common": { + "username": "Brugernavn", + "password": "Adgangskode", + "enter-username": "Indtast brugernavn", + "enter-password": "Indtast adgangskode", + "enter-search": "Indtast søgning", + "created-time": "Oprettelsestidspunkt", + "loading": "Indlæser..." + }, + "converter": { + "converter": "Dataomformer", + "converters": "Dataomformere", + "select-converter": "Vælg dataomformer", + "no-converters-matching": "", + "converter-required": "Dataomformer er påkrævet", + "delete": "Slet omformer", + "management": "Styring af dataomformere", + "add-converter-text": "Tilføj ny dataomformer", + "no-converters-text": "Ingen dataomformere fundet", + "selected-converters": "", + "delete-converter-title": "", + "delete-converter-text": "Vær forsigtig. Efter bekræftelsen vil dataomformeren og alle relaterede data være uoprettelige.", + "delete-converters-title": "", + "delete-converters-action-title": "", + "delete-converters-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte dataomformere blive fjernet, og alle relaterede data vil være uoprettelige.", + "events": "Begivenheder", + "add": "Tilføj dataomformer", + "search": "Søg efter dataomformere", + "converter-details": "Oplysninger om dataomformer", + "details": "Oplysninger", + "copyId": "Kopiér omformer-id", + "idCopiedMessage": "Omformer-id er blevet kopieret til udklipsholder", + "debug-mode": "Debug-tilstand", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "decoder": "Dekoder", + "encoder": "Indkoder", + "test-decoder-fuction": "Test af dekoderfunktion", + "test-encoder-fuction": "Test af indkoderfunktion", + "decoder-input-params": "Parametre for dekoderindgang", + "encoder-input-params": "Parametre for indkoderindgang", + "payload": "Data", + "payload-content-type": "Dataindholdstype", + "payload-content": "Dataindhold", + "message": "Meddelelse", + "message-type": "Meddelelsestype", + "message-type-required": "Meddelelsestype er påkrævet", + "test": "Test", + "metadata": "Metadata", + "metadata-required": "Metadataposter må ikke være tomme.", + "integration-metadata": "Integrationsmetadata", + "integration-metadata-required": "Integrationsmetadataposter må ikke være tomme.", + "output": "Output", + "import": "Importér omformer", + "export": "Eksportér omformer", + "export-failed-error": "", + "create-new-converter": "Opret ny omformer", + "converter-file": "Omformerfil", + "invalid-converter-file-error": "Omformeren kunne ikke importeres: Ugyldig omformerdatastruktur.", + "type": "Type", + "type-required": "Type er påkrævet.", + "type-uplink": "Uplink", + "type-downlink": "Downlink" + }, + "content-type": { + "json": "Json", + "text": "Tekst", + "binary": "Binær (Base64)" + }, + "customer": { + "customer": "Kunde", + "customers": "Kunder", + "management": "Kundeadministration", + "dashboard": "Kundens dashboard", + "dashboards": "Kundens dashboards", + "devices": "Kundeenheder", + "entity-views": "Kundeentitetsvisninger", + "assets": "Kundeaktiver", + "public-dashboards": "Offentlige dashboards", + "public-devices": "Offentlige enheder", + "public-assets": "Offentlige aktiver", + "public-entity-views": "Visninger af offentlig entitet", + "add": "Tilføj kunde", + "delete": "Slet kunde", + "manage-customer-user-groups": "Administrer kundebrugergrupper", + "manage-customer-groups": "Administrer kundegrupper", + "manage-customer-device-groups": "Administrer kundeenhedsgrupper", + "manage-customer-asset-groups": "Administrer kundeaktivgrupper", + "manage-customer-entity-view-groups": "Administrer visningsgrupper for kundeentitet", + "manage-customer-dashboard-groups": "Administrer kundedashboardgrupper", + "manage-customer-users": "Administrer kundebrugere", + "manage-customers": "Administrer kunder", + "manage-customer-devices": "Administrer kundeenheder", + "manage-customer-entity-views": "Administrer visninger af kundeentitet", + "manage-customer-dashboards": "Administrer kundedashboards", + "manage-public-devices": "Administrer offentlige enheder", + "manage-public-dashboards": "Administrer offentlige dashboards", + "manage-customer-assets": "Administrer kundeaktiver", + "manage-public-assets": "Administrer offentlige aktiver", + "add-customer-text": "Tilføj ny kunde", + "no-customers-text": "Ingen kunder fundet", + "customer-details": "Kundeinformation", + "delete-customer-title": "", + "delete-customer-text": "Vær forsigtig. Efter bekræftelsen vil kunden og alle relaterede data være uoprettelige.", + "delete-customers-title": "", + "delete-customers-action-title": "", + "delete-customers-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte kunder blive fjernet, og alle relaterede data vil være uoprettelige.", + "manage-user-groups": "Administrer brugergrupper", + "manage-asset-groups": "Administrer aktivgrupper", + "manage-device-groups": "Administrer enhedsgrupper", + "manage-dashboard-groups": "Administrer dashboardgrupper", + "manage-entity-view-groups": "Administrer entitetsvisningsgrupper", + "manage-users": "Administrer brugere", + "manage-assets": "Administrer aktiver", + "manage-devices": "Administrer enheder", + "manage-dashboards": "Administrer dashboards", + "title": "Titel", + "title-required": "Titel er påkrævet.", + "description": "Beskrivelse", + "details": "Oplysninger", + "events": "Begivenheder", + "copyId": "Kopiér kunde-id", + "idCopiedMessage": "Kunde-id er blevet kopieret til udklipsholder", + "select-customer": "Vælg kunde", + "no-customers-matching": "", + "customer-required": "Kunde er påkrævet", + "selected-customers": "", + "search": "Søg efter kunder", + "select-group-to-add": "Vælg målgruppe for at tilføje udvalgte kunder", + "select-group-to-move": "Vælg målgruppe for at flytte udvalgte kunder", + "remove-customers-from-group": "", + "group": "Kundegruppe", + "list-of-groups": "", + "group-name-starts-with": "", + "select-default-customer": "Vælg standardkunde", + "default-customer": "Standardkunde", + "default-customer-required": "Standardkunde er påkrævet for at debugge dashboard på lejerniveau", + "allow-white-labeling": "Tillad hvid mærkning" + }, + "customers-hierarchy": { + "customers-hierarchy": "Kundehierarki", + "open-nav-tree": "Åbn navigationstræ", + "return-to-top-level": "Tilbage til øverste niveau" + }, + "custom-menu": { + "custom-menu": "Brugerdefineret menu", + "custom-menu-hint": "Definer brugerdefineret menu JSON nedenfor. Denne JSON indeholder en liste over brugerdefinerede menupunkter." + }, + "custom-translation": { + "custom-translation": "Brugerdefineret oversættelse", + "translation-map": "Oversættelsestilknytning", + "key": "Oversættelsesnøgle", + "import": "Importér oversættelse", + "export": "Eksportér oversættelse", + "export-data": "Eksportér oversættelsesdata", + "import-data": "Importér oversættelsesdata", + "translation-file": "Oversættelsesfil", + "invalid-translation-file-error": "Kunne ikke importere oversættelsesfil: Ugyldig oversættelsesdatastruktur.", + "custom-translation-hint": "Definer brugerdefineret oversættelse JSON nedenfor. Denne JSON overskriver standardoversættelsen. Klik på 'Download lokalfil' for at hente eksisterende oversættelse. Du kan også bruge den downloadede fil som reference til tilgængelige nøgleværdipar for oversættelse.", + "download-locale-file": "Download lokalfil" + }, + "datetime": { + "date-from": "Dato fra", + "time-from": "Tidspunkt fra", + "date-to": "Dato til", + "time-to": "Tidspunkt til" + }, + "dashboard": { + "dashboard": "Dashboard", + "dashboards": "Dashboards", + "management": "Dashboardadministration", + "view-dashboards": "Vis dashboards", + "add": "Tilføj dashboard", + "assign-dashboard-to-customer": "Tildel dashboard(s) til kunde", + "assign-dashboard-to-customer-text": "Vælg de dashboards, der skal tildeles til kunden", + "assign-to-customer-text": "Vælg den kunde, der skal tildeles dashboard(s)", + "assign-to-customer": "Tildel til kunde", + "unassign-from-customer": "Fjern tildeling fra kunde", + "make-public": "Gør dashboard offentligt", + "make-private": "Gør dashboard privat", + "manage-assigned-customers": "Administrer tildelte kunder", + "assigned-customers": "Tildelte kunder", + "assign-to-customers": "Tildel dashboard(s) til kunder", + "assign-to-customers-text": "Vælg de kunder, der skal tildeles dashboard(s)", + "unassign-from-customers": "Fjern tildeling af dashboard(s) fra kunder", + "unassign-from-customers-text": "Vælg de kunder, hvor tildeling skal fjernes fra dashboard(s)", + "no-dashboards-text": "Ingen dashboards fundet", + "no-widgets": "Ingen widgets konfigureret", + "add-widget": "Tilføj ny widget", + "title": "Titel", + "select-widget-title": "Vælg widget", + "select-widget-value": "", + "select-widget-subtitle": "Liste over tilgængelige widget-typer", + "delete": "Slet dashboard", + "title-required": "Titel er påkrævet.", + "description": "Beskrivelse", + "details": "Oplysninger", + "dashboard-details": "Oplysninger om dashboard", + "add-dashboard-text": "Tilføj nyt dashboard", + "assign-dashboards": "Tildel dashboards", + "assign-new-dashboard": "Tildel nyt dashboard", + "assign-dashboards-text": "", + "unassign-dashboards-action-text": "", + "delete-dashboards": "Slet dashboards", + "unassign-dashboards": "Fjern tildeling af dashboards", + "unassign-dashboards-action-title": "", + "delete-dashboard-title": "", + "delete-dashboard-text": "Vær forsigtig. Efter bekræftelsen vil dashboardet og alle relaterede data være uoprettelige.", + "delete-dashboards-title": "", + "delete-dashboards-action-title": "", + "delete-dashboards-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte dashboards blive fjernet, og alle relaterede data vil være uoprettelige.", + "unassign-dashboard-title": "", + "unassign-dashboard-text": "Efter bekræftelsen vil dashboardets tildeling blive fjernet og vil ikke være tilgængelig for kunden.", + "unassign-dashboard": "Fjern tildeling af dashboard", + "unassign-dashboards-title": "", + "unassign-dashboards-text": "Efter bekræftelsen vil tildelingen af alle valgte dashboards blive fjernet og vil ikke være tilgængelige for kunden.", + "public-dashboard-title": "Dashboard er nu offentligt", + "public-dashboard-text": "", + "public-dashboard-notice": "Bemærk: Glem ikke at gøre relaterede enheder offentlige for at få adgang til deres data.", + "public-dashboard-link": "Link til offentligt dashboard", + "public-dashboard-link-text": "", + "public-dashboard-link-notice": "Bemærk: Glem ikke at gøre relaterede enheder, aktiver og entitetsvisninger offentlige for at få adgang til deres data.", + "make-private-dashboard-title": "", + "make-private-dashboard-text": "Efter bekræftelsen vil dashboardet blive gjort privat og vil ikke være tilgængeligt for andre.", + "make-private-dashboard": "Gør dashboard privat", + "socialshare-text": "", + "socialshare-title": "", + "select-dashboard": "Vælg dashboard", + "no-dashboards-matching": "", + "dashboard-required": "Dashboard er påkrævet.", + "select-existing": "Vælg eksisterende dashboard", + "create-new": "Opret nyt dashboard", + "new-dashboard-title": "Ny dashboardtitel", + "open-dashboard": "Åbn dashboard", + "set-background": "Angiv baggrund", + "background-color": "Baggrundsfarve", + "background-image": "Baggrundsbillede", + "background-size-mode": "Baggrundsstørrelsestilstand", + "no-image": "Intet billede valgt", + "drop-image": "Træk og slip et billede, eller klik for at vælge en fil, der skal uploades.", + "maximum-upload-file-size": "", + "cannot-upload-file": "Filen kan ikke uploades", + "settings": "Indstillinger", + "columns-count": "Kolonneantal", + "columns-count-required": "Kolonneantal er påkrævet.", + "min-columns-count-message": "Kun 10 minimum kolonneantal er tilladt.", + "max-columns-count-message": "Kun 1000 maksimum kolonneantal er tilladt.", + "widgets-margins": "Margin mellem widgets", + "margin-required": "Marginværdi er påkrævet.", + "min-margin-message": "Kun 0 er tilladt som minimummarginværdi.", + "max-margin-message": "Kun 50 er tilladt som maksimummarginværdi.", + "horizontal-margin": "Horisontal margin", + "horizontal-margin-required": "Horisontal marginværdi er påkrævet.", + "min-horizontal-margin-message": "Kun 0 er tilladt som horisontal minimummarginværdi.", + "max-horizontal-margin-message": "Kun 50 er tilladt som horisontal maksimummarginværdi.", + "vertical-margin": "Vertikal margin", + "vertical-margin-required": "Vertikal marginværdi er påkrævet.", + "min-vertical-margin-message": "Kun 0 er tilladt som vertikal minimummarginværdi.", + "max-vertical-margin-message": "Kun 50 er tilladt som vertikal maksimummarginværdi.", + "autofill-height": "Autoudfyld layouthøjde", + "mobile-layout": "Mobile layoutindstillinger", + "mobile-row-height": "Mobil rækkehøjde, px", + "mobile-row-height-required": "Mobil rækkehøjdeværdi er påkrævet.", + "min-mobile-row-height-message": "Kun 5 pixel er tilladt som minimumværdi for mobilrækkehøjde.", + "max-mobile-row-height-message": "Kun 200 pixel er tilladt som maksimumværdi for mobilrækkehøjde.", + "display-title": "Vis dashboardtitel", + "toolbar-always-open": "Hold værktøjslinjen åben", + "title-color": "Titelfarve", + "display-dashboards-selection": "Vis valg af dashboards", + "display-entities-selection": "Vis valg af entiteter", + "display-filters": "Vis filtre", + "display-dashboard-timewindow": "Vis tidsvindue", + "display-dashboard-export": "Vis eksport", + "import": "Importér dashboard", + "export": "Eksportér dashboard", + "export-failed-error": "", + "export-pdf": "Eksportér som PDF", + "export-png": "Eksportér som PNG", + "export-jpg": "Eksportér som JPEG", + "export-json-config": "Eksportér JSON-konfiguration", + "download-dashboard-progress": "", + "create-new-dashboard": "Opret nyt dashboard", + "dashboard-file": "Dashboardfil", + "invalid-dashboard-file-error": "Kunne ikke importere dashboard: Ugyldig dashboarddatastruktur.", + "dashboard-import-missing-aliases-title": "Konfigurer aliasser anvendt af importeret dashboard", + "create-new-widget": "Opret ny widget", + "import-widget": "Importér widget", + "widget-file": "Widget-fil", + "invalid-widget-file-error": "Kan ikke importere widget: Ugyldig widget-datastruktur.", + "widget-import-missing-aliases-title": "Konfigurer aliasser, der bruges af importeret widget", + "open-toolbar": "Skjul dashboardets værktøjslinje", + "close-toolbar": "Luk værktøjslinje", + "configuration-error": "Konfigurationsfejl", + "alias-resolution-error-title": "Konfigurationsfejl i dashboardaliasser", + "invalid-aliases-config": "Kunne ikke finde nogen enheder, der matcher nogle af aliasfiltrene.
              Kontakt din administrator for at løse dette problem.", + "select-devices": "Vælg enheder", + "assignedToCustomer": "Tildelt til kunde", + "assignedToCustomers": "Tildelt til kunder", + "public": "Offentlig", + "public-link": "Offentligt link", + "copy-public-link": "Kopiér offentligt link", + "public-link-copied-message": "Dashboardets offentilige link er blevet kopieret til udklipsholderen", + "manage-states": "Administrer dashboardtilstande", + "states": "Dashboardtilstande", + "search-states": "Søg efter dashboardtilstande", + "selected-states": "", + "edit-state": "Rediger dashboardtilstand", + "delete-state": "Slet dashboardtilstand", + "add-state": "Tilføj dashboardtilstand", + "no-states-text": "Ingen tilstande fundet", + "state": "Dashboardtilstand", + "state-name": "Navn", + "state-name-required": "Dashboardtilstandsnavn er påkrævet.", + "state-id": "Tilstands-id", + "state-id-required": "Dashboardtilstands-id er påkrævet.", + "state-id-exists": "Dashboardtilstand med samme id findes allerede.", + "is-root-state": "Rodtilstand", + "delete-state-title": "Slet dashboardtilstand", + "delete-state-text": "", + "show-details": "Vis oplysninger", + "hide-details": "Skjul oplysninger", + "select-state": "Vælg måltilstand", + "state-controller": "Tilstandscontroller", + "selected-dashboards": "", + "search": "Søg efter dashboards", + "home-dashboard": "Startside", + "home-dashboard-hide-toolbar": "Skjul startsidens værktøjslinje", + "select-group-to-add": "Vælg målgruppe for at tilføje valgte dashboards", + "select-group-to-move": "Vælg målgruppe for at flytte valgte dashboards", + "remove-dashboards-from-group": "", + "group": "Gruppe af dashboards", + "list-of-groups": "", + "group-name-starts-with": "" + }, + "datakey": { + "settings": "Indstillinger", + "advanced": "Fremskreden", + "label": "Mærkning", + "color": "Farve", + "units": "Specielt symbol, der vises ved siden af værdi", + "decimals": "Antal cifre efter flydende punkt", + "data-generation-func": "Datagenereringsfunktion", + "use-data-post-processing-func": "Brug dataefterbehandlingsfunktion", + "configuration": "Konfiguration af datanøgle", + "timeseries": "Tidsserier", + "attributes": "Attributter", + "entity-field": "Entitetsfelt", + "alarm": "Alarmfelter", + "timeseries-required": "Entitets tidsserier er påkrævet.", + "timeseries-or-attributes-required": "Entitets tidsserier/attributter er påkrævet.", + "alarm-fields-timeseries-or-attributes-required": "Alarmfelter eller entitets tidsserier/attributter er påkrævet.", + "maximum-timeseries-or-attributes": "", + "alarm-fields-required": "Alarmfelter er påkrævet.", + "function-types": "Funktionstyper", + "function-types-required": "Funktionstyper er påkrævet.", + "maximum-function-types": "", + "time-description": "tidsstempel for den aktuelle værdi", + "value-description": "den aktuelle værdi", + "prev-value-description": "resultat af forrige funktionskald", + "time-prev-description": "tidsstempel for den forrige værdi", + "prev-orig-value-description": "oprindelig tidligere værdi" + }, + "datasource": { + "type": "Datakildetype", + "name": "Navn", + "label": "Mærkning", + "add-datasource-prompt": "Tilføj datakilde" + }, + "details": { + "details": "Oplysninger", + "edit-mode": "Redigeringstilstand", + "edit-json": "Rediger JSON", + "toggle-edit-mode": "Skift redigeringstilstand" + }, + "device": { + "device": "Enhed", + "device-required": "Enhed er påkrævet.", + "devices": "Enheder", + "management": "Enhedsadministration", + "view-devices": "Vis enheder", + "device-alias": "Enhedsalias", + "aliases": "Enhedsaliasser", + "no-alias-matching": "", + "no-aliases-found": "Ingen aliasser fundet.", + "no-key-matching": "", + "no-keys-found": "Ingen nøgler fundet.", + "create-new-alias": "Opret en ny!", + "create-new-key": "Opret en ny!", + "duplicate-alias-error": "", + "configure-alias": "", + "no-devices-matching": "", + "alias": "Alias", + "alias-required": "Enhedsalias er påkrævet.", + "remove-alias": "Fjern enhedsalias", + "add-alias": "Tilføj enhedsalias", + "name-starts-with": "Enhedens navn starter med", + "device-list": "Enhedsliste", + "use-device-name-filter": "Anvend filter", + "device-list-empty": "Ingen enheder valgt.", + "device-name-filter-required": "Enhedsnavnfilter er påkrævet.", + "device-name-filter-no-device-matched": "", + "add": "Tilføj enhed", + "assign-to-customer": "Tildel til kunde", + "assign-device-to-customer": "Tildel enhed(er) til kunde", + "assign-device-to-customer-text": "Vælg de enheder, der skal tildeles kunden", + "make-public": "Gør enheden offentlig", + "make-private": "Gør enheden privat", + "no-devices-text": "Ingen enheder fundet", + "assign-to-customer-text": "Vælg den kunde, der skal tilknyttes enheden/enhederne", + "device-details": "Enhedsoplysninger", + "add-device-text": "Tilføj ny enhed", + "credentials": "Brugeroplysninger", + "manage-credentials": "Administrer brugeroplysninger", + "delete": "Slet enhed", + "assign-devices": "Tildel enheder", + "assign-devices-text": "", + "delete-devices": "Slet enheder", + "unassign-from-customer": "Fjern tildeling fra kunde", + "unassign-devices": "Fjern tildeling af enheder", + "unassign-devices-action-title": "", + "assign-new-device": "Tildel ny enhed", + "make-public-device-title": "", + "make-public-device-text": "Efter bekræftelsen vil enheden og alle dens data blive gjort offentlige og tilgængelige for andre.", + "make-private-device-title": "", + "make-private-device-text": "Efter bekræftelsen vil enheden og alle dens data blive gjort private og vil ikke være tilgængelige for andre.", + "view-credentials": "Vis brugeroplysninger", + "delete-device-title": "", + "delete-device-text": "Vær forsigtig. Efter bekræftelsen vil enheden og alle relaterede data være uoprettelige.", + "delete-devices-title": "", + "delete-devices-action-title": "", + "delete-devices-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte enheder blive fjernet, og alle relaterede data vil være uoprettelige.", + "unassign-device-title": "", + "unassign-device-text": "Efter bekræftelsen vil enhedens tildeling blive fjernet og vil ikke være tilgængelig for kunden.", + "unassign-device": "Fjern tildeling af enhed", + "unassign-devices-title": "", + "unassign-devices-text": "Efter bekræftelsen vil tildelingen af alle valgte enheder blive fjernet og vil ikke være tilgængelige for kunden.", + "device-credentials": "Enhedsbrugeroplysninger", + "credentials-type": "Type af brugeroplysninger", + "access-token": "Adgangstoken", + "access-token-required": "Adgangstoken er påkrævet.", + "access-token-invalid": "Adgangstokenlængden skal være fra 1 til 20 tegn.", + "rsa-key": "RSA offentlig nøgle", + "rsa-key-required": "RSA offentlig nøgle er påkrævet.", + "client-id": "Klient-id", + "client-id-pattern": "Indeholder ugyldigt tegn.", + "user-name": "Brugernavn", + "user-name-required": "Brugernavn er påkrævet.", + "client-id-or-user-name-necessary": "Klient-id og/eller brugernavn er nødvendige", + "password": "Adgangskode", + "secret": "Hemmelig", + "secret-required": "Hemmelig er påkrævet.", + "device-type": "Enhedstype", + "device-type-required": "Enhedstype er påkrævet.", + "select-device-type": "Vælg enhedstype", + "enter-device-type": "Indtast enhedstype", + "any-device": "Enhver enhed", + "no-device-types-matching": "", + "device-type-list-empty": "Ingen enhedstyper valgt.", + "device-types": "Enhedstyper", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "label": "Mærkning", + "events": "Begivenheder", + "details": "Oplysninger", + "copyId": "Kopiér enheds-id", + "copyAccessToken": "Kopiér adgangstoken", + "copy-mqtt-authentication": "Kopiér MQTT-brugeroplysninger", + "idCopiedMessage": "Enheds-id er blevet kopieret til udklipsholder", + "accessTokenCopiedMessage": "Enhedsadgangstoken er blevet kopieret til udklipsholder", + "mqtt-authentication-copied-message": "Enhedens MQTT-godkendelse er blevet kopieret til udklipsholder", + "assignedToCustomer": "Tildelt til kunde", + "unable-delete-device-alias-title": "Kan ikke slette enhedsalias", + "unable-delete-device-alias-text": "", + "is-gateway": "Er gateway", + "overwrite-activity-time": "Overskriv aktivitetstid for tilsluttet enhed", + "public": "Offentlig", + "device-public": "Enheden er offentlig", + "select-device": "Vælg enhed", + "selected-devices": "", + "search": "Søg efter enheder", + "select-group-to-add": "Vælg målgruppe for at tilføje valgte enheder", + "select-group-to-move": "Vælg målgruppe for at flytte valgte enheder", + "remove-devices-from-group": "", + "group": "Gruppe af enheder", + "list-of-groups": "", + "group-name-starts-with": "", + "import": "Importér enhed", + "device-file": "Enhedsfil", + "device-configuration": "Enhedskonfiguration", + "transport-configuration": "Transportkonfiguration", + "wizard": { + "device-wizard": "Enhedsguide", + "device-details": "Enhedsoplysninger", + "new-device-profile": "Opret ny enhedsprofil", + "existing-device-profile": "Vælg eksisterende enhedsprofil", + "specific-configuration": "Specifik konfiguration", + "customer-to-assign-device": "Kunden skal tildele enheden", + "add-credential": "Tilføj brugeroplysninger" + } + }, + "device-profile": { + "device-profile": "Enhedsprofil", + "device-profiles": "Enhedsprofiler", + "all-device-profiles": "Alle", + "add": "Tilføj enhedsprofil", + "edit": "Rediger enhedsprofil", + "device-profile-details": "Oplysninger om enhedsprofil", + "no-device-profiles-text": "Ingen enhedsprofiler fundet", + "search": "Søg efter enhedsprofiler", + "selected-device-profiles": "", + "no-device-profiles-matching": "", + "device-profile-required": "Enhedsprofil er påkrævet", + "idCopiedMessage": "Enhedsprofil-id er blevet kopieret til udklipsholder", + "set-default": "Gør enhedsprofil standard", + "delete": "Slet enhedsprofil", + "copyId": "Kopiér enhedsprofil-id", + "new-device-profile-name": "Enhedsprofilnavn", + "new-device-profile-name-required": "Enhedsprofilnavn er påkrævet.", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "type": "Profiltype", + "type-required": "Profiltype er påkrævet.", + "type-default": "Standard", + "transport-type": "Transporttype", + "transport-type-required": "Transporttype er påkrævet.", + "transport-type-default": "Standard", + "transport-type-default-hint": "Understøtter grundlæggende MQTT-, HTTP- og CoAP-transport", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "Aktiverer avancerede MQTT-transportindstillinger", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "LWM2M-transporttype", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "Aktiverer avancerede CoAP-transportindstillinger", + "description": "Beskrivelse", + "default": "Standard", + "profile-configuration": "Profilkonfiguration", + "transport-configuration": "Transportkonfiguration", + "default-rule-chain": "Standardregelkæde", + "select-queue-hint": "Vælg fra en rulleliste, eller tilføj et brugerdefineret navn.", + "delete-device-profile-title": "", + "delete-device-profile-text": "Vær forsigtig. Efter bekræftelsen vil enhedsprofilen og alle relaterede data være uoprettelige.", + "delete-device-profiles-title": "", + "delete-device-profiles-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte enhedsprofiler blive fjernet, og alle relaterede data vil være uoprettelige.", + "set-default-device-profile-title": "", + "set-default-device-profile-text": "Efter bekræftelsen vil enhedsprofilen blive markeret som standard og vil blive brugt til nye enheder, hvor der ikke er angivet nogen profil.", + "no-device-profiles-found": "Ingen enhedsprofiler fundet.", + "create-new-device-profile": "Opret en ny!", + "mqtt-device-topic-filters": "MQTT-enhedsemnefiltre", + "mqtt-device-topic-filters-unique": "MQTT-enhedsemnefiltre skal være unikke.", + "mqtt-device-payload-type": "MQTT-enhedsdata", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Datatype er påkrævet.", + "coap-device-type": "CoAP-enhedstype", + "coap-device-payload-type": "CoAP-enhedsdata", + "coap-device-type-required": "CoAP-enhedstype er påkrævet.", + "coap-device-type-default": "Standard", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "Enkelt [+] jokertegn og [#] jokertegn på flere niveauer understøttes.", + "telemetry-topic-filter": "Telemetriemnefilter", + "telemetry-topic-filter-required": "Telemetriemnefilter er påkrævet.", + "attributes-topic-filter": "Attributemnefilter", + "attributes-topic-filter-required": "Attributemnefilter er påkrævet.", + "telemetry-proto-schema": "Telemetri-protoskema", + "telemetry-proto-schema-required": "Telemetri-protoskema er påkrævet.", + "attributes-proto-schema": "Protoskema for attributter", + "attributes-proto-schema-required": "Protoskema for attributter er påkrævet.", + "rpc-response-topic-filter": "RPC-svaremnefilter", + "rpc-response-topic-filter-required": "RPC-svaremnefilter er påkrævet.", + "not-valid-pattern-topic-filter": "Ikke gyldigt mønsteremnefilter", + "not-valid-single-character": "Ugyldig brug af jokertegn i et enkelt niveau", + "not-valid-multi-character": "Ugyldig brug af jokertegn i flere niveauer", + "single-level-wildcards-hint": "[+] er velegnet til ethvert emnefilterniveau. Eks.: v1/enheder/+/telemetri eller +/enheder/+/attributter.", + "multi-level-wildcards-hint": "[#] kan selv erstatte emnefilteret og skal være det sidste symbol i emnet. Eks.: # eller v1/enheder/me/#.", + "alarm-rules": "Alarmregler", + "alarm-rules-with-count": "", + "no-alarm-rules": "Ingen alarmregler konfigureret", + "add-alarm-rule": "Tilføj alarmregel", + "edit-alarm-rule": "Rediger alarmregel", + "alarm-type": "Alarmtype", + "alarm-type-required": "Alarmtype er påkrævet.", + "alarm-type-unique": "Alarmtypen skal være unik inden for alarmreglerne for enhedsprofilen.", + "create-alarm-pattern": "", + "create-alarm-rules": "Opret alarmregler", + "no-create-alarm-rules": "Ingen opret betingelser konfigureret", + "add-create-alarm-rule-prompt": "Tilføj opret alarmregel", + "clear-alarm-rule": "Ryd alarmregel", + "no-clear-alarm-rule": "Ingen klar betingelse konfigureret", + "add-create-alarm-rule": "Tilføj opret betingelse", + "add-clear-alarm-rule": "Tilføj ryd tilstand", + "select-alarm-severity": "Vælg alarmens alvorsgrad", + "alarm-severity-required": "Alarmens alvorsgrad er påkrævet.", + "condition-duration": "Varighed af betingelse", + "condition-duration-value": "Varighedsværdi", + "condition-duration-time-unit": "Tidsenhed", + "condition-duration-value-range": "Varighedsværdien skal ligge i området fra 1 til 2147483647.", + "condition-duration-value-pattern": "Varighedsværdien skal være heltal.", + "condition-duration-value-required": "Varighedsværdi er påkrævet.", + "condition-duration-time-unit-required": "Tidsenhed er påkrævet.", + "advanced-settings": "Avancerede indstillinger", + "alarm-rule-details": "Oplysninger", + "add-alarm-rule-details": "Tilføj oplysninger", + "propagate-alarm": "Overfør alarm", + "alarm-rule-relation-types-list": "Relationstyper, der skal overføres", + "alarm-rule-relation-types-list-hint": "Hvis der ikke vælges Overfør relationstyper vil alarmer blive overført uden filtrering på relationstype.", + "alarm-details": "Alarmoplysninger", + "alarm-rule-condition": "Alarmregelbetingelse", + "enter-alarm-rule-condition-prompt": "Tilføj alarmregelbetingelse", + "edit-alarm-rule-condition": "Rediger alarmregelbetingelse", + "device-provisioning": "Klargøring af enheden", + "provision-strategy": "Strategi for klargøring", + "provision-strategy-required": "Strategi for klargøring er påkrævet.", + "provision-strategy-disabled": "Deaktiveret", + "provision-strategy-created-new": "Tillad oprettelse af nye enheder", + "provision-strategy-check-pre-provisioned": "Kontrollér, om der er forhåndsklargjorte enheder", + "provision-device-key": "Klargøringsenhedsnøgle", + "provision-device-key-required": "Klargøringsenhedsnøgle er påkrævet.", + "copy-provision-key": "Kopiér klargøringsnøgle", + "provision-key-copied-message": "Klargøringsnøgle er blevet kopieret til udklipsholder", + "provision-device-secret": "Klargøringsenhed hemmelig", + "provision-device-secret-required": "Klargøringsenhed hemmelig er påkrævet.", + "copy-provision-secret": "Kopiér klargøring hemmelig", + "provision-secret-copied-message": "Klargøring hemmelig er blevet kopieret til udklipsholder", + "condition": "Betingelse", + "condition-type": "Betingelsestype", + "condition-type-simple": "Enkel", + "condition-type-duration": "Varighed", + "condition-during": "", + "condition-type-repeating": "Gentager", + "condition-type-required": "Betingelsesnavn er påkrævet.", + "condition-repeating-value": "Antal begivenheder", + "condition-repeating-value-range": "Antallet af begivenheder skal ligge i intervallet fra 1 til 2147483647.", + "condition-repeating-value-pattern": "Antal begivenheder skal være heltal.", + "condition-repeating-value-required": "Antal begivenheder er påkrævet.", + "condition-repeat-times": "", + "schedule-type": "Planlægningstype", + "schedule-type-required": "Planlægningstype er påkrævet.", + "schedule": "Tidsplan", + "edit-schedule": "Rediger alarmtidsplan", + "schedule-any-time": "Aktiv hele tiden", + "schedule-specific-time": "Aktiv på et bestemt tidspunkt", + "schedule-custom": "Brugerdefineret", + "schedule-day": { + "monday": "Mandag", + "tuesday": "Tirsdag", + "wednesday": "Onsdag", + "thursday": "Torsdag", + "friday": "Fredag", + "saturday": "Lørdag", + "sunday": "Søndag" + }, + "schedule-days": "Dage", + "schedule-time": "Tid", + "schedule-time-from": "Fra", + "schedule-time-to": "Til", + "schedule-days-of-week-required": "Der skal vælges mindst én ugedag.", + "create-device-profile": "Opret ny enhedsprofil", + "import": "Importér enhedsprofil", + "export": "Eksportér enhedsprofil", + "export-failed-error": "", + "device-profile-file": "Fil for enhedsprofil", + "invalid-device-profile-file-error": "Kan ikke importere enhedsprofil: Ugyldig datastruktur for enhedsprofil." + }, + "dialog": { + "close": "Tæt" + }, + "direction": { + "column": "Kolonne", + "row": "Række" + }, + "error": { + "unable-to-connect": "Kan ikke oprette forbindelse til serveren! Kontrollér din internetforbindelse.", + "unhandled-error-code": "", + "unknown-error": "Ukendt fejl" + }, + "entity": { + "entity": "Entitet", + "entities": "Entiteter", + "entities-count": "Antal entiteter", + "aliases": "Entitetsaliasser", + "entity-alias": "Entitetsalias", + "unable-delete-entity-alias-title": "Entitetsalias kunne ikke slettes", + "unable-delete-entity-alias-text": "", + "duplicate-alias-error": "", + "missing-entity-filter-error": "", + "configure-alias": "", + "alias": "Alias", + "alias-required": "Entitetsalias er påkrævet.", + "remove-alias": "Fjern entitetsalias", + "add-alias": "Tilføj entitetsalias", + "entity-list": "Entitetsliste", + "entity-type": "Entitetstype", + "entity-types": "Entitetstyper", + "entity-type-list": "Liste over entitetstype", + "any-entity": "Enhver entitet", + "enter-entity-type": "Indtast entitetstype", + "no-entities-matching": "", + "no-entity-types-matching": "", + "name-starts-with": "Navnet begynder med", + "use-entity-name-filter": "Anvend filter", + "entity-list-empty": "Ingen entiteter valgt.", + "entity-type-list-empty": "Ingen entitetstyper valgt.", + "entity-name-filter-required": "Entitetsnavnfilter er påkrævet.", + "entity-name-filter-no-entity-matched": "", + "all-subtypes": "Alle", + "select-entities": "Vælg entiteter", + "no-aliases-found": "Ingen aliasser fundet.", + "no-alias-matching": "", + "create-new-alias": "Opret en ny!", + "key": "Nøgle", + "key-name": "Nøglenavn", + "no-keys-found": "Ingen nøgler fundet.", + "no-key-matching": "", + "create-new-key": "Opret en ny!", + "type": "Type", + "type-required": "Entitetstype er påkrævet.", + "type-device": "Enhed", + "type-devices": "Enheder", + "list-of-devices": "", + "device-name-starts-with": "", + "type-device-profile": "Enhedsprofil", + "type-device-profiles": "Enhedsprofiler", + "list-of-device-profiles": "", + "device-profile-name-starts-with": "", + "type-asset": "Aktiv", + "type-assets": "Aktiver", + "list-of-assets": "", + "asset-name-starts-with": "", + "type-entity-view": "Entitetsvisning", + "type-entity-views": "Entitetsvisninger", + "list-of-entity-views": "", + "entity-view-name-starts-with": "", + "type-rule": "Regel", + "type-rules": "Regler", + "list-of-rules": "", + "rule-name-starts-with": "", + "type-plugin": "Plugin", + "type-plugins": "Plugins", + "list-of-plugins": "", + "plugin-name-starts-with": "", + "type-tenant": "Lejer", + "type-tenants": "Lejere", + "list-of-tenants": "", + "tenant-name-starts-with": "", + "type-tenant-profile": "Lejerprofil", + "type-tenant-profiles": "Lejerprofiler", + "list-of-tenant-profiles": "", + "tenant-profile-name-starts-with": "", + "type-customer": "Kunde", + "type-customers": "Kunder", + "list-of-customers": "", + "customer-name-starts-with": "", + "type-user": "Bruger", + "type-users": "Brugere", + "list-of-users": "", + "user-name-starts-with": "", + "type-dashboard": "Dashboard", + "type-dashboards": "Dashboards", + "list-of-dashboards": "", + "dashboard-name-starts-with": "", + "type-alarm": "Alarm", + "type-alarms": "Alarmer", + "list-of-alarms": "", + "alarm-name-starts-with": "", + "type-rulechain": "Regelkæde", + "type-rulechains": "Regelkæder", + "list-of-rulechains": "", + "rulechain-name-starts-with": "", + "type-scheduler-event": "Planlægningsbegivenhed", + "type-scheduler-events": "Planlægningsbegivenheder", + "list-of-scheduler-events": "", + "scheduler-event-name-starts-with": "", + "type-blob-entity": "Blob-entitet", + "type-blob-entities": "Blob-entiteter", + "list-of-blob-entities": "", + "blob-entity-name-starts-with": "", + "type-rulenode": "Regelknude", + "type-rulenodes": "Regelknuder", + "list-of-rulenodes": "", + "rulenode-name-starts-with": "", + "type-current-customer": "Nuværende kunde", + "type-current-tenant": "Nuværende lejer", + "type-current-user": "Nuværende bruger", + "type-current-user-owner": "Nuværende brugerejer", + "search": "Søg efter entiteter", + "selected-entities": "", + "entity-name": "Entitetsnavn", + "entity-label": "Entitetsetiket", + "details": "Entitetsoplysninger", + "no-entities-prompt": "Ingen entiteter fundet", + "no-data": "Ingen data at vise", + "columns-to-display": "Kolonner, der skal vises", + "type-api-usage-state": "Api-brugstilstand", + "type-entity-group": "Entitetsgruppe", + "type-converter": "Dataomformer", + "type-converters": "Dataomformere", + "list-of-converters": "", + "converter-name-starts-with": "", + "type-integration": "Integration", + "type-integrations": "Integrationer", + "list-of-integrations": "", + "integration-name-starts-with": "", + "type-role": "Rolle", + "type-roles": "Roller", + "list-of-roles": "", + "role-name-starts-with": "", + "type-group-permission": "Gruppetilladelse" + }, + "entity-group": { + "entity-group": "Entitetsgruppe", + "details": "Oplysninger", + "columns": "Kolonner", + "add-column": "Tilføj kolonne", + "column-value": "Værdi", + "column-value-required": "Kolonneværdi er påkrævet.", + "column-title": "Titel", + "default-sort-order": "Standardsorteringsrækkefølge", + "default-sort-order-required": "Standardsorteringsrækkefølge er påkrævet.", + "hide-in-mobile-view": "Mobil skjult", + "use-cell-style-function": "Brug celletypefunktion", + "use-cell-content-function": "Brug celleindholdsfunktion", + "edit-column": "Rediger kolonne", + "column-details": "Kolonneoplysninger", + "actions": "Handlinger", + "settings": "Indstillinger", + "search": "Søg entitetsgrupper", + "delete": "Slet entitetsgruppe", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "add": "Tilføj entitetsgruppe", + "open-entity-group": "Åbn entitetsgruppe", + "add-entity-group-text": "Tilføj ny entitetsgruppe", + "no-entity-groups-text": "Ingen entitetsgrupper fundet", + "entity-group-details": "Oplysninger om entitetsgruppe", + "selected-entity-groups": "", + "delete-entity-groups": "Slet entitetsgrupper", + "delete-entity-group-title": "", + "delete-entity-group-text": "Vær forsigtig. Efter bekræftelsen vil entitetsgruppen og alle relaterede data være uoprettelige.", + "delete-entity-groups-title": "", + "delete-entity-groups-action-title": "", + "delete-entity-groups-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte entitetsgrupper blive fjernet, og alle relaterede data vil være uoprettelige.", + "device-groups": "Enhedsgrupper", + "asset-groups": "Aktivgrupper", + "customer-groups": "Kundegrupper", + "device-group": "Enhedsgruppe", + "asset-group": "Aktivgruppe", + "user-group": "Brugergruppe", + "user-groups": "Brugergrupper", + "customer-group": "Kundegruppe", + "entity-view-groups": "Entitetsvisningsgrupper", + "entity-view-group": "Entitetsvisningsgruppe", + "dashboard-groups": "Dashboardgrupper", + "dashboard-group": "Dashboardgruppe", + "fetch-more": "Hent mere", + "column-type": { + "column-type": "Kolonnetype", + "client-attribute": "Klientattribut", + "shared-attribute": "Delt attribut", + "server-attribute": "Serverattribut", + "timeseries": "Tidsserier", + "entity-field": "Entitetsfelt" + }, + "column-type-required": "Kolonnetype er påkrævet.", + "entity-field": { + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "type": "Type", + "device_profile": "Enhedsprofil", + "assigned_customer": "Tildelt kunde", + "authority": "Autoritet", + "first_name": "Fornavn", + "last_name": "Efternavn", + "email": "E-mail", + "title": "Titel", + "country": "Land", + "state": "Region", + "city": "By", + "address": "Adresse", + "address2": "Adresse 2", + "zip": "Postnummer", + "phone": "Telefon", + "label": "Mærkning" + }, + "sort-order": { + "asc": "Stigende", + "desc": "Faldende", + "none": "Ingen" + }, + "details-mode": { + "on-row-click": "Ved klik på række", + "on-action-button-click": "Ved klik på knappen Oplysninger", + "disabled": "Deaktiveret" + }, + "change-owner": "Skift ejer", + "select-target-owner": "Vælg målejer", + "no-owners-matching": "", + "target-owner-required": "Målejer er påkrævet.", + "confirm-change-owner-title": "", + "confirm-change-owner-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte enheder blive fjernet fra den aktuelle ejer og blive placeret i gruppen 'Alle' for målejeren.", + "add-to-group": "Tilføj til gruppe", + "move-to-group": "Flyt til gruppe", + "select-entity-group": "Vælg entitetsgruppe", + "no-entity-groups-matching": "", + "target-entity-group-required": "Målentitetsgruppe er påkrævet.", + "select-user-group": "Vælg brugergruppe", + "no-user-groups-matching": "", + "target-user-group-required": "Målbrugergruppe er påkrævet.", + "remove-from-group": "Fjern fra gruppe", + "group-table-title": "Gruppetabeltitel", + "enable-search": "Aktivér entitetssøgning", + "enable-add": "Aktivér tilføjelse af entiteter", + "enable-delete": "Aktivér sletning af entiteter", + "enable-selection": "Aktivér entitetsvalg", + "enable-group-transfer": "Aktivér gruppeoverførselshandlinger", + "display-pagination": "Vis sidenummerering", + "default-page-size": "Standard sidestørrelse", + "enable-assignment-actions": "Aktivér tildelingshandlinger", + "enable-credentials-management": "Aktivér administration af brugeroplysninger", + "enable-login-as-user": "Aktivér login som brugerhandling", + "enable-users-management": "Aktivér administration af brugere", + "enable-customers-management": "Aktivér administration af kunder", + "enable-assets-management": "Aktivér administration af aktiver", + "enable-devices-management": "Aktivér administration af enheder", + "enable-entity-views-management": "Aktivér administration af entitetsvisninger", + "enable-dashboards-management": "Aktivér administration af dashboards", + "open-details-on": "Åbn entitetsoplysninger på", + "select-existing": "Vælg eksisterende entitetsgruppe", + "create-new": "Opret ny entitetsgruppe", + "new-entity-group-name": "Nyt entitetsgruppenavn", + "entity-group-list": "Entitetsgruppeliste", + "entity-group-list-empty": "Ingen entitetsgrupper valgt.", + "name-starts-with": "Entitetsgruppenavn starter med", + "entity-group-name-filter-required": "Entitetsgruppenavnfilter er påkrævet.", + "roles": "Roller", + "permissions": "Tilladelser", + "public": "Offentlig", + "entity-group-public": "Entitetsgruppe er offentlig", + "make-public": "Gør entitetsgruppen offentlig", + "make-private": "Gør entitetsgruppen privat", + "make-public-entity-group-title": "", + "make-public-entity-group-text": "Efter bekræftelsen vil entitetsgruppen og alle dens entiteter blive gjort offentlige og tilgængelige for andre.", + "make-private-entity-group-title": "", + "make-private-entity-group-text": "Efter bekræftelsen vil entitetsgruppen og alle dens entiteter blive gjort private og vil ikke være tilgængelige for andre.", + "share": "Del entitetsgruppe", + "copyId": "Kopiér entitetsgruppe-id", + "idCopiedMessage": "Entitetsgruppe-id er blevet kopieret til udklipsholder", + "entity-group-name": "Entitetsgruppenavn", + "all-users": "Alle brugere" + }, + "entity-field": { + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "type": "Type", + "first-name": "Fornavn", + "last-name": "Efternavn", + "email": "E-mail", + "title": "Titel", + "country": "Land", + "state": "Region", + "city": "By", + "address": "Adresse", + "address2": "Adresse 2", + "zip": "Postnummer", + "phone": "Telefon", + "label": "Mærkning" + }, + "entity-view": { + "entity-view": "Entitetsvisning", + "entity-view-required": "Entitetsvisning er påkrævet.", + "entity-views": "Entitetsvisninger", + "management": "Administration af entitetsvisning", + "view-entity-views": "Vis entitetsvisninger", + "entity-view-alias": "Alias for entitetsvisning", + "aliases": "Aliasser for entitetsvisning", + "no-alias-matching": "", + "no-aliases-found": "Ingen aliasser fundet.", + "no-key-matching": "", + "no-keys-found": "Ingen nøgler fundet.", + "create-new-alias": "Opret en ny!", + "create-new-key": "Opret en ny!", + "duplicate-alias-error": "", + "configure-alias": "", + "no-entity-views-matching": "", + "public": "Offentlig", + "alias": "Alias", + "alias-required": "Alias for entitetsvisning er påkrævet.", + "remove-alias": "Fjern alias for entitetsvisning", + "add-alias": "Tilføj alias for entitetsvisning", + "name-starts-with": "Entitetsvisningsnavn starter med", + "entity-view-list": "Liste over entitetsvisning", + "use-entity-view-name-filter": "Anvend filter", + "entity-view-list-empty": "Ingen entitetsvisninger valgt.", + "entity-view-name-filter-required": "Entitetsvisningsnavnfilter er påkrævet.", + "entity-view-name-filter-no-entity-view-matched": "", + "add": "Tilføj entitetsvisning", + "entity-view-public": "Entitetsvisning er offentlig", + "assign-to-customer": "Tildel til kunde", + "assign-entity-view-to-customer": "Tildel entitetsvisning(er) til kunde", + "assign-entity-view-to-customer-text": "Vælg de entitetsvisninger, der skal tildeles til kunden", + "no-entity-views-text": "Ingen entitetsvisninger fundet", + "assign-to-customer-text": "Vælg den kunde, der skal tildeles entitetsvisning(er)", + "entity-view-details": "Oplysninger for entitetsvisning", + "add-entity-view-text": "Tilføj ny entitetsvisning", + "delete": "Slet entitetsvisning", + "assign-entity-views": "Tildel entitetsvisninger", + "assign-entity-views-text": "", + "delete-entity-views": "Slet entitetsvisninger", + "make-public": "Gør entitetsvisning offentlig", + "make-private": "Gør entitetsvisning privat", + "unassign-from-customer": "Fjern tildeling fra kunde", + "unassign-entity-views": "Fjern tildeling af entitetsvisninger", + "unassign-entity-views-action-title": "", + "assign-new-entity-view": "Tildel ny entitetsvisning", + "delete-entity-view-title": "", + "delete-entity-view-text": "Vær forsigtig. Efter bekræftelsen vil entitetsvisningen og alle relaterede data være uoprettelige.", + "delete-entity-views-title": "", + "delete-entity-views-action-title": "", + "delete-entity-views-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte entitetsvisninger blive fjernet, og alle relaterede data vil være uoprettelige.", + "make-public-entity-view-title": "", + "make-public-entity-view-text": "Efter bekræftelsen vil entitetsvisningen og alle dens data blive gjort offentlige og tilgængelige for andre.", + "make-private-entity-view-title": "", + "make-private-entity-view-text": "Efter bekræftelsen vil entitetsvisningen og alle dens data blive gjort private og vil ikke være tilgængelige for andre.", + "unassign-entity-view-title": "", + "unassign-entity-view-text": "Efter bekræftelsen vil entitetsvisningens tildeling blive fjernet og vil ikke være tilgængelig for kunden.", + "unassign-entity-view": "Fjern tildeling af entitetsvisning", + "unassign-entity-views-title": "", + "unassign-entity-views-text": "Efter bekræftelsen vil tildelingen af alle valgte entitetsvisninger blive fjernet og vil ikke være tilgængelige for kunden.", + "entity-view-type": "Entitetsvisningstype", + "entity-view-type-required": "Entitetsvisningstype er påkrævet.", + "select-entity-view-type": "Vælg entitetsvisningstype", + "enter-entity-view-type": "Indtast entitetsvisningstype", + "any-entity-view": "Enhver entitetsvisning", + "no-entity-view-types-matching": "", + "entity-view-type-list-empty": "Der er ikke valgt nogen entitetsvisningstyper.", + "entity-view-types": "Entitetsvisningstyper", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "events": "Begivenheder", + "details": "Oplysninger", + "copyId": "Kopiér entitetsvisnings-id", + "idCopiedMessage": "Entitetsvisnings-id er blevet kopieret til udklipsholder", + "assignedToCustomer": "Tildelt til kunde", + "unable-entity-view-device-alias-title": "Kan ikke slette entitetsvisningsalias", + "unable-entity-view-device-alias-text": "", + "select-entity-view": "Vælg entitetsvisning", + "start-date": "Startdato", + "start-ts": "Starttid", + "end-date": "Slutdato", + "end-ts": "Sluttid", + "date-limits": "Datofrister", + "client-attributes": "Klientattributter", + "shared-attributes": "Delte attributter", + "server-attributes": "Serverattributter", + "timeseries": "Tidsserier", + "client-attributes-placeholder": "Klientattributter", + "shared-attributes-placeholder": "Delte attributter", + "server-attributes-placeholder": "Serverattributter", + "timeseries-placeholder": "Tidsserier", + "target-entity": "Målentitet", + "attributes-propagation": "Overførsel af attributter", + "attributes-propagation-hint": "Entitetsvisning vil automatisk kopiere specificerede attributter fra målentitet, hver gang du gemmer eller opdaterer denne entitetsvisning. Af ydelsesmæssige årsager overføres målenhedsattributter ikke til entitetsvisning ved hver attributændring. Du kan aktivere automatisk overførsel ved at konfigurere regelknuden \"Kopiér til visning\" i din regelkæde og knytte meddelelserne \"Postattributter\" og \"Attributter opdateret\" til den nye regelknude.", + "timeseries-data": "Tidsseriedata", + "timeseries-data-hint": "Konfigurer tidsseriedatanøgler for målentiteten, der vil være tilgængelige for entitetsvisningen. Disse tidsseriedata er skrivebeskyttede.", + "selected-entity-views": "", + "search": "Søg efter entitetsvisninger", + "select-group-to-add": "Vælg målgruppe for at tilføje valgte entitetsvisninger", + "select-group-to-move": "Vælg målgruppe for at flytte valgte entitetsvisninger", + "remove-entity-views-from-group": "", + "group": "Gruppe af entitetsvisninger", + "list-of-groups": "", + "group-name-starts-with": "" + }, + "event": { + "events": "Begivenheder", + "event-type": "Begivenhedstype", + "type-error": "Fejl", + "type-lc-event": "Livscyklusbegivenhed", + "type-rw-event": "Rådata", + "type-stats": "Statistikker", + "type-debug-converter": "Debug", + "type-debug-integration": "Debug", + "type-debug-rule-node": "Debug", + "type-debug-rule-chain": "Debug", + "no-events-prompt": "Ingen begivenheder fundet", + "error": "Fejl", + "alarm": "Alarm", + "event-time": "Begivenhedstidspunkt", + "server": "Server", + "body": "Tekst", + "method": "Metode", + "type": "Type", + "in": "Ind", + "out": "Ud", + "metadata": "Metadata", + "message": "Meddelelse", + "entity": "Entitet", + "message-id": "Meddelelses-id", + "message-type": "Meddelelsestype", + "data-type": "Datatype", + "relation-type": "Relationstype", + "data": "Data", + "event": "Begivenhed", + "status": "Status", + "success": "Succes", + "failed": "Mislykket", + "messages-processed": "Behandlede meddelelser", + "errors-occurred": "Der opstod fejl", + "uuid": "UUID" + }, + "extension": { + "extensions": "Udvidelser", + "selected-extensions": "", + "type": "Type", + "key": "Nøgle", + "value": "Værdi", + "id": "Id", + "extension-id": "Udvidelses-id", + "extension-type": "Udvidelsestype", + "transformer-json": "JSON *", + "unique-id-required": "Aktuelt udvidelses-id findes allerede.", + "delete": "Slet udvidelse", + "add": "Tilføj udvidelse", + "edit": "Rediger udvidelse", + "view": "Vis udvidelse", + "delete-extension-title": "", + "delete-extension-text": "Vær forsigtig. Efter bekræftelsen vil udvidelsen og alle relaterede data være uoprettelige.", + "delete-extensions-title": "", + "delete-extensions-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte udvidelser blive fjernet.", + "converters": "Omformere", + "converter-id": "Omformer-id", + "configuration": "Konfiguration", + "converter-configurations": "Omformerkonfigurationer", + "token": "Sikkerhedstoken", + "add-converter": "Tilføj omformer", + "add-config": "Tilføj omformerkonfiguration", + "device-name-expression": "Enhedsnavnudtryk", + "device-type-expression": "Enhedstypeudtryk", + "custom": "Brugerdefineret", + "to-double": "Til dobbelt", + "transformer": "Transformer", + "json-required": "Transformer-json er påkrævet.", + "json-parse": "Kan ikke parse transformer-json.", + "attributes": "Attributter", + "add-attribute": "Tilføj attribut", + "add-map": "Tilføj tilknytningselement", + "timeseries": "Tidsserier", + "add-timeseries": "Tilføj tidsserier", + "field-required": "Felt er påkrævet", + "brokers": "Mæglere", + "add-broker": "Tilføj mægler", + "host": "Vært", + "port": "Port", + "port-range": "Porten skal ligge i området fra 1 til 65535.", + "ssl": "Ssl", + "credentials": "Brugeroplysninger", + "username": "Brugernavn", + "password": "Adgangskode", + "retry-interval": "Forsøg interval igen i millisekunder", + "sas": "Signatur for delt adgang", + "anonymous": "Anonym", + "basic": "Basis", + "pem": "PEM", + "ca-cert": "CA-certifikatfil *", + "private-key": "Privat nøglefil *", + "cert": "Certifikatfil *", + "no-file": "Ingen fil valgt.", + "drop-file": "Træk og slip en fil, eller klik for at vælge en fil, der skal uploades.", + "mapping": "Tilknytning", + "topic-filter": "Emnefilter", + "converter-type": "Omformertype", + "converter-json": "Json", + "json-name-expression": "Udtryk for enhedsnavn json", + "topic-name-expression": "Udtryk for enhedsnavnemne", + "json-type-expression": "Udtryk for enhedstype json", + "topic-type-expression": "Udtryk for enhedstypeemne", + "attribute-key-expression": "Udtryk for attributnøgle", + "attr-json-key-expression": "Udtryk for attributnøgle json", + "attr-topic-key-expression": "Udtryk for attributnøgleemne", + "request-id-expression": "Udtryk for anmodnings-id", + "request-id-json-expression": "Udtryk for anmodnings-id json", + "request-id-topic-expression": "Udtryk for anmodnings-id emne", + "response-topic-expression": "Udtryk for svaremne", + "value-expression": "Udtryk for værdi", + "topic": "Emne", + "timeout": "Timeout i millisekunder", + "converter-json-required": "Omformer-json er påkrævet.", + "converter-json-parse": "Omformeren json kunne ikke parses.", + "filter-expression": "Udtryk for filter", + "connect-requests": "Tilslutningsanmodninger", + "add-connect-request": "Tilføj tilslutningsanmodning", + "disconnect-requests": "Afbryd anmodninger", + "add-disconnect-request": "Tilføj afbrydelsesanmodning", + "attribute-requests": "Attributanmodninger", + "add-attribute-request": "Tilføj attributanmodning", + "attribute-updates": "Attributopdateringer", + "add-attribute-update": "Tilføj attributopdatering", + "server-side-rpc": "Serverside RPC", + "add-server-side-rpc-request": "Tilføj serverside RPC-anmodning", + "device-name-filter": "Enhedsnavnfilter", + "attribute-filter": "Attributfilter", + "method-filter": "Metodefilter", + "request-topic-expression": "Anmod om udtryk for emne", + "response-timeout": "Svartimeout i millisekunder", + "topic-expression": "Udtryk for emne", + "client-scope": "Klientomfang", + "add-device": "Tilføj enhed", + "opc-server": "Servere", + "opc-add-server": "Tilføj server", + "opc-add-server-prompt": "Tilføj venligst server", + "opc-application-name": "Applikationsnavn", + "opc-application-uri": "Applikation uri", + "opc-scan-period-in-seconds": "Scanningsperiode i sekunder", + "opc-security": "Sikkerhed", + "opc-identity": "Identitet", + "opc-keystore": "Keystore", + "opc-type": "Type", + "opc-keystore-type": "Type", + "opc-keystore-location": "Placering *", + "opc-keystore-password": "Adgangskode", + "opc-keystore-alias": "Alias", + "opc-keystore-key-password": "Nøgleadgangskode", + "opc-device-node-pattern": "Mønster for enhedsknude", + "opc-device-name-pattern": "Mønster for enhedsnavn", + "modbus-server": "Servere/slaver", + "modbus-add-server": "Tilføj server/slave", + "modbus-add-server-prompt": "Tilføj venligst server/slave", + "modbus-transport": "Transport", + "modbus-tcp-reconnect": "Automatisk gentilslutning", + "modbus-rtu-over-tcp": "RTU over TCP", + "modbus-port-name": "Serielt portnavn", + "modbus-encoding": "Kodning", + "modbus-parity": "Paritet", + "modbus-baudrate": "Baudrate", + "modbus-databits": "Databits", + "modbus-stopbits": "Stopbits", + "modbus-databits-range": "Databits skal ligge i området fra 7 til 8.", + "modbus-stopbits-range": "Stopbits skal ligge i området fra 1 til 2.", + "modbus-unit-id": "Enheds-id", + "modbus-unit-id-range": "Enheds-id skal ligge i området fra 1 til 247.", + "modbus-device-name": "Enhedsnavn", + "modbus-poll-period": "Undersøgelsesperiode (ms)", + "modbus-attributes-poll-period": "Attributundersøgelsesperiode (ms)", + "modbus-timeseries-poll-period": "Tidsserieundersøgelsesperiode (ms)", + "modbus-poll-period-range": "Undersøgelsesperioden skal have positiv værdi.", + "modbus-tag": "Tag", + "modbus-function": "Funktion", + "modbus-register-address": "Registeradresse", + "modbus-register-address-range": "Registeradresse skal ligge i området fra 0 til 65535.", + "modbus-register-bit-index": "Bitindeks", + "modbus-register-bit-index-range": "Bitindeks skal ligge i området fra 0 til 15.", + "modbus-register-count": "Registeroptælling", + "modbus-register-count-range": "Registeroptælling skal være en positiv værdi.", + "modbus-byte-order": "Byterækkefølge", + "sync": { + "status": "Status", + "sync": "Synkroniseret", + "not-sync": "Ikke synkroniseret", + "last-sync-time": "Sidste synkroniseringstidspunkt", + "not-available": "Ikke til rådighed" + }, + "export-extensions-configuration": "Konfiguration af eksportér udvidelser", + "import-extensions-configuration": "Konfiguration af importér udvidelser", + "import-extensions": "Importér udvidelser", + "import-extension": "Importér udvidelse", + "export-extension": "Eksportér udvidelse", + "file": "Fil for udvidelser", + "invalid-file-error": "Ugyldig udvidelsesfil", + "text": "TEKST", + "json": "JSON", + "binary": "BINÆR", + "hex": "HEX" + }, + "filter": { + "add": "Tilføj filter", + "edit": "Rediger filter", + "name": "Filternavn", + "name-required": "Filternavn er påkrævet.", + "duplicate-filter": "Filter med samme navn findes allerede.", + "filters": "Filtre", + "unable-delete-filter-title": "Filteret kunne ikke slettes", + "unable-delete-filter-text": "", + "duplicate-filter-error": "", + "missing-key-filters-error": "", + "filter": "Filter", + "editable": "Redigerbar", + "no-filters-found": "Ingen filtre fundet.", + "no-filter-text": "Intet filter angivet", + "add-filter-prompt": "Tilføj venligst filter", + "no-filter-matching": "", + "create-new-filter": "Opret en ny!", + "filter-required": "Filter er påkrævet.", + "operation": { + "operation": "Driftsopgave", + "equal": "lig med", + "not-equal": "ikke lig med", + "starts-with": "starter med", + "ends-with": "slutter med", + "contains": "indeholder", + "not-contains": "indeholder ikke", + "greater": "større end", + "less": "mindre end", + "greater-or-equal": "større end eller lig med", + "less-or-equal": "mindre end eller lig med", + "and": "og", + "or": "eller" + }, + "ignore-case": "ignorer versalfølsomhed", + "value": "Værdi", + "remove-filter": "Fjern filter", + "preview": "Visning af filter", + "no-filters": "Ingen filtre konfigureret", + "add-filter": "Tilføj filter", + "add-complex-filter": "Tilføj komplekst filter", + "add-complex": "Tilføj kompleks", + "complex-filter": "Komplekst filter", + "edit-complex-filter": "Rediger komplekst filter", + "edit-filter-user-params": "Rediger filterprædikat for brugerparametre", + "filter-user-params": "Filtrerprædikat for brugerparametre", + "user-parameters": "Brugerparametre", + "display-label": "Etiket, der skal vises", + "autogenerated-label": "Generer automatisk etiket", + "order-priority": "Prioritet af feltrækkefølge", + "key-filter": "Nøglefilter", + "key-filters": "Nøglefiltre", + "key-name": "Nøglenavn", + "key-name-required": "Nøglenavn er påkrævet.", + "key-type": { + "key-type": "Nøgletype", + "attribute": "Attribut", + "timeseries": "Tidsserier", + "entity-field": "Entitetsfelt", + "constant": "Konstant" + }, + "value-type": { + "value-type": "Værditype", + "string": "Streng", + "numeric": "Numerisk", + "boolean": "Boolesk", + "date-time": "Datotid" + }, + "value-type-required": "Nøgleværditype er påkrævet.", + "key-value-type-change-title": "Er du sikker på, at du vil ændre nøgleværditypen?", + "key-value-type-change-message": "Hvis du bekræfter ny værditype, fjernes alle indtastede nøglefiltre.", + "no-key-filters": "Ingen nøglefiltre konfigureret", + "add-key-filter": "Tilføj nøglefilter", + "remove-key-filter": "Fjern nøglefilter", + "edit-key-filter": "Rediger nøglefilter", + "date": "Dato", + "time": "Tid", + "current-tenant": "Nuværende lejer", + "current-customer": "Nuværende kunde", + "current-user": "Nuværende bruger", + "current-device": "Nuværende enhed", + "default-value": "Standardværdi", + "dynamic-source-type": "Dynamisk kildetype", + "no-dynamic-value": "Ingen dynamisk værdi", + "source-attribute": "Kildeattribut", + "switch-to-dynamic-value": "Skift til dynamisk værdi", + "switch-to-default-value": "Skift til standardværdi", + "inherit-owner": "Nedarv fra ejer", + "source-attribute-not-set": "Hvis kildeattributten ikke er angivet" + }, + "fullscreen": { + "expand": "Udvid til fuld skærm", + "exit": "Afslut fuldskærm", + "toggle": "Skift mellem fuldskærmstilstand", + "fullscreen": "Fuld skærm" + }, + "function": { + "function": "Funktion" + }, + "gateway": { + "add-entry": "Tilføj konfiguration", + "connector-add": "Tilføj ny stikforbindelse", + "connector-enabled": "Aktivér stikforbindelse", + "connector-name": "Navn på stikforbindelse", + "connector-name-required": "Navn på stikforbindelse er påkrævet.", + "connector-type": "Stikforbindelsestype", + "connector-type-required": "Stikforbindelsestype er påkrævet.", + "connectors": "Konfiguration af stikforbindelser", + "create-new-gateway": "Opret en ny gateway", + "create-new-gateway-text": "", + "delete": "Slet konfiguration", + "download-tip": "Download konfigurationsfil", + "gateway": "Gateway", + "gateway-exists": "Enhed med samme navn findes allerede.", + "gateway-name": "Gateway-navn", + "gateway-name-required": "Gateway-navn er påkrævet.", + "gateway-saved": "Gateway-konfigurationen blev gemt.", + "json-parse": "Ikke gyldig JSON.", + "json-required": "Feltet må ikke være tomt.", + "no-connectors": "Ingen stikforbindelser", + "no-data": "Ingen konfigurationer", + "no-gateway-found": "Ingen gateway fundet.", + "no-gateway-matching": "", + "path-logs": "Sti til logfiler", + "path-logs-required": "Sti er påkrævet.", + "remote": "Fjernkonfiguration", + "remote-logging-level": "Logføringsniveau", + "remove-entry": "Fjern konfiguration", + "save-tip": "Gem konfigurationsfil", + "security-type": "Sikkerhedstype", + "security-types": { + "access-token": "Adgangstoken", + "tls": "TLS" + }, + "storage": "Lagring", + "storage-max-file-records": "Maks. antal poster i fil", + "storage-max-files": "Maks. antal filer", + "storage-max-files-min": "Min. antal er 1.", + "storage-max-files-pattern": "Antal er ikke gyldigt.", + "storage-max-files-required": "Antal er påkrævet.", + "storage-max-records": "Maks. antal poster i lagring", + "storage-max-records-min": "Min. antal poster er 1.", + "storage-max-records-pattern": "Antal er ikke gyldigt.", + "storage-max-records-required": "Maks. antal poster er påkrævet.", + "storage-pack-size": "Maks. antal pakkestørrelse for begivenhed", + "storage-pack-size-min": "Min. antal er 1.", + "storage-pack-size-pattern": "Antal er ikke gyldigt.", + "storage-pack-size-required": "Maks. antal pakkestørrelse for begivenhed er påkrævet.", + "storage-path": "Lagringssti", + "storage-path-required": "Lagringssti er påkrævet.", + "storage-type": "Lagringstype", + "storage-types": { + "file-storage": "Lagring af filter", + "memory-storage": "Lagring af hukommelse" + }, + "thingsboard": "ThingsBoard", + "thingsboard-host": "ThingsBoard-vært", + "thingsboard-host-required": "Vært er påkrævet.", + "thingsboard-port": "ThingsBoard-port", + "thingsboard-port-max": "Maks. portnummer er 65535.", + "thingsboard-port-min": "Min. portnummer er 1.", + "thingsboard-port-pattern": "Port er ikke gyldig.", + "thingsboard-port-required": "Port er påkrævet.", + "tidy": "Tidy", + "tidy-tip": "Tidy konfig. JSON", + "title-connectors-json": "", + "tls-path-ca-certificate": "Sti til CA-certifikat på gateway", + "tls-path-client-certificate": "Sti til klientcertifikat på gateway", + "tls-path-private-key": "Sti til privat nøgle på gateway", + "toggle-fullscreen": "Skift til fuld skærm", + "transformer-json-config": "Konfiguration JSON*", + "update-config": "Tilføj/opdater konfiguration JSON" + }, + "grid": { + "delete-item-title": "Er du sikker på, du ønsker at slette dette element?", + "delete-item-text": "Vær forsigtig. Efter bekræftelsen vil dette element og alle relaterede data være uoprettelige.", + "delete-items-title": "", + "delete-items-action-title": "", + "delete-items-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte elementer blive fjernet, og alle relaterede data vil være uoprettelige.", + "add-item-text": "Tilføj nyt element", + "no-items-text": "Ingen elementer fundet", + "item-details": "Oplysninger om element", + "delete-item": "Slet element", + "delete-items": "Slet elementer", + "scroll-to-top": "Gå til toppen" + }, + "help": { + "goto-help-page": "Gå til hjælpesiden" + }, + "home": { + "home": "Hjem", + "profile": "Profil", + "logout": "Log ud", + "menu": "Menu", + "avatar": "Avatar", + "open-user-menu": "Åbn brugermenu" + }, + "import": { + "no-file": "Ingen fil valgt", + "drop-file": "Træk og slip en JSON-fil, eller klik for at vælge en fil, der skal uploades.", + "drop-csv-file": "Træk og slip en CSV-fil, eller klik for at vælge en fil, der skal uploades.", + "drop-file-csv": "Træk og slip en CSV-fil, eller klik for at vælge en fil, der skal uploades.", + "column-value": "Værdi", + "column-title": "Titel", + "column-example": "Eksempel på værdidata", + "column-key": "Attribut-/telemetrinøgle", + "csv-delimiter": "CSV-skilletegn", + "csv-first-line-header": "Første linje indeholder kolonnenavne", + "csv-update-data": "Opdater attributter/telemetri", + "import-csv-number-columns-error": "En fil skal indeholde mindst to kolonner", + "import-csv-invalid-format-error": "", + "column-type": { + "name": "Navn", + "type": "Type", + "label": "Mærkning", + "column-type": "Kolonnetype", + "client-attribute": "Klientattribut", + "shared-attribute": "Delt attribut", + "server-attribute": "Serverattribut", + "timeseries": "Tidsserier", + "entity-field": "Entitetsfelt", + "access-token": "Adgangstoken", + "isgateway": "Er gateway", + "activity-time-from-gateway-device": "Aktivitetstid fra gateway-enhed", + "description": "Beskrivelse" + }, + "stepper-text": { + "select-file": "Vælg en fil", + "configuration": "Importér konfiguration", + "column-type": "Vælg kolonnetype", + "creat-entities": "Oprettelse af nye entiteter", + "done": "Udført" + }, + "message": { + "create-entities": "", + "update-entities": "", + "error-entities": "" + } + }, + "integration": { + "integration": "Integration", + "integrations": "Integrationer", + "select-integration": "Vælg integration", + "no-integrations-matching": "", + "integration-required": "Integration er påkrævet", + "delete": "Slet integration", + "management": "Integrationsstyring", + "add-integration-text": "Tilføj ny integration", + "no-integrations-text": "Ingen integrationer fundet", + "selected-integrations": "", + "delete-integration-title": "", + "delete-integration-text": "Vær forsigtig. Efter bekræftelsen vil integrationen og alle relaterede data være uoprettelige.", + "delete-integrations-title": "", + "delete-integrations-action-title": "", + "delete-integrations-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte integrationer blive fjernet, og alle relaterede data vil være uoprettelige.", + "events": "Begivenheder", + "enabled": "Aktiveret", + "allow-create-devices-or-assets": "Tillad oprettelse af enheder eller aktiver", + "add": "Tilføj integration", + "search": "Søg efter integrationer", + "integration-details": "Integrationsoplysninger", + "details": "Oplysninger", + "copyId": "Kopiér integrations-id", + "idCopiedMessage": "Integrations-id er blevet kopieret til udklipsholder", + "debug-mode": "Debug-tilstand", + "enable-security": "Aktivér sikkerhed", + "enable-security-new": "Aktivér sikkerhed for automatiske tokenopdateringer", + "headers-filter": "Filter for overskrifter", + "header": "Overskrift", + "no-headers-filter": "Intet filter for overskrifter", + "downlink-url": "Downlink URL", + "downlink-url-required": "Downlink URL er påkrævet", + "create-loriot-output": "Opret Loriot-applikationsoutput", + "send-downlink": "Send downlink", + "server": "Server", + "server-required": "Server er påkrævet", + "app-id": "Applikations-id", + "app-id-required": "Applikations-id er påkrævet", + "app-token": "Applikationsadgangstoken", + "app-token-required": "Applikationsadgangstoken er påkrævet", + "email": "E-mail", + "email-required": "E-mail er påkrævet", + "application-uri": "Applikation URI", + "as-id": "AS-id", + "as-id-required": "AS-id er påkrævet.", + "as-key": "AS-nøgle", + "as-key-required": "AS-nøgle er påkrævet.", + "client-id-new": "Klient-id", + "client-id-new-required": "Klient-id (login) er påkrævet (login).", + "client-secret": "Klient hemmelig", + "client-secret-required": "Klient hemmelig (adgangskode) er påkrævet (adgangskode).", + "max-time-diff-in-seconds": "Maksimal tidsforskel (sekunder)", + "max-time-diff-in-seconds-required": "Maksimal tidsforskel er påkrævet.", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL er påkrævet", + "security-key": "Sikkerhedsnøgle", + "http-endpoint": "HTTP-slutpunkts-URL", + "replace-no-content-to-ok": "Erstat svarstatus fra 'Intet indhold' til 'OK'", + "copy-http-endpoint-url": "Kopiér HTTP-slutpunkts-URL", + "http-endpoint-url-copied-message": "HTTP-slutpunkts-URL er blevet kopieret til udklipsholder", + "host": "Vært", + "host-required": "Vært er påkrævet.", + "host-type": "Værtstype", + "host-type-required": "Værtstype er påkrævet.", + "custom-host": "Brugerdefineret vært", + "custom-host-required": "Brugerdefineret vært er påkrævet.", + "port": "Port", + "port-required": "Port er påkrævet.", + "port-range": "Porten skal ligge i området fra 1 til 65535.", + "connect-timeout": "Forbindelsestimeout (sek.)", + "connect-timeout-required": "Forbindelsestimeout er påkrævet.", + "connect-timeout-range": "Forbindelsestimeout skal ligge i området fra 1 til 200.", + "client-id": "Klient-id", + "client-id-required": "Klient-id er påkrævet.", + "client-id-range": "Klient-id skal ligge i et interval fra 1 til 23 tegn. [MQTT-3.1.3-5]", + "client-id-pattern": "Klient-id skal bestå af tal og store og små bogstaver. [MQTT-3.1.3-5]", + "max-bytes-in-message": "Maksimum bytes i meddelelse", + "max-bytes-in-message-range": "Maksimum bytes i meddelelsen skal ligge i området fra 1 til 256000000.", + "device-id": "Enheds-id", + "device-id-required": "Enheds-id er påkrævet.", + "device-id-range": "Enheds-id'et skal ligge i området fra 1 til 65535 tegn.", + "device-id-pattern": "Enheds-id'et skal bestå af tal og store og små bogstaver. [MQTT-3.1.3-5]", + "group-id": "Gruppe-id", + "group-id-required": "Gruppe-id er påkrævet.", + "topics": "Emner", + "topics-required": "Emne er påkrævet.", + "routing-keys": "Routing-nøgler", + "routing-keys-required": "Routing-nøgle er påkrævet.", + "queues": "Køer", + "queues-required": "Kønavn er påkrævet.", + "exchange-name": "Udskiftningsnavn", + "exchange-name-required": "Udskiftningsnavn er påkrævet.", + "downlink-topic": "Downlink-emne", + "connection-timeout": "Forbindelsestimeout, ms", + "connection-timeout-min": "Ugyldig forbindelsestimeoutværdi.", + "handshake-timeout": "Handshake-timeout, ms", + "handshake-timeout-min": "Ugyldig handshake-timeoutværdi.", + "virtual-host": "Virtuel vært", + "rabbit-mq-poll-interval": "Undersøgelsesinterval, ms", + "rabbit-mq-poll-interval-min": "Ugyldig undersøgelsesintervalværdi.", + "application-server-url": "Applikationsserver URL", + "application-server-api-token": "Applikationsserver API-token", + "application-server-api-token-required": "Applikationsserver API-token er påkrævet.", + "bootstrap-servers": "Bootstrap-servere", + "bootstrap-servers-required": "Bootstrap-servere er påkrævet.", + "poll-interval": "Undersøgelsesinterval", + "poll-interval-required": "Undersøgelsesinterval er påkrævet.", + "auto-create-topics": "Opret emner automatisk", + "clean-session": "Ryd session", + "enable-ssl": "Aktivér SSL", + "credentials": "Brugeroplysninger", + "credentials-type": "Type af brugeroplysninger", + "credentials-type-required": "Type af brugeroplysninger er påkrævet.", + "username": "Brugernavn", + "username-required": "Brugernavn er påkrævet.", + "password": "Adgangskode", + "password-required": "Brugernavn er påkrævet.", + "azure-ca-cert": "CA-certifikatfil", + "ca-cert": "CA-certifikatfil *", + "private-key": "Privat nøglefil *", + "private-key-password": "Adgangskode til privat nøgle", + "cert": "Certifikatfil *", + "no-file": "Ingen fil valgt.", + "drop-file": "Træk og slip en fil, eller klik for at vælge en fil, der skal uploades.", + "check-connection": "Kontrollér forbindelsen", + "check-success": "Forbindelse oprettet.", + "topic-filters": "Emnefiltre", + "remove-topic-filter": "Fjern emnefilter", + "add-topic-filter": "Tilføj emnefilter", + "add-topic-filter-prompt": "Tilføj venligst emnefilter", + "topic": "Emne", + "mqtt-qos": "QoS", + "mqtt-qos-at-most-once": "Højst én gang", + "mqtt-qos-at-least-once": "Mindst én gang", + "mqtt-qos-exactly-once": "Præcis én gang", + "downlink-topic-pattern": "Mønster for downlink-emne", + "downlink-topic-pattern-required": "Mønster for downlink-emne er påkrævet.", + "aws-access-key-id": "AWS-adgangsnøgle-id", + "aws-secret-access-key": "AWS hemmelig adgangsnøgle", + "aws-region": "Region", + "aws-iot-endpoint": "AWS IoT-slutpunkt", + "aws-iot-endpoint-required": "AWS IoT-slutpunkt er påkrævet.", + "aws-iot-credentials": "AWS IoT-brugeroplysninger", + "aws-sqs-polling-period-in-seconds": "Undersøgelsesperiode i sekunder", + "aws-sqs-queue-url": "SQS Kø URL", + "aws-sqs-queue-url-required": "SQS Kø URL er påkrævet", + "aws-sqs-access-key-id-required": "Adgangsnøgle-id er påkrævet", + "aws-sqs-secret-access-key-required": "Hemmelig adgangsnøgle er påkrævet", + "application-credentials": "Applikationsbrugeroplysninger", + "api-key": "API-nøgle", + "api-key-required": "API-nøgle er påkrævet.", + "api-key-format": "Ugyldigt API-nøgleformat.", + "auth-token": "Godkendelsestoken", + "auth-token-required": "Godkendelsestoken er påkrævet.", + "region": "Region", + "region-required": "Region er påkrævet.", + "application-id": "Applikations-id", + "application-id-required": "Applikations-id er påkrævet.", + "access-key": "Adgangsnøgle", + "access-key-required": "Adgangsnøgle er påkrævet.", + "connection-parameters": "Tilslutningsparametre", + "service-bus-namespace-name": "Namespace-navn for servicebus", + "service-bus-namespace-name-required": "Namespace-navn for servicebus er påkrævet.", + "connection-string": "Tilslutningsstreng", + "connection-string-required": "Tilslutningsstreng påkrævet!", + "event-hub-name": "Navn på begivenhedshub", + "event-hub-name-required": "Navn på begivenhedshub er påkrævet.", + "event-iot-hub-name-required": "Iot-hubnavn er påkrævet for downlink", + "sas-key-name": "SAS-nøglenavn", + "sas-key-name-required": "SAS-nøglenavn er påkrævet.", + "sas-key": "SAS-nøgle", + "sas-key-required": "SAS-nøgle er påkrævet.", + "iot-hub-name": "IoT-hubnavn (påkrævet for downlink)", + "hostname": "Værtsnavn", + "hostname-required": "Værtsnavn er påkrævet", + "integration-clazz": "Integrationsklasse", + "integration-clazz-required": "Integrationsklasse er påkrævet", + "integration-configuration": "Konfiguration af integration JSON", + "metadata": "Metadata", + "type": "Type", + "type-required": "Type er påkrævet.", + "uplink-converter": "Uplink-dataomformer", + "uplink-converter-required": "Uplink-dataomformer er påkrævet.", + "downlink-converter": "Downlink-dataomformer", + "type-http": "HTTP", + "type-ocean-connect": "OceanConnect", + "type-sigfox": "SigFox", + "type-thingpark": "ThingPark", + "type-loriot": "Loriot", + "type-thingpark-enterprise": "ThingParkEnterprise", + "type-tmobile-iot-cdp": "T-Mobile – IoT CDP", + "type-mqtt": "MQTT", + "type-aws-iot": "AWS IoT", + "type-aws-sqs": "AWS SQS", + "type-aws-kinesis": "AWS-kinese", + "type-ibm-watson-iot": "IBM Watson IoT", + "type-ttn": "TheThingsNetwork", + "type-tti": "The Things Stack", + "type-chirpstack": "ChirpStack", + "type-azure-event-hub": "Azure-begivenhedshub", + "type-azure-iot-hub": "Azure IoT-hub", + "type-opc-ua": "OPC-UA", + "type-custom": "Brugerdefineret", + "type-udp": "UDP", + "type-tcp": "TCP", + "type-kafka": "Kafka", + "type-rabbitmq": "RabbitMQ", + "type-pubsub": "Pub/Sub", + "opc-ua-application-name": "Applikationsnavn", + "opc-ua-application-uri": "Applikation uri", + "opc-ua-scan-period-in-seconds": "Scanningsperiode i sekunder", + "opc-ua-scan-period-in-seconds-required": "Scanningsperiode er påkrævet", + "opc-ua-timeout": "Timeout i millisekunder", + "opc-ua-timeout-required": "Timeout er påkrævet", + "opc-ua-security": "Sikkerhed", + "opc-ua-security-required": "Sikkerhed er påkrævet", + "opc-ua-identity": "Identitet", + "opc-ua-identity-required": "Identitet er påkrævet", + "opc-ua-keystore": "Keystore", + "add-opc-ua-keystore-prompt": "Tilføj venligst keystore-fil", + "opc-ua-keystore-required": "Keystore er påkrævet", + "opc-ua-type": "Type", + "opc-ua-keystore-type": "Type", + "opc-ua-keystore-type-required": "Type er påkrævet", + "opc-ua-keystore-location": "Placering *", + "opc-ua-keystore-password": "Adgangskode", + "opc-ua-keystore-password-required": "Adgangskode er påkrævet", + "opc-ua-keystore-alias": "Alias", + "opc-ua-keystore-alias-required": "Alias er påkrævet", + "opc-ua-keystore-key-password": "Nøgleadgangskode", + "opc-ua-keystore-key-password-required": "Adgangskode er påkrævet", + "opc-ua-mapping": "Tilknytning", + "add-opc-ua-mapping-prompt": "Tilføj tilknytning", + "opc-ua-mapping-type": "Tilknytningstype", + "opc-ua-mapping-type-required": "Tilknytningstype er påkrævet", + "opc-ua-device-node-pattern": "Enhedsknudemønster", + "opc-ua-device-node-pattern-required": "Enhedsknudemønster er påkrævet", + "opc-ua-namespace": "Namespace", + "opc-ua-add-map": "Tilføj tilknytningselement", + "kinesis-stream-name": "Streamnavn", + "kinesis-stream-name-required": "Streamnavn er påkrævet", + "kinesis-region": "Region", + "kinesis-region-required": "Region er påkrævet", + "kinesis-access-key-id": "Adgangsnøgle-id", + "kinesis-access-key-id-required": "Adgangsnøgle-id er påkrævet", + "kinesis-secret-access-key": "Hemmelig adgangsnøgle", + "kinesis-secret-access-key-required": "Hemmelig adgangsnøgle er påkrævet", + "kinesis-use-consumers-with-enhanced-fan-out": "Anvend forbrugere med forbedret Fan-Out", + "kinesis-use-credentials-from-instance-metadata": "Anvend brugeroplysninger fra Amazon EC2 Instance Metadata Service", + "kinesis-application-name": "Applikationsnavn (som standard lig med Streamnavn)", + "kinesis-initial-position-in-stream": "Startposition i stream", + "kinesis-initial-position-in-stream-required": "Startposition i stream påkrævet", + "kinesis-max-records": "Maks. poster", + "kinesis-max-records-required": "Maks. poster er påkrævet", + "kinesis-max-records-length-range": "Maks. længde for poster skal ligge i et område fra 1 til 10000", + "kinesis-request-timeout": "Anmodningstimeout i sekunder", + "kinesis-request-timeout-required": "Anmodningstimeout er påkrævet", + "other-properties": "Andre egenskaber", + "subscription-tags": "Abonnementstags", + "remove-subscription-tag": "Fjern abonnementstags", + "add-subscription-tag": "Tilføj abonnementstags", + "add-subscription-tag-prompt": "Tilføj venligst abonnementstags", + "key": "Nøgle", + "path": "Sti", + "required": "Påkrævet", + "integration-key": "Integrationsnøgle", + "copy-integration-key": "Kopiér integrationsnøgle", + "integration-key-copied-message": "Integrationsnøgle er blevet kopieret til udklipsholder", + "integration-secret": "Integration hemmelig", + "copy-integration-secret": "Kopiér integration hemmelig", + "integration-secret-copied-message": "Integration hemmelig er kopieret til udklipsholder", + "execute-remotely": "Fjernbetjent udførelse", + "handler-configuration": "Handler-konfiguration", + "handler-configuration-type": "Handler-type", + "so-broadcast": "Aktivér broadcast – integration accepterer adressepakker for broadcast", + "so-keepalive-option": "Muliggør afsendelse af keepalive-meddelelser på tilslutningsorienterede stik", + "so-reuse-addr": "Bind processen til en port", + "tcp-no-delay": "Tvinger et stik til at sende data uden buffer (deaktiver Nagle's bufferalgoritme)", + "fail-fast": "Undtagelse, når dekoderen bemærker, at rammelængden vil overstige maksimumstørrelse", + "strip-delimiter": "Fjern skilletegn", + "length-field-offset": "Feltforskydning for længde", + "length-field-offset-required": "Feltforskydning for længde er påkrævet.", + "length-field-offset-range": "Feltforskydning for længde skal ligge i et område fra 0 til 8.", + "length-field-length": "Længdefeltlængde", + "length-field-length-required": "Længdefeltlængde er påkrævet.", + "length-field-length-range": "Længdefeltlængde skal ligge i et område fra 0 til 8.", + "length-adjustment": "Længdejustering (kompenseringsværdien, der skal lægges til værdien af længdefeltet)", + "length-adjustment-required": "Længdejustering er påkrævet.", + "length-adjustment-range": "Længdejustering skal ligge i et område fra 0 til 8.", + "byte-order": "Byterækkefølge for længdefeltet", + "initial-bytes-to-strip": "Antal første bytes, der skal fjernes fra den afkodede ramme", + "initial-bytes-to-strip-required": "Antal første bytes, der skal fjernes fra den afkodede ramme, er påkrævet.", + "initial-bytes-to-strip-range": "Antal første bytes, der skal fjernes fra den afkodede ramme, skal ligge i området fra 0 til 8.", + "so-backlog-option": "Maks. antal ventende tilslutninger på stikket", + "so-backlog-option-required": "Maks. antal ventende tilslutninger på stikket er påkrævet.", + "so-backlog-option-range": "Maks. antal ventende tilslutninger på stikket skal ligge i området fra 1 til 65535.", + "so-rcv-buf": "Bufferens størrelse til indgående stik (i KB)", + "so-rcv-buf-required": "Bufferens størrelse til indgående stik (i KB) er påkrævet.", + "so-rcv-buf-range": "Bufferens størrelse til indgående stik (i KB) skal ligge i området fra 1 til 65535.", + "so-snd-buf": "Bufferens størrelse til udgående stik (i KB)", + "so-snd-buf-required": "Bufferens størrelse til udgående stik (i KB) er påkrævet.", + "so-snd-buf-range": "Bufferens størrelse til udgående stik (i KB) skal ligge i et område fra 1 til 65535.", + "charset-name": "Tegnsætnavn", + "charset-name-required": "Tegnsætnavn er påkrævet.", + "message-separator": "Meddelelsesseparator", + "message-separator-required": "Meddelelsesseparator er påkrævet.", + "character-sequence": "Tegnsekvens", + "character-sequence-required": "Tegnsekvens er påkrævet.", + "max-frame-length": "Maks. rammelængde (i bytes)", + "max-frame-length-required": "Maks. rammelængde (i bytes) er påkrævet.", + "max-frame-length-range": "Maks. rammelængde (i byte) skal ligge i området fra 1 til 65535.", + "handler-type": "Handler-type", + "message-size": "Meddelelsesstørrelse", + "message-size-required": "Meddelelsesstørrelse er påkrævet.", + "type-apache-pulsar": "Apache Pulsar", + "service-url": "Service-URL", + "service-url-required": "Service-URL er påkrævet.", + "subscription-name": "Abonnementsnavn", + "subscription-name-required": "Abonnementsnavn er påkrævet.", + "max-num-messages": "Maks. antal meddelelser", + "max-num-messages-required": "Maks. antal meddelelser er påkrævet.", + "max-num-bytes": "Maks. antal bytes", + "max-num-bytes-required": "Maks. antal bytes påkrævet.", + "timeout-in-ms": "Timeout i millisekunder", + "timeout-in-ms-required": "Timeout i millisekunder er påkrævet.", + "user-id": "Bruger-id", + "user-id-required": "Bruger-id er påkrævet.", + "token": "Token", + "token-required": "Token er påkrævet.", + "project-id": "Projekt-id", + "project-id-required": "Projekt-id er påkrævet.", + "subscription-id": "Abonnements-id", + "subscription-id-required": "Abonnements-id er påkrævet.", + "service-account-key": "Nøglefil til servicekonto", + "service-account-key-required": "Nøglefil til servicekonto er påkrævet.", + "tcp": { + "system-line-separator": "Systemlinjeseparator", + "nul-delimiter": "Nul-skilletegn", + "byte-order-little-endian": "Little Endian", + "byte-order-big-endian": "Big Endian" + }, + "cache-size": "Cachestørrelse", + "cache-time-to-live": "Cache time-to-live i minutter", + "min-cache-size": "Cachestørrelse kan ikke være lavere 0", + "min-cache-time-to-live": "Cache time-to-live kan ikke være lavere 0", + "max-cache-time-to-live": "Ugyldigt cache time-to-live, vælg mellem 0 og 525600" + }, + "item": { + "selected": "Valgt" + }, + "js-func": { + "no-return-error": "Funktionen skal returnere værdi!", + "return-type-mismatch": "", + "tidy": "Tidy", + "mini": "Mini" + }, + "key-val": { + "key": "Nøgle", + "value": "Værdi", + "remove-entry": "Fjern post", + "add-entry": "Tilføj post", + "no-data": "Ingen poster" + }, + "layout": { + "layout": "Layout", + "manage": "Administrer layouts", + "settings": "Layoutindstillinger", + "color": "Farve", + "main": "Hoved", + "right": "Højre", + "select": "Vælg mållayout" + }, + "legend": { + "direction": "Signaturforklaringens retning", + "position": "Signaturforklaringens placering", + "sort-legend": "Sortér datanøgler i signaturforklaring", + "show-max": "Vis maks. værdi", + "show-min": "Vis min. værdi", + "show-avg": "Vis gennemsnitsværdi", + "show-total": "Vis samlet værdi", + "settings": "Indstillinger for signaturforklaring", + "min": "min.", + "max": "maks.", + "avg": "gns.", + "total": "i alt", + "comparison-time-ago": { + "previousInterval": "(tidligere interval)", + "days": "(dag siden)", + "weeks": "(uge siden)", + "months": "(måned siden)", + "years": "(år siden)" + } + }, + "login": { + "login": "Log på", + "request-password-reset": "Anmod om nulstilling af adgangskode", + "reset-password": "Nulstil adgangskode", + "create-password": "Opret adgangskode", + "passwords-mismatch-error": "De indtastede adgangskoder skal være ens!", + "password-again": "Gentag adgangskode", + "sign-in": "Log på", + "username": "Brugernavn (e-mail)", + "remember-me": "Husk mig", + "forgot-password": "Glemt adgangskode?", + "password-reset": "Nulstilling af adgangskode", + "expired-password-reset-message": "Dine brugeroplysninger er udløbet! Opret venligst en ny adgangskode.", + "new-password": "Ny adgangskode", + "new-password-again": "Gentag ny adgangskode", + "password-link-sent-message": "Link til nulstilling af adgangskode blev sendt!", + "email": "E-mail", + "no-account": "Har du ikke en konto?", + "create-account": "Opret en konto", + "login-with": "Log ind med din e-mail", + "or": "eller", + "error": "Login-fejl" + }, + "signup": { + "firstname": "Fornavn", + "lastname": "Efternavn", + "email": "E-mail", + "signup": "Tilmeld", + "create-password": "Opret en adgangskode", + "repeat-password": "Gentag din adgangskode", + "have-account": "Har du allerede en konto?", + "signin": "Log på", + "no-captcha-message": "Du skal bekræfte, at du ikke er en robot", + "password-length-message": "Din adgangskode skal bestå af mindst 6 tegn", + "email-verification": "E-mailbekræftelse", + "email-verification-message": "Der er sendt en e-mail med bekræftelsesoplysninger til den angivne e-mailadresse.
              Følg instruktionerne i e-mailen for at fuldføre din tilmeldingsprocedure.
              Bemærk: Hvis du ikke har set e-mailen efter et stykke tid, skal du tjekke din 'spam'-mappe eller forsøge at sende e-mailen igen ved at klikke på knappen 'Send igen'.", + "account-activation-title": "Aktivering af konto", + "account-activated": "Kontoen er aktiveret!", + "account-activated-text": "Tillykke!
              Din konto er blevet aktiveret.", + "resend": "Send igen", + "inactive-user-exists-title": "Inaktiv bruger findes allerede", + "inactive-user-exists-text": "Der er allerede registreret en bruger med en ikke-bekræftet e-mailadresse.
              Klik på knappen \"Send igen\", hvis du ønsker at sende bekræftelses-e-mailen igen.", + "activating-account": "Aktiverer konto...", + "activating-account-text": "Din konto er i øjeblikket ved at blive aktiveret. Vent venligst...", + "accept-privacy-policy": "Accepter fortrolighedspolitik", + "accept": "Accepter", + "privacy-policy": "Fortrolighedspolitik" + }, + "position": { + "top": "Top", + "bottom": "Bund", + "left": "Venstre", + "right": "Højre" + }, + "profile": { + "profile": "Profil", + "last-login-time": "Sidste login", + "change-password": "Skift adgangskode", + "current-password": "Nuværende adgangskode" + }, + "relation": { + "relations": "Relationer", + "direction": "Retning", + "search-direction": { + "FROM": "Fra", + "TO": "Til" + }, + "direction-type": { + "FROM": "fra", + "TO": "til" + }, + "from-relations": "Udgående relationer", + "to-relations": "Indgående relationer", + "selected-relations": "", + "type": "Type", + "to-entity-type": "Til entitetstype", + "to-entity-name": "Til entitetsnavn", + "from-entity-type": "Fra entitetstype", + "from-entity-name": "Fra entitetsnavn", + "to-entity": "Til entitet", + "from-entity": "Fra entitet", + "delete": "Slet relation", + "relation-type": "Relationstype", + "relation-type-required": "Relationstype er påkrævet.", + "any-relation-type": "Enhver type", + "add": "Tilføj relation", + "edit": "Rediger relation", + "delete-to-relation-title": "", + "delete-to-relation-text": "", + "delete-to-relations-title": "", + "delete-to-relations-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte relationer blive fjernet, og tilsvarende entiteter vil ikke være relaterede til den aktuelle entitet.", + "delete-from-relation-title": "", + "delete-from-relation-text": "", + "delete-from-relations-title": "", + "delete-from-relations-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte relationer blive fjernet, og den aktuelle entitet vil ikke være relateret til de tilsvarende entiteter.", + "remove-relation-filter": "Fjern relationsfilter", + "add-relation-filter": "Tilføj relationsfilter", + "any-relation": "Enhver relation", + "relation-filters": "Relationsfiltre", + "additional-info": "Yderligere info (JSON)", + "invalid-additional-info": "Kan ikke parse yderligere info-json.", + "no-relations-text": "Ingen relationer fundet" + }, + "rulechain": { + "rulechain": "Regelkæde", + "rulechains": "Regelkæder", + "root": "Rod", + "delete": "Slet regelkæde", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "add": "Tilføj regelkæde", + "set-root": "Lav regelkæde for rod", + "set-root-rulechain-title": "", + "set-root-rulechain-text": "Efter bekræftelsen vil regelkæden være rod og håndtere alle indgående transportmeddelelser.", + "delete-rulechain-title": "", + "delete-rulechain-text": "Vær forsigtig. Efter bekræftelsen vil regelkæden og alle relaterede data være uoprettelige.", + "delete-rulechains-title": "", + "delete-rulechains-action-title": "", + "delete-rulechains-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte regelkæder blive fjernet, og alle relaterede data vil være uoprettelige.", + "add-rulechain-text": "Tilføj ny regelkæde", + "no-rulechains-text": "Ingen regelkæder fundet", + "rulechain-details": "Oplysninger om regelkæde", + "details": "Oplysninger", + "events": "Begivenheder", + "system": "System", + "import": "Importér regelkæde", + "export": "Eksportér regelkæde", + "export-failed-error": "", + "create-new-rulechain": "Opret ny regelkæde", + "rulechain-file": "Regelkædefil", + "invalid-rulechain-file-error": "Regelkæden kunne ikke importeres: Ugyldig datastruktur for regelkæde.", + "copyId": "Kopiér regelkæde-id", + "idCopiedMessage": "Regelkæde-id er blevet kopieret til udklipsholder", + "select-rulechain": "Vælg regelkæde", + "no-rulechains-matching": "", + "rulechain-required": "Regelkæde er påkrævet", + "management": "Regelstyring", + "debug-mode": "Debug-tilstand", + "search": "Søg efter regelkæder", + "selected-rulechains": "", + "open-rulechain": "Åbn regelkæde" + }, + "rulenode": { + "details": "Oplysninger", + "events": "Begivenheder", + "search": "Søg efter knuder", + "open-node-library": "Åbn knudebibliotek", + "add": "Tilføj regelknude", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "type": "Type", + "description": "Beskrivelse", + "delete": "Slet regelknude", + "select-all-objects": "Vælg alle knuder og tilslutninger", + "deselect-all-objects": "Fravælg alle knuder og tilslutninger", + "delete-selected-objects": "Slet valgte knuder og tilslutninger", + "delete-selected": "Slet valgte", + "select-all": "Vælg alle", + "copy-selected": "Kopiér valgte", + "deselect-all": "Fravælg alle", + "rulenode-details": "Oplysninger om regelknude", + "debug-mode": "Debug-tilstand", + "configuration": "Konfiguration", + "link": "Link", + "link-details": "Oplysninger om regelknudelink", + "add-link": "Tilføj link", + "link-label": "Link-etiket", + "link-label-required": "Link-etiket er påkrævet.", + "custom-link-label": "Brugerdefineret link-etiket", + "custom-link-label-required": "Brugerdefineret link-etiket er påkrævet.", + "link-labels": "Link-etiketter", + "link-labels-required": "Link-etiketter er påkrævet.", + "no-link-labels-found": "Ingen link-etiketter fundet", + "no-link-label-matching": "", + "create-new-link-label": "Opret en ny!", + "type-filter": "Filter", + "type-filter-details": "Filtrer indgående meddelelser med konfigurerede betingelser", + "type-enrichment": "Berigelse", + "type-enrichment-details": "Tilføj yderligere oplysninger i meddelelsesmetadata", + "type-transformation": "Omdannelse", + "type-transformation-details": "Skift meddelelsesdata og metadata", + "type-action": "Handling", + "type-action-details": "Gennemfør ekstrahandling", + "type-analytics": "Analytik", + "type-analytics-details": "Udfør analyse af streamede eller vedvarende data", + "type-external": "Ekstern", + "type-external-details": "Interagerer med eksternt system", + "type-rule-chain": "Regelkæde", + "type-rule-chain-details": "Videresender indgående meddelelser til specificeret regelkæde", + "type-input": "Input", + "type-input-details": "Logisk input af regelkæde, videresender indgående meddelelser til næste relaterede regelknude", + "type-unknown": "Ukendt", + "type-unknown-details": "Uløst regelknude", + "directive-is-not-loaded": "", + "ui-resources-load-error": "Kunne ikke indlæse konfigurations-UI-ressourcer.", + "invalid-target-rulechain": "Kan ikke løse målregelkæde!", + "test-script-function": "Testscriptfunktion", + "message": "Meddelelse", + "message-type": "Meddelelsestype", + "select-message-type": "Vælg meddelelsestype", + "message-type-required": "Meddelelsestype er påkrævet", + "metadata": "Metadata", + "metadata-required": "Metadataposter må ikke være tomme.", + "output": "Output", + "test": "Test", + "help": "Hjælp", + "reset-debug-mode": "Nulstil debug-tilstand i alle knuder" + }, + "role": { + "role": "Rolle", + "roles": "Roller", + "management": "Rollestyring", + "view-roles": "Vis roller", + "no-roles-matching": "", + "role-list": "Rolleliste", + "add": "Tilføj rolle", + "view": "Vis rolle", + "search": "Søg efter roller", + "selected-roles": "", + "no-roles-text": "Ingen roller fundet", + "role-details": "Rolleoplysninger", + "add-role-text": "Tilføj ny rolle", + "delete": "Slet rolle", + "delete-roles": "Slet roller", + "delete-role-title": "", + "delete-role-text": "Vær forsigtig. Efter bekræftelsen vil rollen og alle relaterede data være uoprettelige.", + "delete-roles-title": "", + "delete-roles-action-title": "", + "delete-roles-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte roller blive fjernet, og alle relaterede data vil være uoprettelige.", + "role-type": "Rolletype", + "role-type-required": "Rolletype er påkrævet.", + "select-role-type": "Vælg rolletype", + "enter-role-type": "Indtast rolletype", + "any-role": "Enhver rolle", + "no-role-types-matching": "", + "role-type-list-empty": "Ingen rolletyper valgt.", + "role-types": "Rolletyper", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "description": "Beskrivelse", + "events": "Begivenheder", + "details": "Oplysninger", + "copyId": "Kopiér rolle-id", + "idCopiedMessage": "Rolle-id er blevet kopieret til udklipsholder", + "permissions": "Tilladelser", + "role-required": "Rolle påkrævet", + "roles-required": "Roller påkrævet", + "display-type": { + "GENERIC": "Generisk", + "GROUP": "Gruppe" + } + }, + "group-permission": { + "user-group-roles": "Brugergrupperoller", + "entity-group-permissions": "Tilladelser for entitetsgruppe", + "role-type": "Rolletype", + "role-name": "Rollenavn", + "group-type": "Gruppetype", + "group-name": "Gruppenavn", + "group-owner": "Gruppeejer", + "user-group-name": "Brugergruppenavn", + "user-group-owner": "Brugergruppeejer", + "edit": "Rediger tilladelser", + "delete": "Slet tilladelser", + "selected-group-permissions": "", + "delete-group-permission-title": "", + "delete-group-permission-text": "Vær forsigtig. Efter bekræftelsen vil gruppetilladelsen og alle relaterede data være uoprettelige.", + "delete-group-permission": "Slet gruppetilladelse", + "delete-group-permissions-title": "", + "delete-group-permissions-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte gruppetilladelser blive fjernet, og tilsvarende brugere vil miste adgang til specificerede ressourcer.", + "delete-group-permissions": "Slet gruppetilladelser", + "add-group-permission": "Tilføj gruppetilladelse", + "edit-group-permission": "Rediger gruppetilladelse", + "entity-group": "Entitetsgruppe", + "user-group": "Brugergruppe", + "no-owners-matching": "", + "target-owner-required": "Entitetsgruppeejer er påkrævet.", + "target-user-group-owner-required": "Brugergruppeejer er påkrævet.", + "no-group-permissions-text": "Ingen gruppetilladelser fundet" + }, + "permission": { + "permissions-required": "Mindst én tilladelsespost skal angives.", + "remove-permission": "Fjern tilladelsespost", + "add-permission": "Tilføj tilladelsespost", + "other": "Andet", + "resource": { + "resource": "Ressource", + "select-resource": "Vælg ressource", + "resource-required": "Ressource er påkrævet", + "no-resources-matching": "", + "display-type": { + "ALL": "Alle", + "PROFILE": "Profil", + "ADMIN_SETTINGS": "Admin-indstillinger", + "ALARM": "Alarm", + "DEVICE": "Enhed", + "DEVICE_PROFILE": "Enhedsprofil", + "ASSET": "Aktiv", + "CUSTOMER": "Kunde", + "DASHBOARD": "Dashboard", + "ENTITY_VIEW": "Entitetsvisning", + "TENANT": "Lejer", + "TENANT_PROFILE": "Lejerprofil", + "RULE_CHAIN": "Regelkæde", + "USER": "Bruger", + "WIDGETS_BUNDLE": "Widgets-bundt", + "WIDGET_TYPE": "Widget-type", + "CONVERTER": "Omformer", + "INTEGRATION": "Integration", + "SCHEDULER_EVENT": "Planlægningsbegivenheder", + "BLOB_ENTITY": "Blob-entitet", + "CUSTOMER_GROUP": "Kundegruppe", + "DEVICE_GROUP": "Enhedsgruppe", + "ASSET_GROUP": "Aktivgruppe", + "USER_GROUP": "Brugergruppe", + "ENTITY_VIEW_GROUP": "Entitetsvisningsgruppe", + "DASHBOARD_GROUP": "Dashboardgruppe", + "ROLE": "Rolle", + "GROUP_PERMISSION": "Gruppetilladelse", + "WHITE_LABELING": "Hvid mærkning", + "AUDIT_LOG": "Auditlog", + "API_USAGE_STATE": "API-brugstilstand" + } + }, + "operation": { + "operation": "Driftsopgave", + "operations": "Driftsopgaver", + "operations-required": "Der skal angives mindst én driftsopgave.", + "enter-operation": "Indtast driftsopgave.", + "no-operations-matching": "", + "display-type": { + "ALL": "Alle", + "CREATE": "Opret", + "READ": "Læs", + "WRITE": "Skriv", + "DELETE": "Slet", + "ASSIGN_TO_CUSTOMER": "Tildel til kunde", + "UNASSIGN_FROM_CUSTOMER": "Fjern tildeling fra kunde", + "RPC_CALL": "RPC-opkald", + "READ_CREDENTIALS": "Læs brugeroplysninger", + "WRITE_CREDENTIALS": "Skriv brugeroplysninger", + "READ_ATTRIBUTES": "Læs attributter", + "WRITE_ATTRIBUTES": "Skriv attributter", + "READ_TELEMETRY": "Læs telemetri", + "WRITE_TELEMETRY": "Skriv telemetri", + "CLAIM_DEVICES": "Gør krav på enheder", + "IMPERSONATE": "Efterlign", + "CHANGE_OWNER": "Skift ejer", + "ADD_TO_GROUP": "Tilføj til gruppe", + "REMOVE_FROM_GROUP": "Fjern fra gruppe", + "SHARE_GROUP": "Del gruppe", + "ASSIGN_TO_TENANT": "Tildel til lejer" + } + } + }, + "scheduler": { + "scheduler": "Planlægger", + "scheduler-event": "Planlægningsbegivenhed", + "select-scheduler-event": "Vælg planlægningsbegivenhed", + "no-scheduler-events-matching": "", + "scheduler-event-required": "Planlægningsbegivenhed er påkrævet", + "management": "Tidsplansstyring", + "scheduler-events": "Planlægningsbegivenheder", + "add-scheduler-event": "Tilfjøj planlægningsbegivenhed", + "search-scheduler-events": "Søg efter planlægningsbegivenheder", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "type": "Type", + "created_customer": "Oprettet af kunde", + "edit-scheduler-event": "Rediger planlægningsbegivenhed", + "view-scheduler-event": "Vis planlægningsbegivenhed", + "delete-scheduler-event": "Slet planlægningsbegivenhed", + "no-scheduler-events": "Ingen planlægningsbegivenheder fundet", + "selected-scheduler-events": "", + "delete-scheduler-event-title": "", + "delete-scheduler-event-text": "Vær forsigtig. Efter bekræftelsen vil planlægningsbegivenheden og alle relaterede data være uoprettelige.", + "delete-scheduler-events-title": "", + "delete-scheduler-events-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte planlægningsbegivenheder blive fjernet, og alle relaterede data vil være uoprettelige.", + "create": "Opret planlægningsbegivenhed", + "edit": "Rediger planlægningsbegivenhed", + "view": "Vis planlægningsbegivenhed", + "name-required": "Navn er påkrævet.", + "configuration": "Konfiguration", + "schedule": "Tidsplan", + "start-time": "Starttid", + "repeat": "Gentag", + "repeats": "Gentagelser", + "daily": "Daglig", + "weekly": "Ugentlig", + "monthly": "Månedlig", + "yearly": "Årlig", + "timer": "Timerbaseret", + "repeats-required": "Gentagelser er påkrævet.", + "repeat-on": "Gentag den", + "repeat-every": "Gentag hver", + "ends-on": "Slutter den", + "sunday-label": "L", + "monday-label": "M", + "tuesday-label": "T", + "wednesday-label": "O", + "thursday-label": "T", + "friday-label": "F", + "saturday-label": "L", + "repeat-on-sunday": "Gentag på søndag", + "repeat-on-monday": "Gentag på mandag", + "repeat-on-tuesday": "Gentag på tirsdag", + "repeat-on-wednesday": "Gentag på onsdag", + "repeat-on-thursday": "Gentag på torsdag", + "repeat-on-friday": "Gentag på fredag", + "repeat-on-saturday": "Gentag på lørdag", + "event-type": "Begivenhedstype", + "select-event-type": "Vælg begivenhedstype", + "event-type-required": "Begivenhedstype er påkrævet.", + "list-mode": "Listevisning", + "calendar-mode": "Kalendervisning", + "calendar-view-type": "Kalendervisningstype", + "month": "Måned", + "week": "Uge", + "day": "Dag", + "agenda-week": "Program for uge", + "agenda-day": "Program for dag", + "list-year": "Liste for år", + "list-month": "Liste for måned", + "list-week": "Liste for uge", + "list-day": "Liste for dag", + "today": "I dag", + "navigate-before": "Naviger før", + "navigate-next": "Naviger næste", + "starting-from": "Starter fra", + "until": "til og med", + "on": "den", + "sunday": "Søndag", + "monday": "Mandag", + "tuesday": "Tirsdag", + "wednesday": "Onsdag", + "thursday": "Torsdag", + "friday": "Fredag", + "saturday": "Lørdag", + "originator": "Ophavsmand", + "single-entity": "Enkelt entitet", + "group-of-entities": "Gruppe af entiteter", + "entities-group-owner": "Ejer af gruppe af entiteter", + "single-device": "Enkelt enhed", + "group-of-devices": "Gruppe af enheder", + "devices-group-owner": "Ejer af gruppe af enheder", + "message-body": "Meddelelsestekst", + "target": "Mål", + "rpc-method": "Metode", + "rpc-method-required": "Metode er påkrævet", + "rpc-params": "Parametre", + "select-dashboard-state": "Vælg dashboardtilstand", + "hours": "Timer", + "minutes": "Minutter", + "seconds": "Sekunder", + "time-interval-required": "Tidsinterval er påkrævet", + "time-unit-required": "Tidsenhed er påkrævet", + "every-hour": "", + "every-minute": "", + "every-second": "" + }, + "report": { + "report-config": "Rapportkonfiguration", + "email-config": "E-mailkonfiguration", + "dashboard-state-param": "Parameterværdi for dashboardtilstand", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL er påkrævet.", + "use-dashboard-timewindow": "Brug dashboardtidsvindue", + "timewindow": "Tidsvindue", + "name-pattern": "Rapportnavnsmønster", + "name-pattern-required": "Rapportnavnsmønster er påkrævet", + "type": "Rapporttype", + "use-current-user-credentials": "Brug aktuelle brugeroplysninger", + "customer-user-credentials": "Kundens brugeroplysninger", + "customer-user-credentials-required": "Kundens brugeroplysninger er påkrævet", + "generate-test-report": "Generer testrapport", + "send-email": "Send e-mail", + "from": "Fra", + "from-required": "Fra er påkrævet.", + "to": "Til", + "to-required": "Til er påkrævet.", + "cc": "Cc", + "bcc": "Bcc", + "subject": "Emne", + "subject-required": "Emne er påkrævet.", + "body": "Tekst", + "body-required": "Tekst er påkrævet." + }, + "blob-entity": { + "blob-entity": "Blob-entitet", + "select-blob-entity": "Vælg blob-entitet", + "no-blob-entities-matching": "", + "blob-entity-required": "Blob-entitet er påkrævet", + "files": "Filer", + "search": "Søg efter filer", + "clear-search": "Ryd søgning", + "no-blob-entities-prompt": "Ingen filer fundet", + "report": "Rapport", + "created-time": "Oprettelsestidspunkt", + "name": "Navn", + "type": "Type", + "created_customer": "Oprettet af kunde", + "selected-blob-entities": "", + "download-blob-entity": "Download fil", + "delete-blob-entity": "Slet fil", + "delete-blob-entity-title": "", + "delete-blob-entity-text": "Vær forsigtig. Efter bekræftelsen vil fildata være uoprettelige.", + "delete-blob-entities-title": "", + "delete-blob-entities-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte filer blive fjernet, og alle relaterede data vil være uoprettelige." + }, + "timezone": { + "timezone": "Tidszone", + "select-timezone": "Vælg tidszone", + "no-timezones-matching": "", + "timezone-required": "Tidszone er påkrævet.", + "browser-time": "Browsertid" + }, + "queue": { + "select_name": "Vælg kønavn", + "name": "Kønavn", + "name_required": "Kønavn er påkrævet." + }, + "tenant": { + "tenant": "Lejer", + "tenants": "Lejere", + "management": "Administration af lejer", + "add": "Tilføj lejer", + "admins": "Admin.", + "manage-tenant-admins": "Administrer lejeradmin.", + "delete": "Slet lejer", + "add-tenant-text": "Tilføj ny lejer", + "no-tenants-text": "Ingen lejere fundet", + "tenant-details": "Lejeroplysninger", + "delete-tenant-title": "", + "delete-tenant-text": "Vær forsigtig. Efter bekræftelsen vil lejeren og alle relaterede data være uoprettelige.", + "delete-tenants-title": "", + "delete-tenants-action-title": "", + "delete-tenants-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte lejere blive fjernet, og alle relaterede data vil være uoprettelige.", + "title": "Titel", + "title-required": "Titel er påkrævet.", + "description": "Beskrivelse", + "details": "Oplysninger", + "events": "Begivenheder", + "copyId": "Kopiér lejer-id", + "idCopiedMessage": "Lejer-id er blevet kopieret til udklipsholder", + "select-tenant": "Vælg lejer", + "no-tenants-matching": "", + "tenant-required": "Lejer er påkrævet", + "selected-tenants": "", + "search": "Søg efter lejere", + "allow-white-labeling": "Tillad hvid mærkning", + "allow-customer-white-labeling": "Tillad hvid mærkning af kunder", + "isolated-tb-core": "Behandling i isoleret ThingsBoard Core-beholder", + "isolated-tb-rule-engine": "Behandling i isoleret ThingsBoard regelmotor-beholder", + "isolated-tb-core-details": "Kræver separat(e) microserviceydelse(r) pr. isoleret lejer", + "isolated-tb-rule-engine-details": "Kræver separat(e) microserviceydelse(r) pr. isoleret lejer" + }, + "tenant-profile": { + "tenant-profile": "Lejerprofil", + "tenant-profiles": "Lejerprofiler", + "add": "Tilføj lejerprofil", + "edit": "Rediger lejerprofil", + "tenant-profile-details": "Oplysninger om lejerprofil", + "no-tenant-profiles-text": "Ingen lejerprofiler fundet", + "search": "Søg efter lejerprofiler", + "selected-tenant-profiles": "", + "no-tenant-profiles-matching": "", + "tenant-profile-required": "Lejerprofil er påkrævet", + "idCopiedMessage": "Lejerprofil-id er blevet kopieret til udklipsholder", + "set-default": "Gør lejerprofil til standard", + "delete": "Slet lejerprofil", + "copyId": "Kopiér lejerprofil-id", + "name": "Navn", + "name-required": "Navn er påkrævet.", + "data": "Profildata", + "profile-configuration": "Profilkonfiguration", + "description": "Beskrivelse", + "default": "Standard", + "delete-tenant-profile-title": "", + "delete-tenant-profile-text": "Vær forsigtig. Efter bekræftelsen vil lejerprofilen og alle relaterede data være uoprettelige.", + "delete-tenant-profiles-title": "", + "delete-tenant-profiles-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte lejerprofiler blive fjernet, og alle relaterede data vil være uoprettelige.", + "set-default-tenant-profile-title": "", + "set-default-tenant-profile-text": "Efter bekræftelsen vil lejerprofilen blive markeret som standard og vil blive brugt til nye lejere, hvor der ikke er angivet nogen profil.", + "no-tenant-profiles-found": "Ingen lejerprofiler fundet.", + "create-new-tenant-profile": "Opret en ny!", + "maximum-devices": "Maks. antal enheder (0 – ubegrænset)", + "maximum-devices-required": "Maks. antal enheder er påkrævet.", + "maximum-devices-range": "Min. antal enheder kan ikke være negativt", + "maximum-assets": "Maks. antal aktiver (0 – ubegrænset)", + "maximum-assets-required": "Maks. antal aktiver er påkrævet.", + "maximum-assets-range": "Maks. antal aktiver kan ikke være negativt", + "maximum-customers": "Maks. antal kunder (0 – ubegrænset)", + "maximum-customers-required": "Maks. antal kunder er påkrævet.", + "maximum-customers-range": "Maks. antal kunder kan ikke være negativt", + "maximum-users": "Maks. antal brugere (0 – ubegrænset)", + "maximum-users-required": "Maks. antal brugere er påkrævet.", + "maximum-users-range": "Maks. antal brugere kan ikke være negativt", + "maximum-dashboards": "Maks. antal dashboards (0 – ubegrænset)", + "maximum-dashboards-required": "Maks. antal dashboards er påkrævet.", + "maximum-dashboards-range": "Maks. antal dashboards kan ikke være negativt", + "maximum-rule-chains": "Maks. antal regelkæder (0 – ubegrænset)", + "maximum-rule-chains-required": "Maks. antal regelkæder er påkrævet.", + "maximum-rule-chains-range": "Maks. antal regelkæder kan ikke være negativt", + "maximum-integrations": "Maks. antal integrationer (0 – ubegrænset)", + "maximum-integrations-required": "Maks. antal integrationer er påkrævet.", + "maximum-integrations-range": "Maks. antal integrationer kan ikke være negativt", + "maximum-converters": "Maks. antal omformere (0 – ubegrænset)", + "maximum-converters-required": "Maks. antal omformere er påkrævet.", + "maximum-converters-range": "Maks. antal omformere kan ikke være negativt", + "maximum-scheduler-events": "Maks. antal planlægningsbegivenheder (0 – ubegrænset)", + "maximum-scheduler-events-required": "Maks. antal planlægningsbegivenheder er påkrævet.", + "maximum-scheduler-events-range": "Maks. antal planlægningsbegivenheder kan ikke være negativt", + "transport-tenant-msg-rate-limit": "Hastighedsgrænse for transport af lejermeddelelser.", + "transport-tenant-telemetry-msg-rate-limit": "Hastighedsgrænse for transport af lejertelemetrimeddelelser.", + "transport-tenant-telemetry-data-points-rate-limit": "Hastighedsgrænse for transport af lejertelemetridatapunkter.", + "transport-device-msg-rate-limit": "Hastighedsgrænse for transport af enhedsmeddelelser.", + "transport-device-telemetry-msg-rate-limit": "Hastighedsgrænse for transport af enhedstelemetrimeddelelser.", + "transport-device-telemetry-data-points-rate-limit": "Hastighedsgrænse for transport af enhedstelemetridatapunkter.", + "max-transport-messages": "Maks. antal transportmeddelelser (0 – ubegrænset)", + "max-transport-messages-required": "Maks. antal transportmeddelelser er påkrævet.", + "max-transport-messages-range": "Maks. antal transportmeddelelser kan ikke være negativt", + "max-transport-data-points": "Maks. antal transportdatapunkter (0 – ubegrænset)", + "max-transport-data-points-required": "Maks. antal transportdatapunkter er påkrævet.", + "max-transport-data-points-range": "Maks. antal transportdatapunkter kan ikke være negativt", + "max-r-e-executions": "Maks. antal regelmotor-udførelser (0 – ubegrænset)", + "max-r-e-executions-required": "Maks. antal regelmotor-udførelser er påkrævet.", + "max-r-e-executions-range": "Maks. antal regelmotor-udførelser kan ikke være negativt", + "max-j-s-executions": "Maks. antal JavaScript-udførelser (0 – ubegrænset)", + "max-j-s-executions-required": "Maks. antal JavaScript-udførelser er påkrævet.", + "max-j-s-executions-range": "Maks. antal JavaScript-udførelser kan ikke være negativt", + "max-d-p-storage-days": "Maks. antal lagringsdage for datapunkter (0 – ubegrænset)", + "max-d-p-storage-days-required": "Maks. antal lagringsdage for datapunkter er påkrævet.", + "max-d-p-storage-days-range": "Maks. antal lagringsdage for datapunkter kan ikke være negativt", + "default-storage-ttl-days": "Standard lagringsdage for TTL (0 – ubegrænset)", + "default-storage-ttl-days-required": "Standard lagringsdage for TTL er påkrævet.", + "default-storage-ttl-days-range": "Standard lagringsdage for TTL kan ikke være negative", + "max-rule-node-executions-per-message": "Maks. antal regelknudeudførelser pr. meddelelse (0 – ubegrænset)", + "max-rule-node-executions-per-message-required": "Maks. antal regelknudeudførelser pr. meddelelse er påkrævet.", + "max-rule-node-executions-per-message-range": "Maks. antal regelknudeudførelser pr. meddelelse kan ikke være negativt", + "max-emails": "Maks. antal sendte e-mails (0 – ubegrænset)", + "max-emails-required": "Maks. antal sendte e-mails er påkrævet.", + "max-emails-range": "Maks. antal sendte e-mails kan ikke være negativt", + "max-sms": "Maks. antal sendte SMS'er (0 – ubegrænset)", + "max-sms-required": "Maks. antal sendte SMS'er er påkrævet.", + "max-sms-range": "Maks. antal sendte SMS'er kan ikke være negativt" + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, 1 {1 sekund} other {# sekunder} }", + "minutes-interval": "{ minutes, plural, 1 {1 minut} other {# minutter} }", + "hours-interval": "{ hours, plural, 1 {1 time} other {# timer} }", + "days-interval": "{ days, plural, 1 {1 dag} other {# dage} }", + "days": "Dage", + "hours": "Timer", + "minutes": "Minutter", + "seconds": "Sekunder", + "advanced": "Fremskreden", + "predefined": { + "yesterday": "I går", + "day-before-yesterday": "Dagen før i går", + "this-day-last-week": "Denne dag i sidste uge", + "previous-week": "Forrige uge (søn – lør)", + "previous-week-iso": "Forrige uge (man – søn)", + "previous-month": "Forrige måned", + "previous-year": "Forrige år", + "current-hour": "Aktuel time", + "current-day": "Aktuel dag", + "current-day-so-far": "Aktuel dag indtil nu", + "current-week": "Aktuel uge (søn – lør)", + "current-week-iso": "Aktuel uge (man – søn)", + "current-week-so-far": "Aktuel uge indtil videre (søn – lør)", + "current-week-iso-so-far": "Aktuel uge indtil videre (man– søn)", + "current-month": "Aktuel måned", + "current-month-so-far": "Aktuel måned indtil nu", + "current-year": "Aktuelt år", + "current-year-so-far": "Aktuelt år indtil nu" + } + }, + "timeunit": { + "seconds": "Sekunder", + "minutes": "Minutter", + "hours": "Timer", + "days": "Dage" + }, + "timewindow": { + "days": "{ days, plural, 1 { dag } other {# dage } }", + "hours": "{ hours, plural, 0 { time } 1 {1 time } other {# timer } }", + "minutes": "{ minutes, plural, 0 { minut } 1 {1 minut } other {# minutter } }", + "seconds": "{ seconds, plural, 0 { sekund } 1 {1 sekund } other {# sekunder } }", + "realtime": "Realtid", + "history": "Historie", + "last-prefix": "sidst", + "period": "fra {{ startTime }} til {{ endTime }}", + "edit": "Rediger tidsvindue", + "date-range": "Datointerval", + "last": "Sidst", + "time-period": "Tidsperiode", + "hide": "Skjul", + "interval": "Interval" + }, + "user": { + "user": "Bruger", + "users": "Brugere", + "management": "Brugeradministration", + "customer-users": "Kundebrugere", + "tenant-admins": "Lejeradmin.", + "sys-admin": "Systemadministrator", + "tenant-admin": "Bruger", + "customer": "Kunde", + "anonymous": "Anonym", + "add": "Tilføj bruger", + "delete": "Slet bruger", + "add-user-text": "Tilføj ny bruger", + "no-users-text": "Ingen brugere fundet", + "user-details": "Brugerdetaljer", + "delete-users": "Slet brugere", + "delete-user-title": "", + "delete-user-text": "Vær forsigtig. Efter bekræftelsen vil brugeren og alle relaterede data være uoprettelige.", + "delete-users-title": "", + "delete-users-action-title": "", + "delete-users-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte brugere blive fjernet, og alle relaterede data vil være uoprettelige.", + "activation-email-sent-message": "Aktiverings-e-mail blev sendt!", + "resend-activation": "Gensend aktivering", + "email": "E-mail", + "email-required": "E-mail er påkrævet.", + "invalid-email-format": "Ugyldigt e-mailformat.", + "first-name": "Fornavn", + "last-name": "Efternavn", + "description": "Beskrivelse", + "default-dashboard": "Standard dashboard", + "always-fullscreen": "Altid fuld skærm", + "select-user": "Vælg bruger", + "no-users-matching": "", + "user-required": "Bruger er påkrævet", + "activation-method": "Aktiveringsmetode", + "display-activation-link": "Vis aktiveringslink", + "send-activation-mail": "Send aktiverings-e-mail", + "activation-link": "Link til brugeraktivering", + "activation-link-text": "", + "copy-activation-link": "Kopiér aktiveringslink", + "activation-link-copied-message": "Brugeraktiveringslinket er blevet kopieret til udklipsholderen", + "selected-users": "", + "search": "Søg efter brugere", + "details": "Oplysninger", + "login-as-tenant-admin": "Log ind som lejeradministrator", + "login-as-customer-user": "Log ind som kundebruger", + "select-group-to-add": "Vælg målgruppe for at tilføje valgte brugere", + "select-group-to-move": "Vælg målgruppe for at flytte valgte brugere", + "remove-users-from-group": "", + "group": "Gruppe af brugere", + "list-of-groups": "", + "group-name-starts-with": "", + "disable-account": "Deaktiver brugerkonto", + "enable-account": "Aktivér brugerkonto", + "enable-account-message": "Brugerkontoen er blevet aktiveret!", + "disable-account-message": "Brugerkontoen blev deaktiveret!" + }, + "value": { + "type": "Værditype", + "string": "Streng", + "string-value": "Strengværdi", + "string-value-required": "Strengværdi er påkrævet", + "integer": "Heltal", + "integer-value": "Heltalsværdi", + "integer-value-required": "Heltalsværdi er påkrævet", + "invalid-integer-value": "Ugyldig heltalsværdi", + "double": "Dobbelt", + "double-value": "Dobbelt værdi", + "double-value-required": "Dobbelt værdi er påkrævet", + "boolean": "Boolesk", + "boolean-value": "Boolesk værdi", + "false": "FALSK", + "true": "SANDT", + "long": "Lang", + "json": "JSON", + "json-value": "JSON-værdi", + "json-value-invalid": "JSON-værdi har et ugyldigt format", + "json-value-required": "JSON-værdi er påkrævet." + }, + "widget": { + "widget-library": "Widgets-bibliotek", + "widget-bundle": "Widgets-bundt", + "all-bundles": "Alle bundter", + "select-widgets-bundle": "Vælg widgets-bundt", + "management": "Widget-administration", + "editor": "Widget-editor", + "widget-type-not-found": "Problem under indlæsning af widget-konfiguration.
              Sandsynligvis tilknyttet\r\n widget-type blev fjernet.", + "widget-type-load-error": "Widget blev ikke indlæst pga. følgende fejl:", + "remove": "Fjern widget", + "edit": "Rediger widget", + "remove-widget-title": "", + "remove-widget-text": "Efter bekræftelsen vil widgeten og alle relaterede data være uoprettelige.", + "timeseries": "Tidsserier", + "search-data": "Søg efter data", + "no-data-found": "Ingen data fundet", + "latest": "Seneste værdier", + "rpc": "Styring af widget", + "alarm": "Alarm-widget", + "static": "Statisk widget", + "select-widget-type": "Vælg widget-type", + "missing-widget-title-error": "Widget-titel skal angives!", + "widget-saved": "Widget gemt", + "unable-to-save-widget-error": "Widget kunne ikke gemmes! Widget har fejl!", + "save": "Gem widget", + "saveAs": "Gem widget som", + "save-widget-type-as": "Gem widget-type som", + "save-widget-type-as-text": "Indtast en ny widget-titel, og/eller vælg målwidget-bundt", + "toggle-fullscreen": "Skift til fuld skærm", + "run": "Kør widget", + "title": "Widget-titel", + "title-required": "Widget-titel er påkrævet.", + "type": "Widget-type", + "resources": "Ressourcer", + "resource-url": "JavaScript/CSS URL", + "resource-is-module": "Er modul", + "remove-resource": "Fjern ressource", + "add-resource": "Tilføj ressource", + "html": "HTML", + "tidy": "Tidy", + "css": "CSS", + "settings-schema": "Indstillingsskema", + "datakey-settings-schema": "Skema over datanøgleindstillinger", + "widget-settings": "Widget-indstillinger", + "description": "Beskrivelse", + "image-preview": "Forhåndsvisning af billede", + "javascript": "Javascript", + "js": "JS", + "remove-widget-type-title": "", + "remove-widget-type-text": "Efter bekræftelsen vil widget-typen og alle relaterede data være uoprettelige.", + "remove-widget-type": "Fjern widget-type", + "add-widget-type": "Tilføj ny widget-type", + "widget-type-load-failed-error": "Kunne ikke indlæse widget-type!", + "widget-template-load-failed-error": "Kunne ikke indlæse widget-skabelon!", + "add": "Tilføj widget", + "undo": "Fortryd widget-ændringer", + "export": "Eksportér widget", + "export-data": "Eksportér widget-data", + "export-to-csv": "Eksportér data til CSV...", + "export-to-excel": "Eksportér data til XLS...", + "export-to-excel-xlsx": "Eksportér data til XLSX...", + "no-data": "Ingen data at vise på widget", + "data-overflow": "", + "alarm-data-overflow": "", + "search": "Søg efter widget", + "filter": "Widget-filtertype", + "loading-widgets": "Indlæser widgets..." + }, + "widget-action": { + "header-button": "Widget-overskriftsknap", + "open-dashboard-state": "Naviger til ny dashboardtilstand", + "update-dashboard-state": "Opdater aktuel dashboardtilstand", + "open-dashboard": "Naviger til et andet dashboard", + "custom": "Brugerdefineret handling", + "custom-pretty": "Brugerdefineret handling (med HTML-skabelon)", + "target-dashboard-state": "Mål-dashboardtilstand", + "target-dashboard-state-required": "Mål-dashboardtilstand er påkrævet", + "set-entity-from-widget": "Angiv entitet fra widget", + "target-dashboard": "Mål-dashboard", + "open-right-layout": "Åbn højre dashboardlayout (mobilvisning)", + "open-in-separate-dialog": "Åbn i separat dialogboks", + "dialog-title": "Dialogbokstitel", + "dialog-hide-dashboard-toolbar": "Skjul dashboardets værktøjslinje i dialogboks", + "dialog-width": "Dialogboksbredde i procent i forhold til visningsportens bredde", + "dialog-height": "Dialogbokshøjde i procent i forhold til visningsportens højde", + "dialog-size-range-error": "Dialogboksstørrelsens procentværdi skal ligge i området fra 1 til 100.", + "open-new-browser-tab": "Åbn i en ny browserfane" + }, + "widgets-bundle": { + "current": "Nuværende bundt", + "widgets-bundles": "Widgets-bundter", + "add": "Tilføj widgets-bundt", + "delete": "Slet widgets-bundt", + "title": "Titel", + "title-required": "Titel er påkrævet.", + "description": "Beskrivelse", + "image-preview": "Forhåndsvisning af billede", + "add-widgets-bundle-text": "Tilføj nye widgets-bundter", + "no-widgets-bundles-text": "Ingen widgets-bundter fundet", + "empty": "Widgets-bundt er tomt", + "details": "Oplysninger", + "widgets-bundle-details": "Oplysninger om widgets-bundt", + "delete-widgets-bundle-title": "", + "delete-widgets-bundle-text": "Vær forsigtig. Efter bekræftelsen vil widgets-bundtet og alle relaterede data være uoprettelige.", + "delete-widgets-bundles-title": "", + "delete-widgets-bundles-action-title": "", + "delete-widgets-bundles-text": "Vær forsigtig. Efter bekræftelsen vil alle valgte widgets-bundter blive fjernet, og alle relaterede data vil være uoprettelige.", + "no-widgets-bundles-matching": "", + "widgets-bundle-required": "Widgets-bundt er påkrævet.", + "system": "System", + "import": "Importér widgets-bundt", + "export": "Eksportér widgets-bundt", + "export-failed-error": "", + "create-new-widgets-bundle": "Opret nyt widgets-bundt", + "widgets-bundle-file": "Widgets-bundtfil", + "invalid-widgets-bundle-file-error": "Widgets-bundt kunne ikke importeres: Ugyldig datastruktur for widgets-bundt.", + "search": "Søg efter widget-bundter", + "selected-widgets-bundles": "", + "open-widgets-bundle": "Åbn widgets-bundt", + "loading-widgets-bundles": "Indlæser widgets-bundter..." + }, + "widget-config": { + "data": "Data", + "settings": "Indstillinger", + "advanced": "Fremskreden", + "title": "Titel", + "title-tooltip": "Værktøjstip for titel", + "general-settings": "Generelle indstillinger", + "display-title": "Vis titel", + "drop-shadow": "Slip skygge", + "enable-fullscreen": "Aktivér fuldskærm", + "enable-data-export": "Aktivér dataeksport", + "background-color": "Baggrundsfarve", + "text-color": "Tekstfarve", + "padding": "Padding", + "margin": "Margin", + "widget-style": "Widget-stil", + "title-style": "Titeltype", + "mobile-mode-settings": "Indstillinger for mobiltilstand", + "order": "Rækkefølge", + "height": "Højde", + "units": "Specielt symbol, der vises ved siden af værdi", + "decimals": "Antal cifre efter flydende punkt", + "timewindow": "Tidsvindue", + "use-dashboard-timewindow": "Brug dashboardtidsvindue", + "display-timewindow": "Vis tidsvindue", + "display-legend": "Vis siganturforklaring", + "datasources": "Datakilder", + "maximum-datasources": "", + "datasource-type": "Type", + "datasource-parameters": "Parametre", + "remove-datasource": "Fjern datakilde", + "add-datasource": "Tilføj datakilde", + "target-device": "Målenhed", + "alarm-source": "Alarmkilde", + "actions": "Handlinger", + "action": "Handling", + "add-action": "Tilføj handling", + "search-actions": "Søg efter handlinger", + "no-actions-text": "Ingen handlinger fundet", + "action-source": "Handlingskilde", + "action-source-required": "Handlingskilde er påkrævet.", + "action-name": "Navn", + "action-name-required": "Handlingsnavn er påkrævet.", + "action-name-not-unique": "Der findes allerede en anden handling med samme navn.
              Handlingsnavnet skal være unikt inden for den samme handlingskilde.", + "action-icon": "Ikon", + "action-type": "Type", + "action-type-required": "Handlingstype er påkrævet.", + "edit-action": "Rediger handling", + "delete-action": "Slet handling", + "delete-action-title": "Slet widget-handling", + "delete-action-text": "", + "display-icon": "Vis titelikon", + "icon-color": "Ikonfarve", + "icon-size": "Ikonstørrelse" + }, + "widget-type": { + "import": "Importér widget-type", + "export": "Eksportér widget-type", + "export-failed-error": "", + "create-new-widget-type": "Opret ny widget-type", + "widget-type-file": "Widget-typefil", + "invalid-widget-type-file-error": "Kan ikke importere widget-type: Ugyldig datastruktur for widget-type." + }, + "self-registration": { + "self-registration": "Selvregistrering", + "self-registration-url": "Selvregistrerings-URL", + "captcha-site-key": "reCAPTCHA site-nøgle", + "captcha-secret-key": "reCAPTCHA hemmelig nøgle", + "notification-email": "Notifikations-e-mail", + "privacy-policy-text": "Fortrolighedspolitik tekst", + "text-message-page": "Tekstmeddelelse til tilmeldingsside" + }, + "white-labeling": { + "white-labeling": "Hvid mærkning", + "login-white-labeling": "Login for hvid mærkning", + "preview": "Forhåndsvisning", + "app-title": "Applikationstitel", + "favicon": "Website-ikon", + "favicon-description": "", + "favicon-size-error": "", + "favicon-type-error": "Ugyldigt filformat for website-billede. Kun ICO-, GIF- eller PNG-billeder accepteres.", + "drop-favicon-image": "Træk og slip et website-ikonbillede, eller klik for at vælge en fil, der skal uploades.", + "no-favicon-image": "Intet ikon valgt", + "logo": "Logo", + "logo-description": "", + "logo-size-error": "", + "logo-type-error": "Ugyldigt logofilformat. Kun billeder accepteres.", + "drop-logo-image": "Træk og slip et logobillede, eller klik for at vælge en fil, der skal uploades.", + "no-logo-image": "Intet logo valgt", + "logo-height": "Logohøjde, px", + "primary-palette": "Primær palet", + "accent-palette": "Accent palet", + "customize-palette": "Tilpas", + "advanced-css": "Avanceret CSS", + "edit-palette": "Rediger palet", + "save-palette": "Gem palet", + "primary-background": "Primær baggrund", + "secondary-background": "Sekundær baggrund", + "hue1": "HUE 1", + "hue2": "HUE 2", + "hue3": "HUE 3", + "page-background-color": "Baggrundsfarve for side", + "dark-foreground": "Mørk forgrund", + "domain-name": "Domænenavn", + "base-url": "Basis-URL", + "base-url-required": "Basis-URL er påkrævet.", + "prohibit-different-url": "Det er ikke tilladt at bruge værtsnavn fra overskrifterne for klientanmodninger", + "prohibit-different-url-hint": "Denne indstilling skal aktiveres for produktionsmiljøer. Kan forårsage sikkerhedsproblemer ved deaktivering", + "help-link-base-url": "Basis-URL for hjælpelinks", + "enable-help-links": "Aktivér hjælpelinks", + "error-verification-url": "Et domænenavn må ikke indeholde symbolerne '/' og ':'. Eksempel: thingsboard.io", + "show-platform-name-version": "Vis platformnavn og version", + "platform-name": "Platformnavn", + "platform-version": "Platformversion", + "version-mask": "", + "position": { + "label": "Platformnavn og versionsposition", + "under-logo": "Under logoet", + "bottom": "Nederst i login-formularen" + } + }, + "widgets": { + "date-range-navigator": { + "localizationMap": { + "Sun": "Søn", + "Mon": "Man", + "Tue": "Tir", + "Wed": "Ons", + "Thu": "Tor", + "Fri": "Fre", + "Sat": "Lør", + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mar", + "Apr": "Apr", + "May": "Maj", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Aug", + "Sep": "Sep", + "Oct": "Okt", + "Nov": "Nov", + "Dec": "Dec", + "January": "Januar", + "February": "Februar", + "March": "Marts", + "April": "April", + "June": "Juni", + "July": "Juli", + "August": "August", + "September": "September", + "October": "Oktober", + "November": "November", + "December": "December", + "Custom Date Range": "Brugerdefineret datointerval", + "Date Range Template": "Skabelon for datointerval", + "Today": "I dag", + "Yesterday": "I går", + "This Week": "Denne uge", + "Last Week": "Sidste uge", + "This Month": "Denne måned", + "Last Month": "Sidste måned", + "Year": "År", + "This Year": "I år", + "Last Year": "Sidste år", + "Date picker": "Datovælger", + "Hour": "Time", + "Day": "Dag", + "Week": "Uge", + "2 weeks": "2 uger", + "Month": "Måned", + "3 months": "3 måneder", + "6 months": "6 måneder", + "Custom interval": "Brugerdefineret interval", + "Interval": "Interval", + "Step size": "Trinstørrelse", + "Ok": "Okay" + } + }, + "input-widgets": { + "attribute-not-allowed": "Attributparameter kan ikke bruges i denne widget", + "blocked-location": "Geoplaceringen er blokeret i din browser", + "claim-device": "Gør krav på enhed", + "claim-failed": "Kunne ikke gøre krav på enheden!", + "claim-not-found": "Enhed ikke fundet!", + "claim-successful": "Enheden er blevet krævet!", + "date": "Dato", + "device-name": "Enhedsnavn", + "device-name-required": "Enhedsnavn er påkrævet", + "discard-changes": "Kassér ændringer", + "entity-attribute-required": "Entitetsattribut er påkrævet", + "entity-coordinate-required": "Både felter, breddegrad og længdegrad er påkrævet", + "entity-timeseries-required": "Tidsserie for entitet er påkrævet", + "get-location": "Få den aktuelle placering", + "invalid-date": "Ugyldig dato", + "latitude": "Breddegrad", + "longitude": "Længde", + "min-value-error": "", + "max-value-error": "", + "not-allowed-entity": "Den valgte entitet kan ikke have delte attributter", + "no-attribute-selected": "Ingen attribut er valgt", + "no-datakey-selected": "Ingen datanøgle er valgt", + "no-coordinate-specified": "Datanøgle for breddegrad/længdegrad er ikke angivet", + "no-entity-selected": "Ingen entitet valgt", + "no-image": "Intet billede", + "no-support-geolocation": "Din browser understøtter ikke geoplacering", + "no-support-web-camera": "Din browser understøtter ikke kameraer", + "enable-https-use-widget": "Aktivér HTTPS for at bruge denne widget", + "no-found-your-camera": "Kan ikke finde dit kamera", + "no-permission-camera": "Tilladelse blev nægtet af brugeren / Dette website har ikke tilladelse til at bruge kameraet", + "no-timeseries-selected": "Ingen tidsserier valgt", + "secret-key": "Hemmelig nøgle", + "secret-key-required": "Hemmelig nøgle er påkrævet", + "switch-attribute-value": "Skift entitetsattributværdi", + "switch-camera": "Skift kamera", + "switch-timeseries-value": "Skift entitetstidsserieværdi", + "take-photo": "Tag et billede", + "time": "Tid", + "timeseries-not-allowed": "Tidsserieparameter kan ikke bruges i denne widget", + "update-failed": "Opdatering mislykkedes", + "update-successful": "Opdatering lykkedes", + "update-attribute": "Opdatering", + "update-timeseries": "Opdater tidsserier", + "value": "Værdi" + } + }, + "icon": { + "icon": "Ikon", + "select-icon": "Vælg ikon", + "material-icons": "Materialeikoner", + "show-all": "Vis alle ikoner" + }, + "subscription": { + "entity-limit-text": "Du kan dog opgradere din abonnementsordning for at øge dine begrænsninger.", + "upgrade-your-plan": "Opgrader abonnementsordning", + "white-labeling-feature": "Funktion til hvid mærkning", + "white-labeling-text-full": "Rebrand ThingsBoard-platformens webinterface med dit virksomheds- eller produktlogo og farveskema på 2 minutter.

              Fjern “Powered By” i dashboardets sidefod.
              Ingen kodning eller genstart af tjeneste påkrævet. Giv også dine kunder mulighed for at hvidmærke deres interface.", + "enable-white-labeling": "Aktivér hvidmærkningsfunktionen nu ved at opgradere din abonnementsordning!", + "read-more": "Læs mere", + "white-labeling-video-text": "Se videovejledningen nedenfor for at se, hvordan denne funktion fungerer!" + }, + "subscription-error": { + "title": "Misligholdelse af abonnement", + "warning-title": "Abonnementsadvarsel", + "limit-reached": { + "device-count": "", + "asset-count": "" + }, + "feature-disabled": { + "white-labeling": "Hvidmærkningsfunktionen er ikke tilladt af din abonnementsordning!" + } + }, + "custom": { + "widget-action": { + "action-cell-button": "Handlingscelleknap", + "row-click": "Ved klik på række", + "polygon-click": "Ved klik på polygon", + "marker-click": "Ved klik på markør", + "tooltip-tag-action": "Værktøjstip for taghandling", + "node-selected": "På valgt knude", + "element-click": "Ved klik på HTML-element", + "pie-slice-click": "Ved klik på udsnit", + "row-double-click": "Ved dobbeltklik på række" + }, + "add-new-facility": { + "add-entity": "Tilføj placering", + "facility-name": "placeringsnavn", + "facility-name-required": "placeringsnavn er påkrævet.", + "title": "Tilføj ny placering" + }, + "delete-facility": { + "are-you-sure-question": "Er du sikker på, at du vil slette placering '{{facilityName}}'?", + "title": "Slet placering" + }, + "facilities": { + "set-location-and-facility-map": "Indstil placering" + }, + "general": { + "account": "Konto", + "accounts": "Konti", + "activation-link-is-sent-to-the-email-address": "Aktiveringslink er sendt til e-mailadressen: '{{email}}'", + "add-ecl": "Tilføj ECL", + "add-ecl-device": "Tilføj ECL-enhed", + "add-edit-ally-email": "Tilføj Ally™ konto", + "add-edit-entity-ally-account": "Tilføj {{ entityName }}'s Ally™ konto", + "add-home": "Tilføj Hjem", + "add-home-area": "Tilføj Hjemmeområde", + "add-new-ally-account": "Tilføj ny konto", + "add-new-location": "Tilføj ny placering", + "add-new-read-only-user": "Tilføj ny skrivebeskyttet bruger", + "add-new-read-only-user-for-facility": "Tilføj ny skrivebeskyttet bruger for '{{facilityName}}'", + "add-vacation-for-zone": "Tilføj ferie for denne zone", + "open-calendar": "Åbn kalender", + "add-zone": "Tilføj zone", + "alarm-code": "Alarmkode", + "alarm-description": "Beskrivelse", + "alarm-message": "Meddelelse", + "alarms-disabled-msg": "Alarmer er deaktiveret.", + "alarms-disabled-state": "Deaktiveret", + "alarms-enabled-msg": "Alarmer er aktiveret.", + "alarms-enabled-state": "Aktiveret", + "all-devices-in-home": "Alle enheder i hjemmet", + "ally-email": "Ally™ e-mail", + "ally-email-access-check-email": "Tjek din e-mail {{ allyEmail }} for at se den 4-cifrede kode fra Ally™ Pro", + "ally-email-access-code-label": "Indtast din adgangskode (4 cifre)", + "ally-email-account-is-missing-or-is-not-valid": "Ally™ e-mailkonto mangler eller er ikke gyldig", + "an-error-occurred-entities-try-again": "Der opstod en fejl under sletning af enhederne. Prøv igen.", + "an-error-occurred-entity-try-again": "Der opstod en fejl under sletning af enheden. Prøv igen.", + "an-error-occurred-please-try-again": "Der opstod en fejl. Prøv igen.", + "app": "App", + "app-version": "Appversion", + "area-name-is-required": "Områdenavn er påkrævet.", + "assign-existing-user-to-facility": "Tildel eksisterende bruger til placering", + "assign-user-to-facility": "Tildel bruger til '{{facilityName}}'", + "available-devices": "Tilgængelige enheder", + "battery": "Batteri", + "calendar": "Kalender", + "cant-remove-yourself": "Du kan ikke fjerne dig selv fra placeringen.", + "change-temperature": "Ændr temperatur", + "change-zone-map": "Skift zonekort", + "child-lock": "Børnesikring", + "child-lock-disabled": "Deaktiveret", + "child-lock-enabled": "Aktiveret", + "circuit": "Kreds", + "comfort": "Komfort", + "comfort-dhw-setpoint": "Sætpunkt for Komfort varmt brugsvand", + "comfort-dhw-setpoint-is-required": "Sætpunkt for Komfort varmt brugsvand er påkrævet.", + "comfort-room": "Komfort rum", + "comfort-room-setpoint": "Sætpunkt for Komfort rum", + "comfort-room-setpoint-is-required": "Sætpunkt for Komfort rum er påkrævet.", + "confirm-btn": "Bekræft", + "confirm-delete-device": "Er du sikker på, du ønsker at slette enhed '{{deviceName}}'?", + "confirm-delete-devices": "Er du sikker på, du ønsker at slette {{numberOfDevices}} enheder?", + "confirm-delete-home": "Er du sikker på, du ønsker at slette hjem '{{homeName}}'; deres zoner og enheder?", + "confirm-delete-zone": "Er du sikker på, du ønsker at slette zonen '{{zoneName}}'?", + "confirm-remove-user": "Er du sikker på, du ønsker at fjerne {{ thisUser }} fra lokation {{ locationName }}", + "constant-comfort-temperature": "Konstant komforttemperatur", + "constant-setback-temperature": "Konstant sænkningstemperatur", + "coordinates": "Koordinater", + "create-ecl-home-without-ally-account": "Opret ECL hjem uden Ally™ konto", + "create-vacation-event": "Opret feriebegivenhed", + "current-humidity": "Luftfugtighed", + "current-temp": "Aktuel temp.", + "current-temperature": "Aktuel temperatur", + "default-flow-temperature-at-minus-30": "Standard fremløbstemperatur ved -30 °C", + "default-flow-temperature-at-minus-15": "Standard fremløbstemperatur ved -15 °C", + "default-flow-temperature-at-minus-5": "Standard fremløbstemperatur ved -5 °C", + "default-flow-temperature-at-zero": "Standard fremløbstemperatur ved 0 °C", + "default-flow-temperature-at-plus-5": "Standard fremløbstemperatur ved 5 °C", + "default-flow-temperature-at-plus-15": "Standard fremløbstemperatur ved 15 °C", + "delete-account": "Slet konto", + "delete-all-devices": "Slet alle enheder", + "delete-device-from-home": "Slet enhed fra hjem", + "delete-devices": "Slet enheder", + "delete-facility-account": "Slet konto", + "delete-home": "Slet hjem", + "delete-user": "Slet bruger", + "delete-zone": "Slet zone", + "device-id": "Enheds-id", + "device-is-now-removed-from-this-zone": "Enheden er nu fjernet fra denne zone.", + "device-manual_mode-updated": "Manuel tilstand er indstillet for denne enhed.", + "device-name": "Enhedsnavn", + "device-status-updated": "Enhedsstatus opdateret!", + "device-type": "Enhedstype", + "devices-found-in-home": "Enheder fundet i {{ homeName }}", + "devices-imported": "Enheder importeret!", + "devices-in-zone": "Enheder i zone", + "devices-placed-into-zone": "{{numberOfDevices}} enhed(er) placeret i zone.", + "dhw-circuit": "Varmt brugsvandskreds", + "domestic-hot-water-circuit-menu": "Varmt brugsvand (DHW), menu for kreds", + "duplicate-devices": "Duplikerede enheder", + "duplicate-devices-list": "Du har allerede importeret enheder: {{listOfDevices}}", + "duplicate-devices-were-not-imported": "Duplikerede enheder: {{listOfDevices}} blev ikke importeret.", + "ecl-access-code": "ECL-adgangskode", + "ecl-device-added": "Din ECL-enhed {{device}} er blevet tilføjet.", + "ecl-diagram-title": "Nyt ECL-diagram", + "ecl-diagram-title-a-230-1": "Nyt ECL-diagram A230.1", + "ecl-diagram-title-a-247-1": "Nyt ECL-diagram A247.1", + "ecl-diagram-title-a-260-1": "Nyt ECL-diagram A260.1", + "ecl-diagram-title-a-266-1": "Nyt ECL-diagram A266.1", + "ecl-diagram-title-a-347-1": "Nyt ECL-diagram A347.1", + "ecl-diagram-title-a-376-1": "Nyt ECL-diagram A376.1", + "ecl-diagram-title-a-390-1": "Nyt ECL-diagram A390.1", + "ecl-heating-circuit-has-been-successfully-set": "ECL-varmekredsen er blevet indstillet.", + "ecl-menu": "ECL-menu", + "ecl-mode": "Tilstand", + "ecl-mvp-menu": "ECL MVP-menu", + "ecl-status": "Status", + "edit-facilities-access": "Rediger adgang til faciliteter", + "edit-facility-permission": "Rediger placeringstilladelse", + "edit-user": "Rediger bruger", + "edit-zone": "Rediger zone", + "eg-read-only": "f.eks. skrivebeskyttet", + "energy": "Energi", + "error-occurred": "Der opstod en fejl", + "etrv-update-temperature": "Opdater temperatur", + "facilities": "Faciliteter", + "facilities-for-entity-as-read-only-user": "Faciliteter for '{{entityName}}' som skrivebeskyttet bruger", + "facility-area-name": "placeringsområdenavn", + "facility-managers": "Facility Managers", + "facility-name-is-required": "placeringsnavn er påkrævet.", + "floor-map": "Plantegning", + "floors-in-the-room": "Gulve i rummet", + "flow-heating-curve-parameters-history": "Historik over parametre for flowvarmekurve", + "flow-temperature": "Fremløbstemperatur", + "flow-temperature-at-minus-15": "Fremløbstemperatur ved -150 °C", + "flow-temperature-at-minus-30": "Fremløbstemperatur ved -30 °C", + "flow-temperature-at-minus-5": "Fremløbstemperatur ved -5 °C", + "flow-temperature-at-plus-15": "Fremløbstemperatur ved 15 °C", + "flow-temperature-at-plus-5": "Fremløbstemperatur ved 5 °C", + "flow-temperature-at-zero": "Fremløbstemperatur ved 0 °C", + "flow-temperature-curve": "Fremløbstemperaturkurve", + "flow-temperature-values": "Fremløbstemperaturværdier", + "flow-temperature-without-optimization": "Fremløbstemperatur uden optimering", + "gateway-subdevices": "Gateway-underenheder", + "get-subdevices": "Hent underenheder", + "global-temp-set-msg": "Global temperatur er indstillet.", + "go-to-manual": "Gå til manuel tilstand", + "hardware": "Hardware", + "heating-circuit": "Varmekreds", + "heating-circuit-menu": "Menu for varmekreds", + "holiday-7-23h-comfort-temperature": "Ferie 7-23 t komforttemperatur", + "holiday-constant-comfort-temperature": "Ferie, konstant komforttemperatur", + "holiday-constant-setback-temperature": "Ferie, konstant sænkningstemperatur", + "holiday-frost-protection-standby": "Ferie, frostsikring/standby", + "home-alarms": "Hjemmealarmer", + "home-map": "Hjemmekort", + "home-map-with-zones": "Zoner", + "home-name": "Hjemmenavn", + "home-name-is-required": "Hjemmenavn er påkrævet", + "homes": "Hjem", + "homes-and-zones": "Hjem og zoner", + "homes-imported": "Hjem importeret!", + "homes-successfully-imported": "Hjem blev importeret!", + "import-ally-homes-from-the-button": "Importér Ally™ hjem fra knappen med ikonet 'hus'.", + "import-devices": "Importér enheder", + "import-devices-from-home": "Importer enheder fra hjem", + "import-homes": "Importer hjem", + "information": "Information", + "information-will-be-sent-via-email-to-this-user": "Information sendes via e-mail til denne bruger", + "invalid-temp": "Ugyldig temperaturværdi", + "link-to-ecl": "Link til ECL", + "linked-devices": "Tilknyttede enheder", + "list-of-subdevices": "Liste over underenheder", + "location-city": "Placering, by", + "location-country": "Placering, landområder", + "location-on-maps": "Placering på kort", + "location-street": "Placering, vej", + "location-street-number": "Placering, vejnummer", + "location-successfully-created": "Placeringen blev oprettet!", + "location-zip": "Placering, postnummer", + "locations": "Placeringer", + "lower-temperature": "Lavere temperatur", + "manage-home": "Administrer hjem", + "manual-operation": "Manuel drift", + "manual-temp": "Manuel temp.", + "manual-temperature": "Manuel temperatur", + "map": "Kort", + "max-flow-temperature": "Maks. Fremløbstemperatur", + "min-flow-temperature": "Min. Fremløbstemperatur", + "mode": "Tilstand", + "mode-at-home": "Hjemme", + "mode-leaving-home": "Ikke til stede", + "mode-manual": "Manuel", + "mode-pause": "Pause", + "mode-vacation": "Ferie", + "new-entities-table": "Tabel over nye enheder", + "new-led-indicator": "Ny LED-indikator", + "new-scheduler-events": "Nye planlægningsbegivenheder", + "no-devices-found": "Ingen enheder fundet.", + "no-ecl-devices-found": "Ingen ECL-enheder fundet", + "no-vacations": "Ingen planlagte begivenheder", + "number-of-devices-imported": "{{numberOfDevices}} enhed(er) importeret.", + "offline-status": "Offline", + "online": "Online", + "online-status": "Online", + "outdoor-temperature": "Udendørstemperatur", + "override-temperature": "Overstyringstemperatur", + "overview": "Oversigt", + "owner-name": "Ejerens navn", + "parent-facility-name": "Overordnet placeringsnavn", + "pi-heating-demand": "Pi Heating Demand", + "pi-heating-demand-history": "Pi Heating Demand History", + "pi-heating-demand-values-history": "Pi Heating Demand Values History", + "place-devices-in-this-zone": "Placer enheder i denne zone", + "place-into-zone": "Placer i zone", + "please-choose-user-role": "Vælg brugerrolle", + "pre-comfort": "Forkomfort", + "pre-setback": "Forsænkning", + "production-week": "Produktionsuge", + "read-only-users": "Skrivebeskyttede brugere", + "real-etrv-current-temp": "Termostattemperatur", + "refresh-device-status": "Opdater enhedsstatus", + "remove-from-zone": "Fjern fra zone", + "remove-user-from-loc": "Fjern bruger fra denne placering", + "remove-user-title": "Fjern bruger", + "resend-code": "Send kode igen", + "resend-code-msg": "Din kode er sendt! Tjek din e-mail.", + "return-temp": "Returløbstemperatur", + "room-map": "Kort over rum", + "save-comfort-dhw-setpoint": "Gem sætpunkt for 'Komfort varmt brugsvand'", + "save-saving-dhw-setpoint": "Gem sætpunktet 'Gemmer varmt brugsvand'", + "saving-dhw-setpoint": "Gemmer sætpunktet varmt brugsvand", + "saving-room": "Gemmer rum", + "saving-room-setpoint": "Gemmer sætpunkt for rum", + "saving-room-setpoint-is-required": "Gemmer sætpunkt for rum er påkrævet.", + "scheduled-operation": "Planlagt drift", + "scheduler-events": "Planlægningsbegivenheder", + "see-advanced-settings-for-details": "Se avancerede indstillinger for at få yderligere oplysninger", + "see-areas": "se områder", + "see-devices-in-home": "Se enheder i hjemmet", + "see-information": "Se oplysninger", + "selected-devices-are-successfully-linked-with-ecl-device": "Selected device(s) are successfully linked with ECL device.", + "serial-number": "Serienummer", + "set-ecl-heating-circuit": "Set ECL heating circuit", + "select-ecl-device": "Vælg ECL-enhed...", + "device-are-linked-to-ecl": "Den eller de valgte enheder er med succes forbundet med ECL-enhed.", + "unlink-all-devices": "Fjern linket til alle enheder fra ECL", + "unlink-device": "Fjern forbindelsen mellem enhed fra ECL", + "see-pi-history": "Se PI-historik", + "device-unlinked-msg": "Enheden er fjernet fra ECL", + "set-global-temp": "Indstil den globale temperatur", + "are-you-sure-unlink-all": "Er du sikker på at fjerne linket til ALLE enheder fra ECL?", + "are-you-sure-unlink-device": "Er du sikker på at fjerne linket mellem enhed {{device}} og ECL-controlleren?", + "set-temp": "Indstil temp.", + "set-temperature": "Ønsket temperatur", + "set-vacation": "Indstil ferie", + "setback": "Sænkning", + "setback-dhw-setpoint-is-required": "Gemmer sætpunktet varmt brugsvand er påkrævet.", + "software": "Software", + "software-build-no": "Softwarebuildnr.", + "something-went-wrong": "Noget gik galt!", + "subdevices-information-saved": "Gateway-underenheder gemt.", + "successfully-inserted-devices": "{{numberOfDevices}} enhed(er) blev indsat.", + "temp-required": "Temperaturværdi er påkrævet", + "temperature": "Temperatur", + "this-user": "denne bruger", + "title-homes": "Hjem", + "title-location": "Placering", + "update-area-map": "Opdater områdekort", + "update-facilities": "Opdater faciliteter", + "update-home-map": "Opdater hjemmekort", + "update-zone-map": "Opdater zonekort", + "upper-temperature": "Øvre temperatur", + "user-activation-link-has-been-copied-to-clipboard": "Brugeraktiveringslinket er blevet kopieret til udklipsholderen", + "user-removed-fm": "Bruger fjernet som Facility Manager fra denne placering.", + "user-removed-ro": "Bruger fjernet som skrivebeskyttet bruger fra denne placering.", + "user-was-successfully-assigned-to-the-facility": "Brugeren blev tildelt {{facilityName}}", + "user-with-email-already-exists": "Bruger med e-mail '{{email}}' findes allerede!", + "user-with-this-email-is-already-assigned-to-the-facility": "Bruger med denne e-mail er allerede tildelt '{{facilityName}}'.", + "user-with-this-email-was-not-found": "Bruger med denne e-mail blev ikke fundet.", + "vacation-plan": "Ferieplan", + "view-details": "Vis detaljer", + "view-device-information": "Vis enhedsoplysninger", + "view-home": "Vis hjem", + "view-information": "Vis oplysninger", + "view-users": "Brugere", + "view-zone": "Vis zone", + "warning-uppercase": "ADVARSEL", + "were-not-imported": "blev ikke importeret", + "window-state": "Vinduestilstand", + "work-state": "Arbejdstilstand", + "you-dont-have-attribute-free": "Du har ikke en attribut, der er ledig til placeringsnavn!", + "you-have-valid-ally-account": "Du har en gyldig Ally™ konto.", + "your-ally-email-account": "Din Ally™ e-mailkonto", + "your-facilities": "Dine faciliteter", + "your-home-was-successfully-deleted": "Dit hjem blev slettet.", + "zone": "zone", + "zone-have-no-devices-msg": "Der er ingen enheder placeret i zonen. Placer venligst nogle enheder.", + "zone-management": "Zonestyring", + "zone-name": "Navn", + "zone-name-is-required": "Zonenavn er påkrævet.", + "zone-temp-not-enabled": " ikke aktiveret.", + "zone-temp-sett": "Indstilling af temperaturen", + "zone-temp-sett-tooltip": "Ændr temperaturen", + "zone-temperature": "Zonetemperatur", + "zone-view": "Zonevisning" + } + }, + "language": { + "language": "Sprog" + } +} diff --git a/ui-ngx/src/assets/locale/locale.constant-de_DE.json b/ui-ngx/src/assets/locale/locale.constant-de_DE.json index 59adb6bf31..d60ed055ad 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -23,7 +23,7 @@ "no": "Nein", "update": "Aktualisieren", "remove": "Löschen", - "select": "Auswählen", + "select": "Auswählen", "search": "Suche", "clear-search": "Suchanfrage löschen", "assign": "Zuordnen", @@ -57,7 +57,11 @@ "download": "Download", "next-with-label": "Nächste: {{label}}", "read-more": "Mehr dazu", - "hide": "Verstecken" + "hide": "Verstecken", + "done": "Erledigt", + "print": "Drucken", + "restore": "Wiederherstellen", + "confirm": "Bestätigen" }, "aggregation": { "aggregation": "Aggregation", @@ -74,15 +78,15 @@ "admin": { "general": "Allgemein", "general-settings": "Allgemeine Einstellungen", - "home-settings": "Home Einstellungen", + "home-settings": "Home Einstellungen", "outgoing-mail": "E-Mail Versand", "outgoing-mail-settings": "Konfiguration des Postausgangsservers", "system-settings": "Systemeinstellungen", "test-mail-sent": "Test E-Mail wurde erfolgreich versendet!", "base-url": "Basis-URL", "base-url-required": "Basis-URL ist erforderlich.", - "prohibit-different-url": "Prohibit to use hostname from the client request headers", - "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", + "prohibit-different-url": "Prohibit to use hostname from the client request headers", + "prohibit-different-url-hint": "This setting should be enabled for production environments. May cause security issues when disabled", "mail-from": "E-Mail von", "mail-from-required": "E-Mail von ist erforderlich.", "smtp-protocol": "SMTP Protokoll", @@ -96,7 +100,23 @@ "timeout-invalid": "Das ist keine gültige Wartezeit.", "enable-tls": "TLS aktivieren", "tls-version" : "TLS-Version", + "enable-proxy": "Proxy aktivieren", + "proxy-host": "Proxy Host", + "proxy-host-required": "Proxy Host ist erforderlich.", + "proxy-port": "Proxy Port", + "proxy-port-required": "Proxy Port ist erforderlich.", + "proxy-port-range": "Proxy Port sollte im Bereich 1 bis 65535 sein.", + "proxy-user": "Proxy Benutzername", + "proxy-password": "Proxy Passwort", + "change-password": "Passwort ändern", "send-test-mail": "Test E-Mail senden", + "sms-provider": "SMS Anbieter", + "sms-provider-settings": "SMS Anbieter Einstellungen", + "sms-provider-type": "SMS Anbieter Typ", + "sms-provider-type-required": "SMS Anbieter Typ ist erforderlich.", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", "security-settings": "Sicherheitseinstellungen", "password-policy": "Kennwortrichtlinie", "minimum-password-length": "Minimale Passwortlänge", @@ -126,6 +146,8 @@ "no-alarms-matching": "Keine passenden Alarme zu '{{entity}}' wurden gefunden.", "alarm-required": "Alarm ist erforderlich", "alarm-status": "Alarm Status", + "alarm-status-list": "Alarm Status Liste", + "any-status": "Jeder Status", "search-status": { "ANY": "Jeder", "ACTIVE": "Aktiv", @@ -152,6 +174,8 @@ "end-time": "Endzeit", "ack-time": "Bestätigungszeit", "clear-time": "Zeit gelöscht", + "alarm-severity-list": "Alarm Schwere Liste", + "any-severity": "Jede Schwere", "severity-critical": "Kritisch", "severity-major": "Groß", "severity-minor": "Klein", @@ -159,7 +183,7 @@ "severity-indeterminate": "Unbestimmt", "acknowledge": "Bestätigen", "clear": "Löschen", - "search": "Alarme Suchen", + "search": "Alarme suchen", "selected-alarms": "{ count, plural, 1 {1 Alarm} other {# Alarme} } ausgewählt", "no-data": "Keine Daten zum Anzeigen", "polling-interval": "Alarmabfrageintervall (sec)", @@ -184,6 +208,7 @@ "filter-type-single-entity": "Einzelne Entität", "filter-type-entity-list": "Entitätsliste", "filter-type-entity-name": "Entitätsname", + "filter-type-entity-type": "Entitätstyp", "filter-type-state-entity": "Entität aus dem Dashboard Status", "filter-type-state-entity-description": "Entität aus den Dashboard Status Parametern", "filter-type-asset-type": "Objekttyp", @@ -1890,6 +1915,14 @@ "row-double-click": "Doppelklicken auf Zeile" } }, + "paginator" : { + "items-per-page": "Einträge pro Seite:", + "first-page-label": "Erste Seite", + "last-page-label": "Letzte Seite", + "next-page-label": "Nächste Seite", + "previous-page-label": "Vorherige Seite", + "items-per-page-separator": "von" + }, "language": { "language": "Sprache" } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 7216f7b707..c7ce4f9211 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -328,6 +328,8 @@ "repository-url": "Repository URL", "repository-url-required": "Repository URL is required.", "default-branch": "Default branch name", + "repository-read-only": "Read-only", + "show-merge-commits": "Show merge commits", "authentication-settings": "Authentication settings", "auth-method": "Authentication method", "auth-method-username-password": "Password / access token", @@ -380,6 +382,28 @@ "within-time": "Within time (sec)", "within-time-pattern": "Time must be a positive integer.", "within-time-required": "Time is required." + }, + "jwt": { + "security-settings": "JWT security settings", + "issuer-name": "Issuer name", + "issuer-name-required": "Issuer name is required.", + "signings-key": "Signing key", + "signings-key-hint": "Base64 encoded string representing at least 256 bits of data.", + "signings-key-required": "Signing key is required.", + "signings-key-min-length": "Signing key must be at least 256 bits of data.", + "signings-key-base64": "Signing key must be base64 format.", + "expiration-time": "Token expiration time (sec)", + "expiration-time-required": "Token expiration time is required.", + "expiration-time-pattern": "Token expiration time be a positive integer.", + "expiration-time-min": "Minimum time is 60 seconds (1 minute).", + "refresh-expiration-time": "Refresh token expiration time (sec)", + "refresh-expiration-time-required": "Refresh token expiration time is required.", + "refresh-expiration-time-pattern": "Refresh token expiration time be a positive integer.", + "refresh-expiration-time-min": "Minimum time is 900 seconds (15 minute).", + "refresh-expiration-time-less-token": "Refresh token time must be greater token time.", + "generate-key": "Generate key", + "info-header": "All users will be to re-logined", + "info-message": "Change of the JWT Signing Key will cause all issued tokens to be invalid. All users will need to re-login. This will also affect scripts that use Rest API/Websockets." } }, "alarm": { @@ -1039,7 +1063,22 @@ "value-description": "the current value;", "prev-value-description": "result of the previous function call;", "time-prev-description": "timestamp of the previous value;", - "prev-orig-value-description": "original previous value;" + "prev-orig-value-description": "original previous value;", + "aggregation": "Aggregation", + "aggregation-type-hint-common": "For performance reasons, the aggregated values calculation is available only for fixed time intervals like \"current day\", \"current month\", etc, and is not available for sliding window intervals like 'last 30 minutes' or 'last 24 hours'.", + "aggregation-type-none-hint": "Take latest value.", + "aggregation-type-min-hint": "Find minimum value among data points within a selected time window.", + "aggregation-type-max-hint": "Find maximum value among data points within a selected time window.", + "aggregation-type-avg-hint": "Calculate an average value among data points within a selected time window.", + "aggregation-type-sum-hint": "Sum all values of the data points within a selected time window.", + "aggregation-type-count-hint": "Total number of the data points within a selected time window.", + "delta-calculation": "Delta calculation", + "enable-delta-calculation": "Enable delta calculation", + "enable-delta-calculation-hint": "When enabled, the data key value is calculated based on the aggregated values for a selected time window and a specified comparison period. For performance reasons, the delta calculation is available only for history time windows and not for real-time values. For example, you may calculate the delta between the energy consumption for yesterday compared to the energy consumption for the day before yesterday.", + "delta-calculation-result": "Delta calculation result", + "delta-calculation-result-previous-value": "Previous value", + "delta-calculation-result-delta-absolute": "Delta (absolute)", + "delta-calculation-result-delta-percent": "Delta (percent)" }, "datasource": { "type": "Datasource type", @@ -1216,6 +1255,49 @@ "unassign-devices-from-edge-title": "Are you sure you want to unassign { count, plural, 1 {1 device} other {# devices} }?", "unassign-devices-from-edge-text": "After the confirmation all selected devices will be unassigned and won't be accessible by the edge." }, + "asset-profile": { + "asset-profile": "Asset profile", + "asset-profiles": "Asset profiles", + "all-asset-profiles": "All", + "add": "Add asset profile", + "edit": "Edit asset profile", + "asset-profile-details": "Asset profile details", + "no-asset-profiles-text": "No asset profiles found", + "search": "Search asset profiles", + "selected-asset-profiles": "{ count, plural, 1 {1 asset profile} other {# asset profiles} } selected", + "no-asset-profiles-matching": "No asset profile matching '{{entity}}' were found.", + "asset-profile-required": "Asset profile is required", + "idCopiedMessage": "Asset profile Id has been copied to clipboard", + "set-default": "Make asset profile default", + "delete": "Delete asset profile", + "copyId": "Copy asset profile Id", + "name-max-length": "Name should be less than 256", + "new-device-profile-name": "Asset profile name", + "new-device-profile-name-required": "Asset profile name is required.", + "name": "Name", + "name-required": "Name is required.", + "image": "Asset profile image", + "description": "Description", + "default": "Default", + "default-rule-chain": "Default rule chain", + "mobile-dashboard": "Mobile dashboard", + "mobile-dashboard-hint": "Used by mobile application as a asset details dashboard", + "select-queue-hint": "Select from a drop-down list.", + "delete-asset-profile-title": "Are you sure you want to delete the asset profile '{{assetProfileName}}'?", + "delete-asset-profile-text": "Be careful, after the confirmation the asset profile and all related data will become unrecoverable.", + "delete-asset-profiles-title": "Are you sure you want to delete { count, plural, 1 {1 asset profile} other {# asset profiles} }?", + "delete-asset-profiles-text": "Be careful, after the confirmation all selected asset profiles will be removed and all related data will become unrecoverable.", + "set-default-asset-profile-title": "Are you sure you want to make the asset profile '{{assetProfileName}}' default?", + "set-default-asset-profile-text": "After the confirmation the asset profile will be marked as default and will be used for new assets with no profile specified.", + "no-asset-profiles-found": "No asset profiles found.", + "create-new-asset-profile": "Create a new one!", + "create-asset-profile": "Create new asset profile", + "import": "Import asset profile", + "export": "Export asset profile", + "export-failed-error": "Unable to export asset profile: {{error}}", + "asset-profile-file": "Asset profile file", + "invalid-asset-profile-file-error": "Unable to import asset profile: Invalid asset profile data structure." + }, "device-profile": { "device-profile": "Device profile", "device-profiles": "Device profiles", @@ -1707,6 +1789,7 @@ "type-asset": "Asset", "type-device": "Device", "type-device-profile": "Device Profile", + "type-asset-profile": "Asset Profile", "type-entity-view": "Entity View", "type-alarm": "Alarm", "type-rule-chain": "Rule Chain", @@ -1793,6 +1876,10 @@ "type-device-profiles": "Device profiles", "list-of-device-profiles": "{ count, plural, 1 {One device profile} other {List of # device profiles} }", "device-profile-name-starts-with": "Device profiles whose names start with '{{prefix}}'", + "type-asset-profile": "Asset profile", + "type-asset-profiles": "Asset profiles", + "list-of-asset-profiles": "{ count, plural, 1 {One asset profile} other {List of # asset profiles} }", + "asset-profile-name-starts-with": "Asset profiles whose names start with '{{prefix}}'", "type-asset": "Asset", "type-assets": "Assets", "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", @@ -2496,7 +2583,22 @@ "color": "Color", "main": "Main", "right": "Right", - "select": "Select target layout" + "left": "Left", + "select": "Select target layout", + "percentage-width": "Percentage width (%)", + "fixed-width": "Fixed width (px)", + "left-width": "Left column (%)", + "right-width": "Right column (%)", + "pick-fixed-side": "Fixed side: ", + "layout-fixed-width": "Fixed width (px)", + "value-min-error": "Value must be more then {{min}}{{unit}}", + "value-max-error": "Value must be less then {{max}}{{unit}}", + "layout-fixed-width-required": "Fixed width is required", + "right-width-percentage-required": "Right percentage is required", + "left-width-percentage-required": "Left percentage is required", + "divider": "Divider", + "right-side": "Right side layout", + "left-side": "Left side layout" }, "legend": { "direction": "Legend direction", @@ -2645,6 +2747,9 @@ "tokenCopiedSuccessMessage": "JWT token has been copied to clipboard", "tokenCopiedWarnMessage": "JWT token is expired! Please, refresh the page." }, + "profiles": { + "profiles": "Profiles" + }, "security": { "security": "Security", "2fa": { @@ -2908,6 +3013,8 @@ "ui-resources-load-error": "Failed to load configuration ui resources.", "invalid-target-rulechain": "Unable to resolve target rule chain!", "test-script-function": "Test script function", + "script-lang-java-script": "Java Script", + "script-lang-tbel": "TBEL", "message": "Message", "message-type": "Message type", "select-message-type": "Select message type", @@ -3272,6 +3379,12 @@ "hours": "{ hours, plural, 0 { hour } 1 {1 hour } other {# hours } }", "minutes": "{ minutes, plural, 0 { minute } 1 {1 minute } other {# minutes } }", "seconds": "{ seconds, plural, 0 { second } 1 {1 second } other {# seconds } }", + "short": { + "days": "{ days, plural, 1 {1 day } other {# days } }", + "hours": "{ hours, plural, 1 {1 hour } other {# hours } }", + "minutes": "{{minutes}} min ", + "seconds": "{{seconds}} sec " + }, "realtime": "Realtime", "history": "History", "last-prefix": "last", @@ -3421,7 +3534,8 @@ "sync-strategy-overwrite-hint": "Creates or updates selected entities in the repository. All other repository entities are deleted.", "device-credentials-conflict": "Failed to load the device with external id {{entityId}}
              due to the same credentials are already present in the database for another device.
              Please consider disabling the load credentials setting in the restore form.", "missing-referenced-entity": "Failed to load the {{sourceEntityTypeName}} with external id {{sourceEntityId}}
              because it references missing {{targetEntityTypeName}} with id {{targetEntityId}}.", - "runtime-failed": "Failed: {{message}}" + "runtime-failed": "Failed: {{message}}", + "auto-commit-settings-read-only-hint": "Auto-commit feature doesn't work with enabled read-only option in Repository settings." }, "widget": { "widget-library": "Widgets Library", @@ -3600,6 +3714,7 @@ "order": "Order", "height": "Height", "mobile-hide": "Hide widget in mobile mode", + "desktop-hide": "Hide widget in desktop mode", "units": "Special symbol to show next to value", "decimals": "Number of digits after floating point", "timewindow": "Timewindow", @@ -3609,6 +3724,7 @@ "display-legend": "Display legend", "datasources": "Datasources", "maximum-datasources": "Maximum { count, plural, 1 {1 datasource is allowed.} other {# datasources are allowed} }", + "timeseries-key-error": "At least one timeseries data key should be specified", "datasource-type": "Type", "datasource-parameters": "Parameters", "remove-datasource": "Remove datasource", @@ -4190,6 +4306,7 @@ "qr-code": { "use-qr-code-text-function": "Use QR code text function", "qr-code-text-pattern": "QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')", + "qr-code-text-pattern-hint": "QR code text pattern use the value of the first found key in the entities in the entity alias.", "qr-code-text-pattern-required": "QR code text pattern is required.", "qr-code-text-function": "QR code text function" }, @@ -4378,6 +4495,7 @@ "openstreet-provider-hot": "OpenStreetMap.HOT", "openstreet-provider-esri-street": "Esri.WorldStreetMap", "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-esri-imagery": "Esri.WorldImagery", "openstreet-provider-cartodb-positron": "CartoDB.Positron", "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", "use-custom-provider": "Use custom provider", @@ -4543,7 +4661,10 @@ "point-color-function": "Point color function", "use-point-as-anchor": "Use point as anchor", "point-as-anchor-function": "Point as anchor function", - "independent-point-tooltip": "Independent point tooltip" + "independent-point-tooltip": "Independent point tooltip", + "clustering-markers": "Clustering markers", + "use-icon-create-function": "Use markers colour function", + "marker-color-function": "Marker color function" }, "markdown": { "use-markdown-text-function": "Use markdown/HTML value function", @@ -4589,10 +4710,12 @@ "entity-label-column-title": "Entity label column title", "display-entity-type": "Display entity type column", "default-sort-order": "Default sort order", + "custom-title": "Custom header title", "column-width": "Column width (px or %)", "default-column-visibility": "Default column visibility", "column-visibility-visible": "Visible", "column-visibility-hidden": "Hidden", + "column-visibility-hidden-mobile": "Hidden in mobile mode", "column-selection-to-display": "Column selection in 'Columns to Display'", "column-selection-to-display-enabled": "Enabled", "column-selection-to-display-disabled": "Disabled", @@ -4656,6 +4779,14 @@ "row-double-click": "On row double click" } }, + "paginator" : { + "items-per-page": "Items per page:", + "first-page-label": "First page", + "last-page-label": "Last page", + "next-page-label": "Next page", + "previous-page-label": "Previous page", + "items-per-page-separator": "of" + }, "language": { "language": "Language", "locales": { @@ -4668,6 +4799,7 @@ "ko_KR": "한국어", "ru_RU": "Русский", "es_ES": "Español", + "ca_ES": "Catalan", "ja_JP": "日本語", "tr_TR": "Türkçe", "fa_IR": "فارسي", @@ -4678,7 +4810,8 @@ "lv_LV": "Latviešu", "ka_GE": "ქართული", "pt_BR": "Português do Brasil", - "sl_SI": "Slovenščina" + "sl_SI": "Slovenščina", + "da_DK": "Dansk" } } } diff --git a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json index a361d1cab4..1522a03731 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2479,6 +2479,14 @@ "row-double-click": "Дії при подвійному натисканні на рядок" } }, + "paginator" : { + "items-per-page": "Елементів на сторінці:", + "first-page-label": "Перша сторінка", + "last-page-label": "Остання сторінка", + "next-page-label": "Наступна сторінка", + "previous-page-label": "Попередня сторінка", + "items-per-page-separator": "з" + }, "language": { "language": "Мова" } diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index b7c519f7ef..2f1d4cab96 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1,2852 +1,4786 @@ { - "access": { - "access-forbidden": "禁止访问", - "access-forbidden-text": "您没有访问此位置的权限
              如果您仍希望访问此位置,请尝试使用其他用户登录。", - "permission-denied": "权限被拒绝", - "permission-denied-text": "您没有执行此操作的权限!", - "refresh-token-expired": "会话已过期", - "refresh-token-failed": "无法刷新会话", - "unauthorized": "未授权", - "unauthorized-access": "未授权访问", - "unauthorized-access-text": "您需要登陆才能访问这个资源!" - }, - "action": { - "activate": "激活", - "add": "添加", - "apply": "应用", - "apply-changes": "应用更改", - "assign": "分配", - "back": "后退", - "cancel": "取消", - "clear-search": "清除查询", - "close": "关闭", - "continue": "继续", - "copy": "复制", - "copy-reference": "复制引用", - "create": "创建", - "decline-changes": "撤销更改", - "delete": "删除", - "discard-changes": "放弃更改", - "download": "下载", - "drag": "拖拽", - "edit": "编辑", - "edit-mode": "编辑模式", - "enter-edit-mode": "进入编辑模式", - "export": "导出", - "hide": "隐藏", - "import": "导入", - "make-private": "私有", - "next-with-label": "下一个:{{label}}", - "no": "否", - "ok": "确定", - "paste": "粘贴", - "paste-reference": "粘贴引用", - "read-more": "阅读更多", - "refresh": "刷新", - "remove": "移除", - "run": "运行", - "save": "保存", - "saveAs": "另存为", - "search": "查询", - "select": "选择", - "share": "分享", - "share-via": "通过 {{provider}}分享", - "sign-in": "登录!", - "suspend": "暂停", - "unassign": "取消分配", - "undo": "撤销", - "update": "更新", - "view": "查看", - "yes": "是" - }, - "admin": { - "aws-access-key-id": "AWS访问密钥ID", - "aws-access-key-id-required": "需要访问AWS密钥ID", - "aws-region": "AWS地区", - "aws-region-required": "AWS 区域必填", - "aws-secret-access-key": "AWS秘密访问密钥", - "aws-secret-access-key-required": "AWS 访问密钥必填", - "base-url": "基本URL", - "base-url-required": "基本URL必填。", - "domain-name": "域名", - "domain-name-unique": "域名和协议必须是唯一的。", - "enable-proxy": "启用代理", - "enable-tls": "启用TLS", - "error-verification-url": "域名不应包含符号 “/” 和 “:”。例:thingsboard.io", - "general": "基本设置", - "general-policy": "基本策略", - "general-settings": "基本设置", - "home-settings": "首页设置", - "mail-from": "邮件来自", - "mail-from-required": "邮件发件人必填。", - "max-failed-login-attempts": "登录失败之前的最大登录尝试次数", - "minimum-digits": "最小位数", - "minimum-digits-range": "最小位数不能为负数", - "minimum-lowercase-letters": "最小小写字母数", - "minimum-lowercase-letters-range": "小写字母的最小数目不能为负数", - "minimum-max-failed-login-attempts-range": "登录失败次数不能为负数", - "minimum-password-length": "最小密码长度", - "minimum-password-length-range": "最小密码长度应在5到50之间", - "minimum-password-length-required": "最小密码长度必填", - "minimum-special-characters": "最小特殊字符数", - "minimum-special-characters-range": "特殊字符的最小数目不能为负数", - "minimum-uppercase-letters": "最小大写字母数", - "minimum-uppercase-letters-range": "大写字母的最小数目不能为负数", - "number-from": "发送方电话号码", - "number-from-required": "发送方电话号码必填。", - "number-to": "电话号码至", - "number-to-required": "电话号码必填。", - "oauth2": { - "access-token-uri": "访问令牌URI", - "access-token-uri-required": "访问令牌 URI 必填。", - "activate-user": "激活用户", - "add-domain": "添加域", - "add-provider": "添加 Provider", - "allow-user-creation": "允许用户创建", - "always-fullscreen": "始终全屏", - "authorization-uri": "授权URI", - "authorization-uri-required": "授权 URI 必填。", - "client-authentication-method": "客户端身份验证方法", - "client-id": "客户端ID", - "client-id-required": "客户端 ID 必填。", - "client-secret": "客户机密", - "client-secret-required": "需要客户端密码。", - "copy-redirect-uri": "复制重定向URI", - "custom-setting": "自定义设置", - "customer-name-pattern": "客户名称模式", - "default-dashboard-name": "默认仪表板名称", - "delete-domain": "删除域", - "delete-domain-text": "请注意:确认后域和所有 provider data 将不可用。", - "delete-domain-title": "确实要删除域 '{{domainName}}' 的设置吗?", - "delete-provider": "删除 Provider", - "delete-registration-text": "请注意:确认后 provider data 将不可用。", - "delete-registration-title": "确实要删除 provider '{{name}}' 吗?", - "domain-schema-http": "HTTP", - "domain-schema-https": "HTTPS", - "domain-schema-mixed": "HTTP+HTTPS", - "email-attribute-key": "电子邮件属性键", - "email-attribute-key-required": "电子邮件属性密钥必填。", - "enable": "启用OAuth2设置", - "first-name-attribute-key": "名字属性键", - "general": "General", - "jwk-set-uri": "JSON Web Key URI", - "last-name-attribute-key": "姓氏属性键", - "login-button-icon": "登录按钮图标", - "login-button-label": "Provider 标签", - "login-button-label-placeholder": "使用 $(Provider label) 登录", - "login-button-label-required": "标签必填。", - "login-provider": "Login provider", - "mapper": "Mapper", - "new-domain": "新建域", - "oauth2": "OAuth2", - "protocol": "协议", - "redirect-uri-template": "重定向URI模板", - "registration-id": "注册ID", - "registration-id-required": "注册 ID 必填。", - "registration-id-unique": "系统的注册ID必须是唯一的。", - "scope": "范围", - "scope-required": "范围必填。", - "tenant-name-pattern": "租户名称模式", - "tenant-name-pattern-required": "租户名称模式必填。", - "tenant-name-strategy": "租户名称策略", - "type": "映射器类型", - "uri-pattern-error": "无效的URI格式。", - "url": "统一资源定位地址", - "url-pattern": "无效的URL格式。", - "url-required": "URL 必填。", - "user-info-uri": "用户信息URI", - "user-info-uri-required": "用户信息 URI 必填。", - "user-name-attribute-name": "用户名属性键", - "user-name-attribute-name-required": "用户名属性密钥必填" - }, - "outgoing-mail": "发送邮件", - "outgoing-mail-settings": "发送邮件设置", - "password-expiration-period-days": "密码有效期(天)", - "password-expiration-period-days-range": "密码过期期限(天)不能为负", - "password-policy": "密码策略", - "password-reuse-frequency-days": "密码重用频率(天)", - "password-reuse-frequency-days-range": "天内密码重用频率不能为负", - "phone-number-hint": "E.164格式的电话号码,例如+19995550123", - "phone-number-pattern": "电话号码无效。应为E.164格式,例如+19995550123。", - "prohibit-different-url": "禁止从客户端请求头中使用主机名", - "prohibit-different-url-hint": "应为生产环境启用此设置。禁用时可能会导致安全问题", - "proxy-host": "代理主机", - "proxy-host-required": "代理主机必填。", - "proxy-password": "代理密码", - "proxy-port": "代理端口", - "proxy-port-range": "代理端口应在1到65535之间。", - "proxy-port-required": "代理端口必填。", - "proxy-user": "代理用户", - "security-settings": "安全设置", - "send-test-mail": "发送测试邮件", - "send-test-sms": "发送测试短信", - "sms-message": "短信", - "sms-message-max-length": "短信长度不能超过1600个字符", - "sms-message-required": "短消息内容必填。", - "sms-provider": "SMS 服务商", - "sms-provider-settings": "SMS 服务商设置", - "sms-provider-type": "SMS 服务商类型", - "sms-provider-type-aws-sns": "亚马逊社交网站", - "sms-provider-type-required": "SMS 服务商类型必填。", - "sms-provider-type-twilio": "Twilio", - "smtp-host": "SMTP主机", - "smtp-host-required": "SMTP主机必填。", - "smtp-port": "SMTP端口", - "smtp-port-invalid": "这看起来不是有效的smtp端口。", - "smtp-port-required": "您必须提供一个smtp端口。", - "smtp-protocol": "SMTP协议", - "system-settings": "系统设置", - "test-mail-sent": "测试邮件发送成功!", - "test-sms-sent": "测试短信发送成功!", - "timeout-invalid": "这看起来不像有效的超时值。", - "timeout-msec": "超时(ms)", - "timeout-required": "超时必填。", - "tls-version": "TLS版本", - "twilio-account-sid": "Twilio帐户SID", - "twilio-account-sid-required": "Twilio 帐户的 SID 必填", - "twilio-account-token": "Twilio帐户令牌", - "twilio-account-token-required": "Twilio 帐户令牌必填", - "user-lockout-notification-email": "如果用户帐户锁定,请发送通知到电子邮件" - }, - "aggregation": { - "aggregation": "聚合", - "avg": "平均值", - "count": "计数", - "function": "数据聚合功能", - "group-interval": "分组间隔", - "limit": "最大值", - "max": "最大值", - "min": "最少值", - "none": "空", - "sum": "求和" - }, - "alarm": { - "ack-time": "确认时间", - "acknowledge": "应答", - "aknowledge-alarm-text": "确定要确认报警吗?", - "aknowledge-alarm-title": "确认报警", - "aknowledge-alarms-text": "确定要确认 { count, plural, 1 {# 个警告} other {# 个警告} }?", - "aknowledge-alarms-title": "确认 { count, plural, 1 {# 个警告} other {# 个警告} }", - "alarm": "警告", - "alarm-details": "报警详细信息", - "alarm-filter": "报警筛选器", - "alarm-required": "警告必填", - "alarm-severity-list": "警报严重性列表", - "alarm-status": "警告状态", - "alarm-status-filter": "报警状态筛选器", - "alarm-status-list": "报警状态列表", - "alarm-type-list": "报警类型列表", - "alarms": "警告", - "any-severity": "任何严重程度", - "any-status": "任何状态", - "any-type": "任何类型", - "clear": "清除", - "clear-alarm-text": "确定要清除警报吗?", - "clear-alarm-title": "清除警报", - "clear-alarms-text": "确定要清除 { count, plural, 1 {# 个警告} other {# 个警告} }?", - "clear-alarms-title": "清除 { count, plural, 1 {# 个警告} other {# 个警告} }", - "clear-time": "清除时间", - "created-time": "创建时间", - "details": "详情", - "display-status": { - "ACTIVE_ACK": "激活已确认", - "ACTIVE_UNACK": "激活未确认", - "CLEARED_ACK": "清除已确认", - "CLEARED_UNACK": "清除未确认" - }, - "end-time": "结束时间", - "fetch-size": "获取大小", - "fetch-size-error-min": "最小值为10。", - "fetch-size-required": "Fetch size 必填。", - "max-count-load": "要加载的最大报警数(0-无限制)", - "max-count-load-error-min": "最小值为0。", - "max-count-load-required": "加载的最大报警数必填。", - "min-polling-interval-message": "轮询间隔至少是1秒。", - "no-alarms-matching": "没有找到匹配 '{{entity}}' 的警告", - "no-alarms-prompt": "未发现警告", - "no-data": "无数据显示", - "originator": "发起者", - "originator-type": "发起者类型", - "polling-interval": "警告轮询间隔(秒)", - "polling-interval-required": "警告轮询间隔必填。", - "search": "查找警告", - "search-propagated-alarms": "检索已传递的警报", - "search-status": { - "ACK": "已确认", - "ACTIVE": "激活", - "ANY": "所有", - "CLEARED": "已清除", - "UNACK": "未确认" - }, - "select-alarm": "选择警告", - "selected-alarms": "已选择 { count, plural, 1 {# 个警告} other {# 个警告} }", - "severity": "严重程度", - "severity-critical": "危险", - "severity-indeterminate": "不确定", - "severity-major": "重要", - "severity-minor": "次要", - "severity-warning": "警告", - "start-time": "开始时间", - "status": "状态", - "type": "类型" - }, - "alias": { - "add": "添加别名", - "all-entities": "所有实体", - "any-relation": "不限", - "default-entity-parameter-name": "默认", - "default-state-entity": "默认状态实体", - "duplicate-alias": "别名已经存在。", - "edit": "编辑别名", - "entity-filter": "实体筛选器", - "entity-filter-no-entity-matched": "未找到符合指定筛选条件的实体。", - "filter-type": "筛选器类型", - "filter-type-apiUsageState": "Api使用状态", - "filter-type-asset-search-query": "资产搜索查询", - "filter-type-asset-search-query-description": "类型为 {{assetTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的资产", - "filter-type-asset-type": "资产类型", - "filter-type-asset-type-and-name-description": "类型为 '{{assetType}}' 且以 '{{prefix}}' 开头的资产", - "filter-type-asset-type-description": "类型为 '{{assetType}}' 的资产", - "filter-type-device-search-query": "设备搜索查询", - "filter-type-device-search-query-description": "类型为 {{deviceTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的设备", - "filter-type-device-type": "设备类型", - "filter-type-device-type-and-name-description": "类型为 '{{deviceType}}' 且以 '{{prefix}}' 开头的设备", - "filter-type-device-type-description": "类型为 '{{deviceType}}' 的设备", - "filter-type-edge-type": "边缘类型", - "filter-type-edge-type-description": "类型为 '{{edgeType}}' 的边缘", - "filter-type-edge-type-and-name-description": "类型为 '{{edgeType}}' 且以 '{{prefix}}' 开头的边缘", - "filter-type-edge-search-query": "边缘搜索查询", - "filter-type-edge-search-query-description": "类型为 {{edgeTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的边缘", - "filter-type-entity-list": "实体列表", - "filter-type-entity-name": "实体名称", - "filter-type-entity-view-search-query": "实体视图搜索查询", - "filter-type-entity-view-search-query-description": "类型为 {{entityViewTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的实体视图", - "filter-type-entity-view-type": "实体视图类型", - "filter-type-entity-view-type-and-name-description": "类型为 {{entityView}}' 且以 '{{prefix}}' 开头的实体视图", - "filter-type-entity-view-type-description": "类型为 '{{entityView}}' 的实体视图", - "filter-type-relations-query": "关联查询", - "filter-type-relations-query-description": "具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的 {{entities}} ", - "filter-type-required": "筛选器类型必填。", - "filter-type-single-entity": "单个实体", - "filter-type-state-entity": "仪表板实体状态", - "filter-type-state-entity-description": "仪表板实体令牌状态参数", - "last-level-relation": "仅获取最后一级关联", - "max-relation-level": "最大关联层级", - "name": "别名", - "name-required": "别名必填", - "no-entity-filter-specified": "没有指定实体筛选器", - "resolve-multiple": "解决为多实体", - "root-entity": "根实体", - "root-state-entity": "使用仪表板状态实体作为根实体", - "state-entity": "仪表板状态实体", - "state-entity-parameter-name": "状态实体参数名称", - "unlimited-level": "不限层级" - }, - "api-usage": { - "api-usage": "Api 使用统计", - "data-points": "数据点", - "data-points-storage-days": "日存储数据点数", - "email": "Email", - "email-messages": "Email messages", - "email-messages-daily-activity": "Email messages daily activity", - "email-messages-hourly-activity": "Email messages hourly activity", - "email-messages-monthly-activity": "Email messages monthly activity", - "exceptions": "Exceptions", - "executions": "Executions", - "javascript": "JavaScript", - "javascript-executions": "JavaScript executions", - "javascript-functions": "JavaScript functions", - "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-hourly-activity": "JavaScript functions hourly activity", - "javascript-functions-monthly-activity": "JavaScript functions monthly activity", - "latest-error": "最新错误", - "messages": "消息", - "permanent-failures": "${entityName} 永久性故障", - "permanent-timeouts": "${entityName} 永久超时", - "processing-failures": "${entityName} 处理失败", - "processing-failures-and-timeouts": "处理失败和超时", - "processing-timeouts": "${entityName} 处理超时", - "queue-stats": "队列统计信息", - "rule-chain": "规则链", - "rule-engine": "规则引擎", - "rule-engine-daily-activity": "Rule Engine daily activity", - "rule-engine-executions": "Rule Engine executions", - "rule-engine-hourly-activity": "Rule Engine hourly activity", - "rule-engine-monthly-activity": "Rule Engine monthly activity", - "rule-engine-statistics": "规则引擎统计信息", - "rule-node": "规则节点", - "sms": "SMS", - "sms-messages": "短信", - "sms-messages-daily-activity": "SMS messages daily activity", - "sms-messages-hourly-activity": "SMS messages hourly activity", - "sms-messages-monthly-activity": "SMS messages monthly activity", - "successful": "${entityName} 成功", - "telemetry": "遥测数据", - "telemetry-persistence": "Telemetry persistence", - "telemetry-persistence-daily-activity": "Telemetry persistence daily activity", - "telemetry-persistence-hourly-activity": "Telemetry persistence hourly activity", - "telemetry-persistence-monthly-activity": "Telemetry persistence monthly activity", - "transport": "Transport", - "transport-daily-activity": "Transport daily activity", - "transport-data-points": "传输数据点", - "transport-hourly-activity": "Transport hourly activity", - "transport-messages": "传输消息", - "transport-monthly-activity": "Transport monthly activity", - "view-details": "查看详细信息", - "view-statistics": "查看统计信息", - "alarm":"警告", - "alarms-created": "创建警告数", - "notifications": "通知" - }, - "asset": { - "add": "添加资产", - "add-asset-text": "添加新资产", - "any-asset": "任何资产", - "asset": "资产", - "asset-details": "资产详情", - "asset-file": "资产档案", - "asset-public": "资产公开", - "asset-required": "资产必填", - "asset-type": "资产类型", - "asset-type-list-empty": "资产类型未选择。", - "asset-type-required": "资产类型必填。", - "asset-types": "资产类型", - "assets": "资产", - "assign-asset-to-customer": "将资产分配给客户", - "assign-asset-to-customer-text": "请选择要分配给客户的资产", - "assign-asset-to-edge-text": "请选择要分配给边缘的资产", - "assign-asset-to-edge-title": "将资产分配给边缘", - "assign-assets": "分配资产", - "assign-assets-text": "分配 { count, plural, 1 {# 个资产} other {# 个资产} } 给客户", - "assign-new-asset": "分配新资产", - "assign-to-customer": "分配给客户", - "assign-to-customer-text": "请选择客户以分配资产", - "assignedToCustomer": "分配客户", - "copyId": "复制资产ID", - "delete": "删除资产", - "delete-asset-text": "请注意:确认后资产及其所有相关数据将不可恢复。", - "delete-asset-title": "确定要删除资产 '{{assetName}}'?", - "delete-assets": "删除资产", - "delete-assets-action-title": "删除 { count, plural, 1 {# 个资产} other {# 个资产} }", - "delete-assets-text": "请注意:确认后,所有选定的资产将被删除,所有相关的数据将变得不可恢复。", - "delete-assets-title": "确定要删除 { count, plural, 1 {# 个资产} other {# 个资产} }?", - "description": "说明", - "details": "详情", - "enter-asset-type": "输入资产类型", - "events": "事件", - "idCopiedMessage": "资产ID已经复制到粘贴板", - "import": "导入资产", - "label": "标签", - "make-private": "资产设为私有", - "make-private-asset-text": "确认后,资产及其所有数据将被私有化,无法被他人访问。", - "make-private-asset-title": "你确定你想创建私有 '{{assetName}}' 资产?", - "make-public": "资产设为公开", - "make-public-asset-text": "确认后,资产及其所有数据将被公开并被他人访问。", - "make-public-asset-title": "你确定你想创建公开'{{assetName}}'资产?", - "management": "资产管理", - "name": "名称", - "name-required": "名称必填。", - "name-starts-with": "资产名称以此开头", - "no-asset-types-matching": "没有找到匹配 '{{entitySubtype}}' 的资产类型。", - "no-assets-matching": "没有找到匹配 '{{entity}}' 的资产。", - "no-assets-text": "未找到资产", - "public": "公开", - "search": "查找资产", - "select-asset": "选择资产", - "select-asset-type": "选择资产类型", - "selected-assets": "已选择 { count, plural, 1 {# 个资产} other {# 个资产} }", - "type": "类型", - "type-required": "类型必填。", - "unassign-asset": "未分配资产", - "unassign-asset-from-edge": "取消分配边缘", - "unassign-asset-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", - "unassign-asset-from-edge-title": "您确定要取消对'{{assetName}}'资产的分配吗?", - "unassign-asset-text": "确认后,资产将未分配,客户无法访问。", - "unassign-asset-title": "您确定要取消对'{{assetName}}'资产的分配吗?", - "unassign-assets": "取消分配资产", - "unassign-assets-action-title": "从客户处取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }", - "unassign-assets-text": "确认后,所有选定的资产将被分配,客户无法访问。", - "unassign-assets-title": "您确定要取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }吗?", - "unassign-from-customer": "取消分配客户", - "unassign-assets-from-edge": "取消分配边缘", - "unassign-assets-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", - "unassign-assets-from-edge-title": "您确定要取消分配 { count, plural, 1 {1 资产} other {# 个资产} }吗?", - "view-assets": "查看资产" - }, - "attribute": { - "add": "添加属性", - "add-to-dashboard": "添加到仪表板", - "add-widget-to-dashboard": "将部件添加到仪表板", - "attributes": "属性", - "attributes-scope": "设备属性范围", - "delete-attributes": "删除属性", - "delete-attributes-text": "注意,确认后所有选中的属性都会被删除。", - "delete-attributes-title": "您确定要删除 { count, plural, 1 {# 个属性} other {# 个属性} }吗?", - "enter-attribute-value": "输入属性值", - "key": "键名", - "key-required": "属性键必填。", - "last-update-time": "最后更新时间", - "latest-telemetry": "最新遥测数据", - "next-widget": "下一个部件", - "no-attributes-text": "找不到属性", - "no-telemetry-text": "未找到遥测数据", - "prev-widget": "上一个部件", - "scope-client": "客户端属性", - "scope-latest-telemetry": "最新遥测数据", - "scope-server": "服务端属性", - "scope-shared": "共享属性", - "selected-attributes": "已选择{ count, plural, 1 {# 个属性} other {# 个属性} }", - "selected-telemetry": "已选择 { count, plural, 1 {# telemetry unit} other {# telemetry units} }", - "show-on-widget": "在部件上显示", - "value": "价值", - "value-required": "属性值必填。", - "widget-mode": "部件模式" - }, - "audit-log": { - "action-data": "活动数据", - "audit": "审计", - "audit-log-details": "审计日志详情", - "audit-logs": "审计日志", - "clear-search": "清空查找", - "details": "详情", - "entity-name": "实体名称", - "entity-type": "实体类型", - "failure-details": "失败详情", - "no-audit-logs-prompt": "找不到日志", - "search": "查找审计日志", - "status": "状态", - "status-failure": "失败", - "status-success": "成功", - "timestamp": "时间戳", - "type": "类型", - "type-activated": "激活", - "type-added": "添加", - "type-alarm-ack": "已确认", - "type-alarm-clear": "已清除", - "type-assigned-from-tenant": "从租户分配", - "type-assigned-to-customer": "分配给客户", - "type-assigned-to-edge": "分配给边缘", - "type-assigned-to-tenant": "分配给租户", - "type-attributes-deleted": "删除属性", - "type-attributes-read": "读取属性", - "type-attributes-updated": "更新属性", - "type-credentials-read": "读取凭证", - "type-credentials-updated": "更新凭证", - "type-deleted": "删除", - "type-lockout": "锁定", - "type-login": "登录", - "type-logout": "注销", - "type-provision-failure": "设备预配置失败", - "type-provision-success": "设备已预配置", - "type-relation-add-or-update": "关联已更新", - "type-relation-delete": "关联已删除", - "type-relations-delete": "删除所有关联", - "type-rpc-call": "RPC调用", - "type-suspended": "暂停", - "type-timeseries-deleted": "遥测数据已删除", - "type-timeseries-updated": "遥测数据已更新", - "type-unassigned-from-customer": "未分配给客户", - "type-unassigned-from-edge": "未分配给边缘", - "type-updated": "更新", - "user": "用户" - }, - "common": { - "created-time": "创建时间", - "enter-password": "输入密码", - "enter-search": "输入检索条件", - "enter-username": "输入用户名", - "loading": "正在加载中...", - "password": "密码", - "username": "用户名", - "proceed": "继续", - "open-details-page": "打开详情页" - }, - "confirm-on-exit": { - "html-message": "您有未保存的更改。
              确定要离开此页面吗?", - "message": "您有未保存的更改。确定要离开此页吗?", - "title": "未保存的更改" - }, - "contact": { - "address": "地址", - "address2": "地址2", - "city": "城市", - "country": "国家", - "email": "电子邮件", - "no-address": "无地址", - "phone": "电话", - "postal-code": "邮政编码", - "postal-code-invalid": "只允许数字。", - "state": "州" - }, - "content-type": { - "binary": "Binary (Base64)", - "json": "Json", - "text": "Text" - }, - "custom": { + "access": { + "unauthorized": "未授权", + "unauthorized-access": "未授权访问", + "unauthorized-access-text": "您需要登陆才能访问这个资源!", + "access-forbidden": "禁止访问", + "access-forbidden-text": "您没有访问此位置的权限
              如果您仍希望访问此位置,请尝试使用其他用户登录。", + "refresh-token-expired": "会话已过期", + "refresh-token-failed": "无法刷新会话", + "permission-denied": "权限被拒绝", + "permission-denied-text": "您没有执行此操作的权限!" + }, + "action": { + "activate": "激活", + "suspend": "暂停", + "save": "保存", + "saveAs": "另存为", + "cancel": "取消", + "ok": "确定", + "delete": "删除", + "add": "添加", + "yes": "是", + "no": "否", + "update": "更新", + "remove": "移除", + "select": "选择", + "search": "查询", + "clear-search": "清除查询", + "assign": "分配", + "unassign": "取消分配", + "share": "分享", + "make-private": "私有", + "apply": "应用", + "apply-changes": "应用更改", + "edit-mode": "编辑模式", + "enter-edit-mode": "进入编辑模式", + "decline-changes": "撤销更改", + "close": "关闭", + "back": "后退", + "run": "运行", + "sign-in": "登录!", + "edit": "编辑", + "view": "查看", + "create": "创建", + "drag": "拖拽", + "refresh": "刷新", + "undo": "撤销", + "copy": "复制", + "paste": "粘贴", + "copy-reference": "复制引用", + "paste-reference": "粘贴引用", + "import": "导入", + "export": "导出", + "share-via": "通过{{provider}}分享", + "continue": "继续", + "discard-changes": "放弃更改", + "download": "下载", + "next-with-label": "下一个:{{label}}", + "read-more": "阅读更多", + "hide": "隐藏", + "done": "完毕", + "print": "打印", + "restore": "恢复", + "confirm": "确认" + }, + "aggregation": { + "aggregation": "聚合", + "function": "数据聚合功能", + "limit": "限制数", + "group-interval": "分组间隔", + "min": "最小值", + "max": "最大值", + "avg": "平均值", + "sum": "求和", + "count": "计数", + "none": "无" + }, + "admin": { + "general": "基本设置", + "general-settings": "基本设置", + "home-settings": "首页设置", + "outgoing-mail": "发送邮件", + "outgoing-mail-settings": "发送邮件设置", + "system-settings": "系统设置", + "test-mail-sent": "测试邮件发送成功!", + "base-url": "基本URL", + "base-url-required": "基本URL必填。", + "prohibit-different-url": "禁止从客户端请求头中使用主机名", + "prohibit-different-url-hint": "应为生产环境启用此设置。禁用时可能会导致安全问题", + "mail-from": "邮件来自", + "mail-from-required": "邮件发件人必填。", + "smtp-protocol": "SMTP协议", + "smtp-host": "SMTP主机", + "smtp-host-required": "SMTP主机必填。", + "smtp-port": "SMTP端口", + "smtp-port-required": "您必须提供一个smtp端口。", + "smtp-port-invalid": "这看起来不是有效的smtp端口。", + "timeout-msec": "超时时间(毫秒)", + "timeout-required": "超时必填。", + "timeout-invalid": "这看起来不像有效的超时值。", + "enable-tls": "启用TLS", + "tls-version": "TLS版本", + "enable-proxy": "启用代理", + "proxy-host": "代理主机", + "proxy-host-required": "代理主机必填。", + "proxy-port": "代理端口", + "proxy-port-required": "代理端口必填。", + "proxy-port-range": "代理端口应在1到65535之间。", + "proxy-user": "代理用户", + "proxy-password": "代理密码", + "change-password": "Change password", + "send-test-mail": "发送测试邮件", + "sms-provider": "SMS 服务商", + "sms-provider-settings": "SMS 服务商设置", + "sms-provider-type": "SMS 服务商类型", + "sms-provider-type-required": "SMS 服务商类型必填。", + "sms-provider-type-aws-sns": "亚马逊社交网站", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", + "aws-access-key-id": "AWS访问密钥ID", + "aws-access-key-id-required": "需要访问AWS密钥ID", + "aws-secret-access-key": "AWS秘密访问密钥", + "aws-secret-access-key-required": "AWS 访问密钥必填", + "aws-region": "AWS地区", + "aws-region-required": "AWS 区域必填", + "number-from": "发送方电话号码", + "number-from-required": "发送方电话号码必填。", + "number-to": "电话号码至", + "number-to-required": "电话号码必填。", + "phone-number-hint": "E.164格式的手机号码,例如+19995550123", + "phone-number-hint-twilio": "Phone Number in E.164 format/Phone Number's SID/Messaging Service SID, ex. +19995550123/PNXXX/MGXXX", + "phone-number-pattern": "手机号码无效。应为E.164格式,例如+19995550123。", + "phone-number-pattern-twilio": "Invalid phone number. Should be in E.164 format/Phone Number's SID/Messaging Service SID, ex. +19995550123/PNXXX/MGXXX.", + "sms-message": "短信", + "sms-message-required": "短消息内容必填。", + "sms-message-max-length": "短信长度不能超过1600个字符", + "twilio-account-sid": "Twilio帐户SID", + "twilio-account-sid-required": "Twilio 帐户的 SID 必填", + "twilio-account-token": "Twilio帐户令牌", + "twilio-account-token-required": "Twilio 帐户令牌必填", + "send-test-sms": "发送测试短信", + "test-sms-sent": "测试短信发送成功!", + "security-settings": "安全设置", + "password-policy": "密码策略", + "minimum-password-length": "最小密码长度", + "minimum-password-length-required": "最小密码长度必填", + "minimum-password-length-range": "最小密码长度应在5到50之间", + "minimum-uppercase-letters": "最少大写字母位数", + "minimum-uppercase-letters-range": "最少大写字母位数不能为负数", + "minimum-lowercase-letters": "最少小写字母位数", + "minimum-lowercase-letters-range": "最少小写字母位数不能为负数", + "minimum-digits": "最少数字位数", + "minimum-digits-range": "最少数字位数不能为负数", + "minimum-special-characters": "最少特殊字符位数", + "minimum-special-characters-range": "最少特殊字符位数不能为负数", + "password-expiration-period-days": "密码有效期(天)", + "password-expiration-period-days-range": "密码过期期限(天)不能为负", + "password-reuse-frequency-days": "密码重用频率(天)", + "password-reuse-frequency-days-range": "天内密码重用频率不能为负", + "allow-whitespace": "Allow whitespace", + "general-policy": "基本策略", + "max-failed-login-attempts": "登录失败之前的最大登录尝试次数", + "minimum-max-failed-login-attempts-range": "登录失败次数不能为负数", + "user-lockout-notification-email": "如果用户帐户锁定,请发送通知到电子邮件", + "domain-name": "域名", + "domain-name-unique": "域名和协议必须是唯一的。", + "domain-name-max-length": "域名长度不能大于256", + "error-verification-url": "域名不应包含符号 “/” 和 “:”。例:thingsboard.io", + "oauth2": { + "access-token-uri": "访问令牌URI", + "access-token-uri-required": "访问令牌 URI 必填。", + "activate-user": "激活用户", + "add-domain": "添加域", + "delete-domain": "删除域", + "add-provider": "添加 Provider", + "delete-provider": "删除 Provider", + "allow-user-creation": "允许用户创建", + "always-fullscreen": "始终全屏", + "authorization-uri": "授权URI", + "authorization-uri-required": "授权 URI 必填。", + "client-authentication-method": "客户端身份验证方法", + "client-id": "客户端ID", + "client-id-required": "客户端 ID 必填。", + "client-id-max-length": "客户端ID长度不能大于256", + "client-secret": "客户机密", + "client-secret-required": "需要客户端密码。", + "client-secret-max-length": "客户端密钥长度不能大于2049", + "custom-setting": "自定义设置", + "customer-name-pattern": "客户名称模式", + "customer-name-pattern-max-length": "客户名称模式长度不能大于256", + "default-dashboard-name": "默认仪表板名称", + "default-dashboard-name-max-length": "默认仪表板名称长度不能大于256", + "delete-domain-text": "请注意:确认后,域和所有 provider data 将不可恢复。", + "delete-domain-title": "确定要删除域 '{{domainName}}' 的设置吗?", + "delete-registration-text": "请注意:确认后 provider data 将不可恢复。", + "delete-registration-title": "确定要删除 provider '{{name}}' 吗?", + "email-attribute-key": "电子邮件属性键", + "email-attribute-key-required": "电子邮件属性密钥必填。", + "email-attribute-key-max-length": "电子邮件属性键长度不能大于32", + "first-name-attribute-key": "名字属性键", + "first-name-attribute-key-max-length": "名字属性键长度不能大于32", + "general": "基本设置", + "jwk-set-uri": "JSON Web Key URI", + "last-name-attribute-key": "姓氏属性键", + "last-name-attribute-key-max-length": "姓氏属性键长度不能大于32", + "login-button-icon": "登录按钮图标", + "login-button-label": "Provider 标签", + "login-button-label-placeholder": "使用 $(Provider label) 登录", + "login-button-label-required": "标签必填。", + "login-provider": "Login provider", + "mapper": "Mapper", + "new-domain": "新建域", + "oauth2": "OAuth2", + "password-max-length": "密码长度不能大于256", + "redirect-uri-template": "重定向URI模板", + "copy-redirect-uri": "复制重定向URI", + "registration-id": "注册ID", + "registration-id-required": "注册 ID 必填。", + "registration-id-unique": "系统的注册ID必须是唯一的。", + "scope": "范围", + "scope-required": "范围必填。", + "tenant-name-pattern": "租户名称模式", + "tenant-name-pattern-required": "租户名称模式必填。", + "tenant-name-pattern-max-length": "租户名称模式长度不能大于256", + "tenant-name-strategy": "租户名称策略", + "type": "映射器类型", + "uri-pattern-error": "无效的URI格式。", + "url": "统一资源定位地址", + "url-pattern": "无效的URL格式。", + "url-required": "URL 必填。", + "url-max-length": "URL地址长度不能大于256", + "user-info-uri": "用户信息URI", + "user-info-uri-required": "用户信息 URI 必填。", + "username-max-length": "用户名称长度不能大于256", + "user-name-attribute-name": "用户名属性键", + "user-name-attribute-name-required": "用户名属性密钥必填", + "protocol": "协议", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "启用OAuth2设置", + "domains": "域名", + "mobile-apps": "移动端", + "no-mobile-apps": "无移动端应用配置", + "mobile-package": "应用程包", + "mobile-package-placeholder": "例如: my.example.app", + "mobile-package-hint": "Android:应用程序ID,iOS:产品标识符", + "mobile-package-unique": "应用程序包必须是唯一的。", + "mobile-app-secret": "应用程序密钥", + "invalid-mobile-app-secret": "应用程序密钥必须包含字母,数字,字符并且长度必须在16到2048个字符。", + "copy-mobile-app-secret": "复制应用程序密钥", + "add-mobile-app": "添加应用程序", + "delete-mobile-app": "删除应用程序", + "providers": "提供程序", + "platform-web": "Web", + "platform-android": "Android", + "platform-ios": "iOS", + "all-platforms": "所有平台", + "allowed-platforms": "允许平台" + }, + "smpp-provider": { + "smpp-version": "SMPP版本", + "smpp-host": "SMPP主机", + "smpp-host-required": "SMPP主机必填", + "smpp-port": "SMPP端口", + "smpp-port-required": "SMPP端口必填", + "system-id": "系统ID", + "system-id-required": "系统ID必填", + "password": "密码", + "password-required": "密码必填", + "type-settings": "类型设置", + "source-settings": "源设置", + "destination-settings": "目的地", + "additional-settings": "其他设置", + "system-type": "系统类型", + "bind-type": "绑定类型", + "service-type": "服务类型", + "source-address": "源地址", + "source-ton": "源TON", + "source-npi": "源NPI", + "destination-ton": "目的地TON号码", + "destination-npi": "目的地NPI号码", + "address-range": "地址范围", + "coding-scheme": "编码方案", + "bind-type-tx": "发送者", + "bind-type-rx": "接收者", + "bind-type-trx": "收发器", + "ton-unknown": "未知", + "ton-international": "International", + "ton-national": "National", + "ton-network-specific": "Network Specific", + "ton-subscriber-number": "Subscriber Number", + "ton-alphanumeric": "Alphanumeric", + "ton-abbreviated": "Abbreviated", + "npi-unknown": "0 - Unknown", + "npi-isdn": "1 - ISDN/telephone numbering plan (E163/E164)", + "npi-data-numbering-plan": "3 - Data numbering plan (X.121)", + "npi-telex-numbering-plan": "4 - Telex numbering plan (F.69)", + "npi-land-mobile": "6 - Land Mobile (E.212)", + "npi-national-numbering-plan": "8 - National numbering plan", + "npi-private-numbering-plan": "9 - Private numbering plan", + "npi-ermes-numbering-plan": "10 - ERMES numbering plan (ETSI DE/PS 3 01-3)", + "npi-internet": "13 - Internet (IP)", + "npi-wap-client-id": "18 - WAP Client Id (to be defined by WAP Forum)", + "scheme-smsc": "0 - SMSC Default Alphabet (ASCII for short and long code and to GSM for toll-free)", + "scheme-ia5": "1 - IA5 (ASCII for short and long code, Latin 9 for toll-free (ISO-8859-9))", + "scheme-octet-unspecified-2": "2 - Octet Unspecified (8-bit binary)", + "scheme-latin-1": "3 - Latin 1 (ISO-8859-1)", + "scheme-octet-unspecified-4": "4 - Octet Unspecified (8-bit binary)", + "scheme-jis": "5 - JIS (X 0208-1990)", + "scheme-cyrillic": "6 - Cyrillic (ISO-8859-5)", + "scheme-latin-hebrew": "7 - Latin/Hebrew (ISO-8859-8)", + "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", + "scheme-pictogram-encoding": "9 - Pictogram Encoding", + "scheme-music-codes": "10 - Music Codes (ISO-2022-JP)", + "scheme-extended-kanji-jis": "13 - Extended Kanji JIS (X 0212-1990)", + "scheme-korean-graphic-character-set": "14 - Korean Graphic Character Set (KS C 5601/KS X 1001)" + }, + "queue-select-name": "选择队列名称", + "queue-name": "名称", + "queue-name-required": "队列名称必填。", + "queues": "队列", + "queue-partitions": "分区", + "queue-submit-strategy": "提交策略", + "queue-processing-strategy": "处理策略", + "queue-configuration": "队列配置", + "repository-settings": "仓库设置", + "repository-url": "仓库 URL", + "repository-url-required": "仓库 URL 必填。", + "default-branch": "默认分支名称", + "repository-read-only": "Read-only", + "authentication-settings": "身份验证设置", + "auth-method": "身份验证方法", + "auth-method-username-password": "密码/访问令牌", + "auth-method-private-key": "私钥", + "password-access-token": "密码/访问令牌", + "change-password-access-token": "更改密码/访问令牌", + "private-key": "私钥", + "drop-private-key-file-or": "拖放私钥文件或", + "passphrase": "口令", + "enter-passphrase": "输入口令", + "change-passphrase": "更改口令", + "check-access": "检查访问权限", + "check-repository-access-success": "已成功验证仓库访问!", + "delete-repository-settings-title": "确定要删除仓库设置吗?", + "delete-repository-settings-text": "请注意:确认后,仓库设置将被删除,版本控制功能将不可用。", + "auto-commit-settings": "自动提交设置", + "auto-commit-entities": "自动提交实体", + "no-auto-commit-entities-prompt": "没有设置自动提交的实体", + "delete-auto-commit-settings-title": "确定要删除自动提交设置吗?", + "delete-auto-commit-settings-text": "请注意:确认后,自动提交设置将被删除,所有实体的自动提交将被禁用。", + "2fa": { + "2fa": "双因素身份验证", + "available-providers": "可用选项", + "issuer-name": "发行者名称", + "issuer-name-required": "发行者名称必填。", + "max-verification-failures-before-user-lockout": "用户锁定前最大验证失败次数", + "max-verification-failures-before-user-lockout-pattern": "最大验证失败次数必须为正整数。", + "number-of-checking-attempts": "检查尝试次数", + "number-of-checking-attempts-pattern": "检查尝试次数必须为正整数。", + "number-of-checking-attempts-required": "检查尝试次数必填。", + "number-of-codes": "验证码数量", + "number-of-codes-pattern": "验证码数量必须为正整数。", + "number-of-codes-required": "验证码数量必填。", + "provider": "Provider", + "retry-verification-code-period": "重试验证码周期(秒)", + "retry-verification-code-period-pattern": "最短时间为5秒", + "retry-verification-code-period-required": "重试验证代码周期必填。", + "total-allowed-time-for-verification": "总允许验证时间(秒)", + "total-allowed-time-for-verification-pattern": "总允许验证最小时间为60秒", + "total-allowed-time-for-verification-required": "总允许验证时间必填。", + "use-system-two-factor-auth-settings": "使用系统双因素身份验证设置", + "verification-code-check-rate-limit": "验证码检查速率限制", + "verification-code-lifetime": "验证码生存期(秒)", + "verification-code-lifetime-pattern": "验证码生存期必须为正整数。", + "verification-code-lifetime-required": "验证码生存期必填。", + "verification-message-template": "验证消息模板", + "verification-limitations": "验证限制", + "verification-message-template-pattern": "验证消息需要包含模板:${code}", + "verification-message-template-required": "验证消息模板必填。", + "within-time": "在时间内 (秒)", + "within-time-pattern": "时间必须是正整数。", + "within-time-required": "时间必填。" + } + }, + "alarm": { + "alarm": "告警", + "alarms": "告警", + "select-alarm": "选择告警", + "no-alarms-matching": "未找到匹配 '{{entity}}' 的告警", + "alarm-required": "告警必填", + "alarm-status": "告警状态", + "alarm-status-list": "告警状态列表", + "any-status": "任何状态", + "search-status": { + "ANY": "所有", + "ACTIVE": "激活", + "CLEARED": "已清除", + "ACK": "已确认", + "UNACK": "未确认" + }, + "display-status": { + "ACTIVE_UNACK": "激活未确认", + "ACTIVE_ACK": "激活已确认", + "CLEARED_UNACK": "清除未确认", + "CLEARED_ACK": "清除已确认" + }, + "no-alarms-prompt": "未发现告警", + "created-time": "创建时间", + "type": "类型", + "severity": "严重程度", + "originator": "发起者", + "originator-type": "发起者类型", + "details": "详情", + "status": "状态", + "alarm-details": "告警详细信息", + "start-time": "开始时间", + "end-time": "结束时间", + "ack-time": "确认时间", + "clear-time": "清除时间", + "alarm-severity-list": "警报严重性列表", + "any-severity": "任何严重程度", + "severity-critical": "危险", + "severity-major": "重要", + "severity-minor": "次要", + "severity-warning": "警告", + "severity-indeterminate": "不确定", + "acknowledge": "应答", + "clear": "清除", + "search": "查找告警", + "selected-alarms": "已选择 { count, plural, 1 {# 个告警} other {# 个告警} }", + "no-data": "无数据显示", + "polling-interval": "告警轮询间隔(秒)", + "polling-interval-required": "告警轮询间隔必填。", + "min-polling-interval-message": "轮询间隔至少是1秒。", + "aknowledge-alarms-title": "确认 { count, plural, 1 {# 个告警} other {# 个告警} }", + "aknowledge-alarms-text": "确定要确认 { count, plural, 1 {# 个告警} other {# 个告警} }吗?", + "aknowledge-alarm-title": "确认告警", + "aknowledge-alarm-text": "确定要确认告警吗?", + "clear-alarms-title": "清除 { count, plural, 1 {# 个告警} other {# 个告警} }", + "clear-alarms-text": "确定要清除 { count, plural, 1 {# 个告警} other {# 个告警} }?", + "clear-alarm-title": "清除警报", + "clear-alarm-text": "确定要清除警报吗?", + "alarm-status-filter": "告警状态筛选器", + "alarm-filter": "告警筛选器", + "max-count-load": "要加载的最大告警数(0-无限制)", + "max-count-load-required": "加载的最大告警数必填。", + "max-count-load-error-min": "最小值为0。", + "fetch-size": "获取大小", + "fetch-size-required": "Fetch size 必填。", + "fetch-size-error-min": "最小值为10。", + "alarm-type-list": "告警类型列表", + "any-type": "任何类型", + "search-propagated-alarms": "检索已传递的警报" + }, + "alias": { + "add": "添加别名", + "edit": "编辑别名", + "name": "别名", + "name-required": "别名必填", + "duplicate-alias": "别名已经存在。", + "filter-type-single-entity": "单个实体", + "filter-type-entity-list": "实体列表", + "filter-type-entity-name": "实体名称", + "filter-type-entity-type": "Entity type", + "filter-type-state-entity": "仪表板状态实体", + "filter-type-state-entity-description": "仪表板实体令牌状态参数", + "filter-type-asset-type": "资产类型", + "filter-type-asset-type-description": "类型为 '{{assetType}}' 的资产", + "filter-type-asset-type-and-name-description": "类型为 '{{assetType}}' 且以 '{{prefix}}' 开头的资产", + "filter-type-device-type": "设备类型", + "filter-type-device-type-description": "类型为 '{{deviceType}}' 的设备", + "filter-type-device-type-and-name-description": "类型为 '{{deviceType}}' 且以 '{{prefix}}' 开头的设备", + "filter-type-entity-view-type": "实体视图类型", + "filter-type-entity-view-type-description": "类型为 '{{entityView}}' 的实体视图", + "filter-type-entity-view-type-and-name-description": "类型为 {{entityView}}' 且以 '{{prefix}}' 开头的实体视图", + "filter-type-edge-type": "边缘类型", + "filter-type-edge-type-description": "类型为 '{{edgeType}}' 的边缘", + "filter-type-edge-type-and-name-description": "类型为 '{{edgeType}}' 且以 '{{prefix}}' 开头的边缘", + "filter-type-relations-query": "关联查询", + "filter-type-relations-query-description": "具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的 {{entities}} ", + "filter-type-asset-search-query": "资产搜索查询", + "filter-type-asset-search-query-description": "类型为 {{assetTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的资产", + "filter-type-device-search-query": "设备搜索查询", + "filter-type-device-search-query-description": "类型为 {{deviceTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的设备", + "filter-type-entity-view-search-query": "实体视图搜索查询", + "filter-type-entity-view-search-query-description": "类型为 {{entityViewTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的实体视图", + "filter-type-apiUsageState": "Api使用状态", + "filter-type-edge-search-query": "边缘搜索查询", + "filter-type-edge-search-query-description": "类型为 {{edgeTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的边缘", + "entity-filter": "实体筛选器", + "resolve-multiple": "解析为多实体", + "filter-type": "筛选器类型", + "filter-type-required": "筛选器类型必填。", + "entity-filter-no-entity-matched": "未找到匹配指定筛选条件的实体。", + "no-entity-filter-specified": "没有指定实体筛选器", + "root-state-entity": "使用仪表板状态实体作为根实体", + "last-level-relation": "仅获取最后一级关联", + "root-entity": "根实体", + "state-entity-parameter-name": "状态实体参数名称", + "default-state-entity": "默认状态实体", + "default-entity-parameter-name": "默认", + "max-relation-level": "最大关联层级", + "unlimited-level": "不限层级", + "state-entity": "仪表板状态实体", + "all-entities": "所有实体", + "any-relation": "不限" + }, + "asset": { + "asset": "资产", + "assets": "资产", + "management": "资产管理", + "view-assets": "查看资产", + "add": "添加资产", + "asset-type-max-length": "资产类型要小于256", + "assign-to-customer": "分配给客户", + "assign-asset-to-customer": "将资产分配给客户", + "assign-asset-to-customer-text": "请选择要分配给客户的资产", + "no-assets-text": "未找到资产", + "assign-to-customer-text": "请选择客户以分配资产", + "public": "公开", + "assignedToCustomer": "分配客户", + "make-public": "资产设为公开", + "make-private": "资产设为私有", + "unassign-from-customer": "取消分配客户", + "delete": "删除资产", + "asset-public": "资产公开", + "asset-type": "资产类型", + "asset-type-required": "资产类型必填。", + "select-asset-type": "选择资产类型", + "enter-asset-type": "输入资产类型", + "any-asset": "任何资产", + "no-asset-types-matching": "未找到匹配 '{{entitySubtype}}' 的资产类型。", + "asset-type-list-empty": "资产类型未选择。", + "asset-types": "资产类型", + "name": "名称", + "name-required": "名称必填。", + "name-max-length": "名称长度不能大于256", + "label-max-length": "标签长度应小于256", + "description": "说明", + "type": "类型", + "type-required": "类型必填。", + "details": "详情", + "events": "事件", + "add-asset-text": "添加新资产", + "asset-details": "资产详情", + "assign-assets": "分配资产", + "assign-assets-text": "分配 { count, plural, 1 {# 个资产} other {# 个资产} } 给客户", + "assign-asset-to-edge-title": "将资产分配给边缘", + "assign-asset-to-edge-text": "请选择要分配给边缘的资产", + "delete-assets": "删除资产", + "unassign-assets": "取消分配资产", + "unassign-assets-action-title": "从客户处取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }", + "assign-new-asset": "分配新资产", + "delete-asset-title": "确定要删除资产 '{{assetName}}'吗?", + "delete-asset-text": "请注意:确认后,资产及其所有相关数据将不可恢复。", + "delete-assets-title": "确定要删除 { count, plural, 1 {# 个资产} other {# 个资产} }吗?", + "delete-assets-action-title": "删除 { count, plural, 1 {# 个资产} other {# 个资产} }", + "delete-assets-text": "请注意:确认后,所有选定的资产将被删除,所有相关的数据将不可恢复。", + "make-public-asset-title": "确定要将资产 '{{assetName}}' 设为公开吗?", + "make-public-asset-text": "确认后,资产及其所有数据将被公开并被他人访问。", + "make-private-asset-title": "确定要将资产 '{{assetName}}' 设为私有吗?", + "make-private-asset-text": "确认后,资产及其所有数据将被私有化,无法被他人访问。", + "unassign-asset-title": "确定要取消对'{{assetName}}'资产的分配吗?", + "unassign-asset-text": "确认后,资产将未分配,客户无法访问。", + "unassign-asset": "未分配资产", + "unassign-assets-title": "确定要取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }吗?", + "unassign-assets-text": "确认后,所有选定的资产将被分配,客户无法访问。", + "unassign-assets-from-edge": "取消分配边缘", + "copyId": "复制资产ID", + "idCopiedMessage": "资产ID已经复制到粘贴板", + "select-asset": "选择资产", + "no-assets-matching": "未找到匹配 '{{entity}}' 的资产。", + "asset-required": "资产必填", + "name-starts-with": "资产名称以此开头", + "help-text": "根据需要可以使用'%'进行匹配,例如:'%asset_name_contains%', '%asset_name_ends', 'asset_starts_with'。", + "import": "导入资产", + "asset-file": "资产档案", + "label": "标签", + "search": "查找资产", + "assign-asset-to-edge": "Assign Asset(s) To Edge", + "unassign-asset-from-edge": "取消分配边缘", + "unassign-asset-from-edge-title": "确定要取消对'{{assetName}}'资产的分配吗?", + "unassign-asset-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", + "unassign-assets-from-edge-title": "确定要取消分配 { count, plural, 1 {1 资产} other {# 个资产} }吗?", + "unassign-assets-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", + "selected-assets": "已选择 { count, plural, 1 {# 个资产} other {# 个资产} }" + }, + "attribute": { + "attributes": "属性", + "latest-telemetry": "最新遥测数据", + "attributes-scope": "设备属性范围", + "scope-latest-telemetry": "最新遥测数据", + "scope-client": "客户端属性", + "scope-server": "服务端属性", + "scope-shared": "共享属性", + "add": "添加属性", + "key": "键名", + "key-max-length": "关键字长度应小于256", + "last-update-time": "最后更新时间", + "key-required": "属性键必填。", + "value": "数值", + "value-required": "属性值必填。", + "delete-attributes-title": "确定要删除 { count, plural, 1 {# 个属性} other {# 个属性} }吗?", + "delete-attributes-text": "注意,确认后所有选中的属性都会被删除。", + "delete-attributes": "删除属性", + "enter-attribute-value": "输入属性值", + "show-on-widget": "在部件上显示", + "widget-mode": "部件模式", + "next-widget": "下一个部件", + "prev-widget": "上一个部件", + "add-to-dashboard": "添加到仪表板", + "add-widget-to-dashboard": "将部件添加到仪表板", + "selected-attributes": "已选择{ count, plural, 1 {# 个属性} other {# 个属性} }", + "selected-telemetry": "已选择 { count, plural, 1 {# 遥测} other {# 遥测} }", + "no-attributes-text": "未找到属性", + "no-telemetry-text": "未找到遥测数据" + }, + "api-usage": { + "api-usage": "Api统计", + "alarm": "警报", + "alarms-created": "创建警报数", + "alarms-created-daily-activity": "每天产生的警报", + "alarms-created-hourly-activity": "每小时产生的警报", + "alarms-created-monthly-activity": "每月产生的警报", + "data-points": "数据点", + "data-points-storage-days": "日存储数据点数", + "email": "邮件", + "email-messages": "邮件信息", + "email-messages-daily-activity": "每天产生的邮件信息", + "email-messages-monthly-activity": "每月产生的邮件信息", + "exceptions": "例外", + "executions": "执行", + "javascript": "JavaScript", + "javascript-executions": "JavaScript例外", + "javascript-functions": "JavaScript函数", + "javascript-functions-daily-activity": "每天执行的JavaScript函数", + "javascript-functions-hourly-activity": "每小时执行的JavaScript函数", + "javascript-functions-monthly-activity": "每月执行的JavaScript函数", + "latest-error": "最新错误", + "messages": "消息", + "notifications": "通知", + "notifications-email-sms": "通知(Email/SMS)", + "notifications-hourly-activity": "每小时的通知", + "permanent-failures": "${entityName}永久性故障", + "permanent-timeouts": "${entityName}永久超时", + "processing-failures": "${entityName}处理失败", + "processing-failures-and-timeouts": "处理失败和超时", + "processing-timeouts": "${entityName}处理超时", + "queue-stats": "队列统计信息", + "rule-chain": "规则链", + "rule-engine": "规则引擎", + "rule-engine-daily-activity": "每天的规则引擎活动", + "rule-engine-executions": "规则引擎执行", + "rule-engine-hourly-activity": "每小时的规则引擎活动", + "rule-engine-monthly-activity": "每月的规则引擎活动", + "rule-engine-statistics": "规则引擎统计信息", + "rule-node": "规则节点", + "sms": "SMS", + "sms-messages": "短信信息", + "sms-messages-daily-activity": "每天的短信息", + "sms-messages-monthly-activity": "每小时的短信息", + "successful": "${entityName}成功", + "telemetry": "遥测数据", + "telemetry-persistence": "遥测持久化", + "telemetry-persistence-daily-activity": "每天的遥测持久化", + "telemetry-persistence-hourly-activity": "每小时的遥测持久化", + "telemetry-persistence-monthly-activity": "每月的遥测持久化", + "transport": "传输", + "transport-daily-activity": "每天传输数据量", + "transport-data-points": "传输数据点", + "transport-hourly-activity": "每小时传输数据量", + "transport-messages": "传输消息", + "transport-monthly-activity": "每月传输数据量", + "view-details": "查看详细信息", + "view-statistics": "查看统计信息" + }, + "audit-log": { + "audit": "审计", + "audit-logs": "审计日志", + "timestamp": "时间戳", + "entity-type": "实体类型", + "entity-name": "实体名称", + "user": "用户", + "type": "类型", + "status": "状态", + "details": "详情", + "type-added": "添加", + "type-deleted": "删除", + "type-updated": "更新", + "type-attributes-updated": "更新属性", + "type-attributes-deleted": "删除属性", + "type-rpc-call": "RPC调用", + "type-credentials-updated": "更新凭据", + "type-assigned-to-customer": "分配给客户", + "type-unassigned-from-customer": "未分配给客户", + "type-assigned-to-edge": "分配给边缘", + "type-unassigned-from-edge": "未分配给边缘", + "type-activated": "激活", + "type-suspended": "暂停", + "type-credentials-read": "读取凭据", + "type-attributes-read": "读取属性", + "type-relation-add-or-update": "关联已更新", + "type-relation-delete": "关联已删除", + "type-relations-delete": "删除所有关联", + "type-alarm-ack": "已确认", + "type-alarm-clear": "已清除", + "type-login": "登录", + "type-logout": "注销", + "type-lockout": "锁定", + "status-success": "成功", + "status-failure": "失败", + "audit-log-details": "审计日志详情", + "no-audit-logs-prompt": "未找到日志", + "action-data": "活动数据", + "failure-details": "失败详情", + "search": "查找审计日志", + "clear-search": "清空查找", + "type-assigned-from-tenant": "从租户分配", + "type-assigned-to-tenant": "分配给租户", + "type-provision-success": "设备已预配置", + "type-provision-failure": "设备预配置失败", + "type-timeseries-updated": "遥测数据已更新", + "type-timeseries-deleted": "遥测数据已删除" + }, + "confirm-on-exit": { + "message": "有未保存的更改,确定要离开此页吗?", + "html-message": "有未保存的更改。
              确定要离开此页面吗?", + "title": "未保存的更改" + }, + "contact": { + "country": "国家", + "city": "城市", + "state": "州", + "postal-code": "邮政编码", + "postal-code-invalid": "只允许数字。", + "address": "地址", + "address2": "地址二", + "phone": "电话", + "email": "电子邮件", + "no-address": "无地址", + "state-max-length": "省份名称长度应小于256", + "phone-max-length": "电话号码长度应小于256", + "city-max-length": "城市名称长度应小于256" + }, + "common": { + "username": "用户名", + "password": "密码", + "enter-username": "输入用户名", + "enter-password": "输入密码", + "enter-search": "输入检索条件", + "created-time": "创建时间", + "loading": "正在加载中...", + "proceed": "继续", + "open-details-page": "打开详情页" + }, + "content-type": { + "json": "Json", + "text": "Text", + "binary": "Binary (Base64)" + }, + "customer": { + "customer": "客户", + "customers": "客户", + "management": "客户管理", + "dashboard": "客户仪表板", + "dashboards": "客户仪表板", + "devices": "客户设备", + "entity-views": "客户实体视图", + "assets": "客户资产", + "public-dashboards": "公共仪表板", + "public-devices": "公共设备", + "public-assets": "公共资产", + "public-edges": "公共边缘", + "public-entity-views": "公共实体视图", + "add": "添加客户", + "delete": "删除此客户", + "manage-customer-users": "管理客户用户", + "manage-customer-devices": "管理客户设备", + "manage-customer-dashboards": "管理客户仪表板", + "manage-public-devices": "管理公共设备", + "manage-public-dashboards": "管理公共仪表板", + "manage-customer-assets": "管理客户资产", + "manage-public-assets": "管理公共资产", + "manage-customer-edges": "管理客户边缘", + "manage-public-edges": "管理公共边缘", + "add-customer-text": "添加新客户", + "no-customers-text": "未找到客户", + "customer-details": "客户详情", + "delete-customer-title": "确定要删除客户'{{customerTitle}}'吗?", + "delete-customer-text": "请注意:确认后,客户及其所有相关数据将不可恢复。", + "delete-customers-title": "确定要删除 { count, plural, 1 {# 个客户} other {# 个客户} }吗?", + "delete-customers-action-title": "删除 { count, plural, 1 {# 个客户} other {# 个客户} }", + "delete-customers-text": "请注意:确认后,所有选定的客户将被删除,所有相关数据将不可恢复。", + "manage-users": "管理用户", + "manage-assets": "管理资产", + "manage-devices": "管理设备", + "manage-dashboards": "管理仪表板", + "title": "标题", + "title-required": "标题必填。", + "title-max-length": "标题长度必须少于256个字符", + "description": "说明", + "details": "详情", + "events": "事件", + "copyId": "复制客户ID", + "idCopiedMessage": "客户ID已复制到粘贴板", + "select-customer": "选择客户", + "no-customers-matching": "未找到匹配 '{{entity}}' 的客户。", + "customer-required": "客户必填", + "select-default-customer": "选择默认的客户", + "default-customer": "默认客户", + "default-customer-required": "为了调试租户级别上的仪表板,需要默认客户。", + "search": "查找客户", + "selected-customers": "已选择 { count, plural, 1 {# 个客户} other {# 个客户} }", + "edges": "客户边缘实例", + "manage-edges": "管理边缘" + }, + "datetime": { + "date-from": "开始日期", + "time-from": "开始时间", + "date-to": "结束日期", + "time-to": "结束时间" + }, + "dashboard": { + "dashboard": "仪表板", + "dashboards": "仪表板库", + "management": "仪表板管理", + "view-dashboards": "查看仪表板", + "add": "添加仪表板", + "assign-dashboard-to-customer": "将仪表板分配给客户", + "assign-dashboard-to-customer-text": "请选择要分配给客户的仪表板", + "assign-dashboard-to-edge-title": "将仪表板分配给边缘", + "assign-to-customer-text": "请选择客户分配仪表板", + "assign-to-customer": "分配给客户", + "unassign-from-customer": "取消分配客户", + "make-public": "仪表板设为公开", + "make-private": "仪表板设为私有", + "manage-assigned-customers": "管理已分配的客户", + "assigned-customers": "已分配的客户", + "assign-to-customers": "将仪表板分配给客户", + "assign-to-customers-text": "请选择客户指定仪表板", + "unassign-from-customers": "客户未分配仪表板", + "unassign-from-customers-text": "请选择从仪表板中取消分配的客户", + "no-dashboards-text": "未找到仪表板", + "no-widgets": "没有配置部件", + "add-widget": "添加新的部件", + "title": "标题", + "image": "仪表板图片", + "mobile-app-settings": "移动端应用设置", + "mobile-order": "移动端应用中的仪表板排序", + "mobile-hide": "在移动端应用中隐藏仪表板", + "update-image": "更新缩略图", + "take-screenshot": "截图", + "select-widget-title": "选择部件", + "select-widget-value": "{{title}}: 选择部件", + "select-widget-subtitle": "可用的部件类型列表", + "delete": "删除仪表板", + "title-required": "标题必填。", + "title-max-length": "标题长度必须少于256个字符", + "description": "说明", + "details": "详情", + "dashboard-details": "仪表板详情", + "add-dashboard-text": "添加新的仪表板", + "assign-dashboards": "分配仪表板", + "assign-new-dashboard": "分配新的仪表板", + "assign-dashboards-text": "分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", + "unassign-dashboards-action-text": "取消分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", + "delete-dashboards": "删除仪表板", + "unassign-dashboards": "取消分配仪表板", + "unassign-dashboards-action-title": "取消分配此客户 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", + "delete-dashboard-title": "确定要删除仪表板 '{{dashboardTitle}}'吗?", + "delete-dashboard-text": "请注意:确认后,仪表板及其所有相关数据将不可恢复。", + "delete-dashboards-title": "确定要删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }吗?", + "delete-dashboards-action-title": "删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", + "delete-dashboards-text": "请注意:确认后,所有选定的仪表板将被删除,所有相关数据将不可恢复。", + "unassign-dashboard-title": "确定要取消分配仪表板 '{{dashboardTitle}}'吗?", + "unassign-dashboard-text": "确认后,面板将被取消分配,客户将无法访问。", + "unassign-dashboard": "取消分配仪表板", + "unassign-dashboards-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", + "unassign-dashboards-text": "确认后,所有选定的仪表板将被取消分配,客户将无法访问。", + "public-dashboard-title": "仪表板现已公开", + "public-dashboard-text": "仪表板 {{dashboardTitle}} 已被公开,可通过如下 链接访问:", + "public-dashboard-notice": "提示: 不要忘记将相关设备公开以访问其数据。", + "make-private-dashboard-title": "确定要将仪表板 '{{dashboardTitle}}' 设为私有吗?", + "make-private-dashboard-text": "确认后,仪表板将被设为私有,不能被其他人访问。", + "make-private-dashboard": "仪表板设为私有", + "socialshare-text": "'{{dashboardTitle}}' 由Thingsboard提供支持", + "socialshare-title": "'{{dashboardTitle}}' 由Thingsboard提供支持", + "select-dashboard": "选择仪表板", + "no-dashboards-matching": "未找到匹配 '{{entity}}' 的仪表板。", + "dashboard-required": "仪表板必填。", + "select-existing": "选择现有仪表板", + "create-new": "创建新的仪表板", + "new-dashboard-title": "新仪表板标题", + "open-dashboard": "打开仪表板", + "set-background": "设置背景", + "background-color": "背景颜色", + "background-image": "背景图片", + "background-size-mode": "背景大小模式", + "no-image": "无图像选择", + "empty-image": "No image", + "drop-image": "拖拽图像或单击以选择要上传的文件。", + "maximum-upload-file-size": "最大上传文件大小: {{ size }}", + "cannot-upload-file": "无法上传文件", + "settings": "设置", + "layout-settings": "Layout settings", + "columns-count": "列数", + "columns-count-required": "需要列数。", + "min-columns-count-message": "只允许最少10列", + "max-columns-count-message": "只允许最多1000列", + "widgets-margins": "部件间边距", + "margin-required": "边距值必填。", + "min-margin-message": "最小边距值只允许为0。", + "max-margin-message": "仅允许50作为最大边距值。", + "horizontal-margin": "水平边距", + "horizontal-margin-required": "需要水平边距值。", + "min-horizontal-margin-message": "只允许0作为最小水平边距值。", + "max-horizontal-margin-message": "只允许50作为最大水平边距值。", + "vertical-margin": "垂直边距", + "vertical-margin-required": "需要垂直边距值。", + "min-vertical-margin-message": "只允许0作为最小垂直边距值。", + "max-vertical-margin-message": "只允许50作为最大垂直边距值。", + "autofill-height": "自动填充布局高度", + "mobile-layout": "移动端布局设置", + "mobile-row-height": "移动端行高距(px)", + "mobile-row-height-required": "移动端行高距必填。", + "min-mobile-row-height-message": "移动端行高距至少5px。", + "max-mobile-row-height-message": "移动端行高距最多200px。", + "title-settings": "Title settings", + "display-title": "显示仪表板标题", + "title-color": "标题颜色", + "toolbar-settings": "Toolbar settings", + "hide-toolbar": "Hide toolbar", + "toolbar-always-open": "工具栏常驻", + "display-dashboards-selection": "显示仪表板选项", + "display-entities-selection": "显示实体选项", + "display-filters": "显示筛选器", + "display-dashboard-timewindow": "显示时间窗口", + "display-dashboard-export": "显示导出", + "display-update-dashboard-image": "显示仪表板缩略图", + "dashboard-logo-settings": "Logo设置", + "display-dashboard-logo": "在仪表板全屏模式下显示 Logo", + "dashboard-logo-image": "仪表板 Logo 图片", + "advanced-settings": "高级设置", + "dashboard-css": "仪表板样式", + "import": "导入仪表板", + "export": "导出仪表板", + "export-failed-error": "无法导出仪表板: {{error}}", + "create-new-dashboard": "创建新的仪表板", + "dashboard-file": "仪表板文件", + "invalid-dashboard-file-error": "无法导入仪表板: 仪表板数据结构无效。", + "dashboard-import-missing-aliases-title": "配置导入仪表板使用的别名", + "create-new-widget": "创建新部件", + "import-widget": "导入部件", + "widget-file": "部件文件", + "invalid-widget-file-error": "无法导入窗口部件: 窗口部件数据结构无效。", + "widget-import-missing-aliases-title": "配置导入的窗口部件使用的别名", + "open-toolbar": "打开仪表板工具栏", + "close-toolbar": "关闭工具栏", + "configuration-error": "配置错误", + "alias-resolution-error-title": "仪表板别名配置错误", + "invalid-aliases-config": "无法找到与某些别名筛选器匹配的任何设备。
              请联系您的管理员以解决此问题。", + "select-devices": "选择设备", + "assignedToCustomer": "分配给客户", + "assignedToCustomers": "分配给客户", + "public": "公开", + "copyId": "复制仪表板Id", + "idCopiedMessage": "仪表板ID已经复制到粘贴板", + "public-link": "公共链接", + "copy-public-link": "复制公共链接", + "public-link-copied-message": "仪表板的公共链接已被复制到剪贴板", + "manage-states": "仪表板状态管理", + "states": "仪表板状态", + "search-states": "仪表板状态检索", + "selected-states": "已选择 { count, plural, 1 {# 个仪表板状态} other {# 个仪表板状态} }", + "edit-state": "仪表板状态编辑", + "delete-state": "删除仪表板状态", + "add-state": "添加仪表板状态", + "no-states-text": "未找到状态", + "state": "仪表板状态", + "state-name": "名称", + "state-name-required": "仪表板状态名必填。", + "state-id": "状态ID", + "state-id-required": "仪表板状态ID必填。", + "state-id-exists": "仪表板状态ID已经存在。", + "is-root-state": "根状态", + "delete-state-title": "删除仪表板状态", + "delete-state-text": "确定要删除仪表板状态 '{{stateName}}' 吗?", + "show-details": "显示详情", + "hide-details": "隐藏详情", + "select-state": "选择目标状态", + "state-controller": "状态控制", + "search": "查找仪表板", + "selected-dashboards": "已选择 { count, plural, 1 {# 个仪表盘} other {# 个仪表盘} }", + "home-dashboard": "首页仪表板", + "home-dashboard-hide-toolbar": "隐藏首页仪表板工具栏", + "unassign-dashboard-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", + "unassign-dashboards-from-edge-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", + "unassign-dashboards-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", + "assign-dashboard-to-edge": "将仪表板分配给边缘", + "assign-dashboard-to-edge-text": "请选择要分配给边缘的仪表板", + "non-existent-dashboard-state-error": "仪表盘\"{{ stateId }}\"未找到" + }, + "datakey": { + "settings": "设置", + "advanced": "高级", + "label": "标签", + "color": "颜色", + "units": "单位符号", + "decimals": "小数位数", + "data-generation-func": "数据生成功能", + "use-data-post-processing-func": "使用数据后处理功能", + "configuration": "数据键配置", + "timeseries": "Timeseries", + "attributes": "属性", + "entity-field": "实体字段", + "alarm": "告警字段", + "timeseries-required": "实体 Timeseries 必填。", + "timeseries-or-attributes-required": "实体 Timeseries/属性必填。", + "alarm-fields-timeseries-or-attributes-required": "告警字段或实体 Timeseries/属性必填。", + "maximum-timeseries-or-attributes": "最多允许 { count, plural, 1 {# 个 timeseries/属性。} other {# 个 timeseries/属性。} }", + "alarm-fields-required": "告警字段必填。", + "function-types": "函数类型", + "function-type": "函数类型", + "function-types-required": "需要函数类型。", + "alarm-keys": "报警数据键", + "alarm-key": "报警数据键", + "alarm-key-functions": "报警数据函数", + "alarm-key-function": "报警数据函数", + "latest-keys": "最新数据键", + "latest-key": "最新数据键", + "latest-key-functions": "最新数据函数", + "latest-key-function": "最新数据函数", + "timeseries-keys": "时序数据键", + "timeseries-key": "时序数据键", + "timeseries-key-functions": "时序数据函数", + "timeseries-key-function": "时序数据函数", + "maximum-function-types": "最多允许 { count, plural, 1 {# 个函数类型} other {# 个函数类型} }", + "time-description": "当前值的时间戳;", + "value-description": "当前值;", + "prev-value-description": "上一次函数调用的结果;", + "time-prev-description": "上一个值的时间戳;", + "prev-orig-value-description": "先前的原始值;", + "aggregation": "聚合", + "aggregation-type-hint-common": "出于性能原因聚合值计算仅适用于“当前日期”、“当前月份”等固定时间间隔,而不适用于“最近30分钟”或“最近24小时”等滑动窗口间隔。", + "aggregation-type-none-hint": "取最新值。", + "aggregation-type-min-hint": "在选定时间窗口内的数据点中查找最小值。", + "aggregation-type-max-hint": "在选定时间窗口内的数据点中查找最大值。", + "aggregation-type-avg-hint": "计算选定时间窗口内数据点之间的平均值。", + "aggregation-type-sum-hint": "对选定时间窗口内所有数据点的值求和。", + "aggregation-type-count-hint": "选定时间窗口内的数据点总数。", + "delta-calculation": "增量计算", + "enable-delta-calculation": "启用增量计算", + "enable-delta-calculation-hint": "启用后将根据选定时间窗口和指定比较时段的聚合值计算数据键值。出于性能原因,增量计算仅适用于历史时间窗口,而不适用于实时值。例如,您可以计算昨天的能耗与前天的能耗之间的差值。", + "delta-calculation-result": "增量计算结果", + "delta-calculation-result-previous-value": "上个值", + "delta-calculation-result-delta-absolute": "绝对值", + "delta-calculation-result-delta-percent": "百分比" + }, + "datasource": { + "type": "数据源类型", + "name": "名称", + "label": "标签", + "add-datasource-prompt": "请添加数据源" + }, + "details": { + "details": "详情", + "edit-mode": "编辑模式", + "edit-json": "编辑JSON", + "toggle-edit-mode": "切换编辑模式" + }, + "device": { + "device": "设备", + "device-required": "设备必填", + "devices": "设备", + "management": "设备管理", + "view-devices": "查看设备", + "device-alias": "设备别名", + "device-type-max-length": "设备类型长度必须少于256个字符", + "aliases": "设备别名", + "no-alias-matching": "'{{alias}}' 未找到。", + "no-aliases-found": "未找到别名。", + "no-key-matching": "'{{key}}' 未找到。", + "no-keys-found": "未找到密钥。", + "create-new-alias": "创建一个新的!", + "create-new-key": "创建一个新的!", + "duplicate-alias-error": "找到重复别名 '{{alias}}'。
              设备别名必须是唯一的。", + "configure-alias": "配置 '{{alias}}' 别名", + "no-devices-matching": "未找到与 '{{entity}}' 匹配的设备。", + "alias": "别名", + "alias-required": "设备别名必填。", + "remove-alias": "删除设备别名", + "add-alias": "添加设备别名", + "name-starts-with": "名称前缀", + "help-text": "根据需要可以使用'%'进行匹配,例如:'%device_name_contains%','%device_name_ends','device_starts_with'。", + "device-list": "设备列表", + "use-device-name-filter": "使用筛选器", + "device-list-empty": "没有被选中的设备", + "device-name-filter-required": "设备名称筛选器必填。", + "device-name-filter-no-device-matched": "未找到以'{{device}}' 开头的设备。", + "add": "添加设备", + "assign-to-customer": "分配给客户", + "assign-device-to-customer": "将设备分配给客户", + "assign-device-to-customer-text": "请选择要分配给客户的设备", + "assign-device-to-edge-title": "将设备分配给边缘", + "assign-device-to-edge-text": "请选择要分配给边缘的设备", + "make-public": "公开", + "make-private": "私有", + "no-devices-text": "未找到设备", + "assign-to-customer-text": "请选择客户分配设备", + "device-details": "设备详细信息", + "add-device-text": "添加新设备", + "credentials": "凭据", + "manage-credentials": "管理凭据", + "delete": "删除设备", + "assign-devices": "分配设备", + "assign-devices-text": "将 {count,plural,1 {# 个设备} other {# 个设备} }分配给客户", + "delete-devices": "删除设备", + "unassign-from-customer": "取消分配客户", + "unassign-devices": "取消分配设备", + "unassign-devices-action-title": "取消分配此客户 {count,plural,1 {# 个设备} other {# 个设备} }", + "unassign-device-from-edge-title": "确定要取消分配设备 '{{deviceName}}' 吗?", + "unassign-device-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", + "unassign-devices-from-edge": "取消分配边缘", + "assign-new-device": "分配新设备", + "make-public-device-title": "确定要将设备 '{{deviceName}}' 设为公开吗?", + "make-public-device-text": "确认后,设备及其所有数据将被设为公开并可被其他人访问。", + "make-private-device-title": "确定要将设备 '{{deviceName}}' 设为私有吗?", + "make-private-device-text": "确认后,设备及其所有数据将被设为私有,不被其他人访问。", + "view-credentials": "查看凭据", + "delete-device-title": "确定要删除设备的{{deviceName}}吗?", + "delete-device-text": "请注意:确认后,设备及其所有相关数据将不可恢复。", + "delete-devices-title": "确定要删除{count,plural,1 {# 个设备} other {# 个设备} } 吗?", + "delete-devices-action-title": "删除 {count,plural,1 {# 个设备} other {# 个设备} }", + "delete-devices-text": "请注意:确认后,所有选定的设备将被删除,所有相关数据将不可恢复。", + "unassign-device-title": "确定要取消分配设备 '{{deviceName}}' 吗?", + "unassign-device-text": "确认后,设备将被取消分配,客户将无法访问。", + "unassign-device": "取消分配设备", + "unassign-devices-title": "确定要取消分配 {count,plural,1 {# 个设备} other {# 个设备} } 吗?", + "unassign-devices-text": "确认后,所有选定的设备将被取消分配,并且客户将无法访问。", + "device-credentials": "设备凭据", + "loading-device-credentials": "加载设备凭证...", + "credentials-type": "凭据类型", + "access-token": "访问令牌", + "access-token-required": "访问令牌必填", + "access-token-invalid": "访问令牌长度必须为1到32个字符。", + "certificate-pem-format": "PEM证书格式", + "certificate-pem-format-required": "PEM证书格式必填。", + "lwm2m-security-config": { + "identity": "客户端标识", + "identity-required": "客户端标识必填。", + "identity-tooltip": "PSK标识符是多达128字节的任意PSK标识符,如标准[RFC7925]所述。", + "client-key": "客户端密钥", + "client-key-required": "客户端密钥必填。", + "client-key-tooltip-prk": "RPK公钥必须满足标准[RFC7250]并且Base64编码!", + "client-key-tooltip-psk": "PSK密钥必须是[RFC4279]标准和HexDec格式: 32, 64, 128字符!", + "endpoint": "客户端名称", + "endpoint-required": "客户端名称必填。", + "client-public-key": "客户端公钥", + "client-public-key-hint": "如果客户端公钥为空则使用信任证书", + "client-public-key-tooltip": "X509公钥必须是DER-encoded X509v3格式并支持EC算法编码Base64!", + "mode": "安全配置模式", + "client-tab": "客户端安全配置", + "client-certificate": "客户端证书", + "bootstrap-tab": "Bootstrap Client", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", + "client-publicKey-or-id": "客户端公钥或ID", + "client-publicKey-or-id-required": "客户端公钥或ID必填。", + "client-publicKey-or-id-tooltip-psk": "SK标识符是最多128字节,如标准[RFC7925]所述。", + "client-publicKey-or-id-tooltip-rpk": "RPK必须满足标准[RFC7250]而且编码为 Base64!", + "client-publicKey-or-id-tooltip-x509": "X509公钥必须是X509v3格式而且支持EC算法", + "client-secret-key": "客户端密钥", + "client-secret-key-required": "客户端密钥必填。", + "client-secret-key-tooltip-psk": "PSK键必须是[RFC4279]标准和HexDec格式: 32, 64, 128i字符!", + "client-secret-key-tooltip-prk": "RPK密钥必须是PKCS_8格式(DER编码, 标准[RFC5958]) 并编码为Base64!", + "client-secret-key-tooltip-x509": "X509密钥必须是PKCS_8格式(DER编码, 标准[RFC5958])!" + }, + "client-id": "客户端ID", + "client-id-pattern": "包含无效字符。", + "user-name": "用户名", + "user-name-required": "用户名必填。", + "client-id-or-user-name-necessary": "客户端ID和/或用户名是必需的", + "password": "密码", + "secret": "密钥", + "secret-required": "密钥必填", + "device-type": "设备类型", + "device-type-required": "设备类型必填。", + "select-device-type": "选择设备类型", + "enter-device-type": "输入设备类型", + "any-device": "任意设备", + "no-device-types-matching": "未找到匹配 '{{entitySubtype}}' 的设备类型。", + "device-type-list-empty": "未选择设备类型", + "device-types": "设备类型", + "name": "名称", + "name-required": "名称必填。", + "name-max-length": "名称长度必须少于256个字符", + "label-max-length": "标签长度必须少于256个字符", + "description": "说明", + "label": "标签", + "events": "事件", + "details": "详情", + "copyId": "复制设备ID", + "copyAccessToken": "复制访问令牌", + "copy-mqtt-authentication": "复制MQTT凭据", + "idCopiedMessage": "设备ID已复制到剪贴板", + "accessTokenCopiedMessage": "设备访问令牌已复制到剪贴板", + "mqtt-authentication-copied-message": "设备MQTT身份验证已复制到剪贴板", + "assignedToCustomer": "分配给客户", + "unable-delete-device-alias-title": "无法删除设备别名", + "unable-delete-device-alias-text": "设备别名 '{{deviceAlias}}' 不能够被删除,因为它被下列部件所使用:
              {{widgetsList}}", + "is-gateway": "是否网关", + "overwrite-activity-time": "覆盖已连接设备的活动时间", + "public": "公开", + "device-public": "设备公开", + "select-device": "选择设备", + "import": "导入设备", + "device-file": "设备文件", + "search": "查找设备", + "selected-devices": "已选择 { count, plural, 1 {# 个设备} other {# 个设备} }", + "device-configuration": "设备配置", + "transport-configuration": "传输配置", + "wizard": { + "device-wizard": "设备向导", + "device-details": "设备详细信息", + "new-device-profile": "新建设备配置", + "existing-device-profile": "选择已有设备配置", + "specific-configuration": "指定配置", + "customer-to-assign-device": "客户分配设备", + "add-credentials": "添加凭据" + }, + "unassign-devices-from-edge-title": "确定要取消分配 { count, plural, 1 {1 个设备} other {# 个设备} } 吗?", + "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。" + }, + "asset-profile": { + "asset-profile": "资产配置", + "asset-profiles": "资产配置", + "all-asset-profiles": "全部", + "add": "添加资产配置", + "edit": "编辑资产配置", + "asset-profile-details": "资产配置详情", + "no-asset-profiles-text": "未找到资产配置", + "search": "搜索资产配置", + "selected-asset-profiles": "已选择 { count, plural, 1 {1 个资产配置} other {# 个资产配置} }", + "no-asset-profiles-matching": "未找到与 '{{entity}}' 匹配的资产配置。", + "asset-profile-required": "资产配置必填", + "idCopiedMessage": "资产配置ID已复制到剪贴板", + "set-default": "设为默认资产配置", + "delete": "删除资产配置", + "copyId": "复制资产配置ID", + "name-max-length": "名称长度必须少于256个字符", + "new-device-profile-name": "资产配置名称", + "new-device-profile-name-required": "资产配置名称必填。", + "name": "名称", + "name-required": "名称必填。", + "image": "资产配置图片", + "description": "说明", + "default": "默认", + "default-rule-chain": "默认规则链", + "mobile-dashboard": "移动端仪表板", + "mobile-dashboard-hint": "被移动端应用用作资产详情仪表板", + "select-queue-hint": "从下拉列表中选择。", + "delete-asset-profile-title": "确定要删除 '{{assetProfileName}}' 资产配置吗?", + "delete-asset-profile-text": "请注意:确认后,资产配置和所有相关数据将不可恢复。", + "delete-asset-profiles-title": "确定要删除 { count, plural, 1 {1 个资产配置} other {# 个资产配置} }吗?", + "delete-asset-profiles-text": "请注意:确认后,所有选定的资产配置将被删除,所有相关数据将不可恢复。", + "set-default-asset-profile-title": "确定要将 '{{assetProfileName}}' 设为默认资产配置吗?", + "set-default-asset-profile-text": "确认后,资产配置将被标记为默认,并将用于未指定配置的新资产。", + "no-asset-profiles-found": "未不到资产配置。", + "create-new-asset-profile": "创建一个新的!", + "create-asset-profile": "创建资产配置", + "import": "导入资产配置", + "export": "导出资产配置", + "export-failed-error": "无法导出资产配置: {{error}}", + "asset-profile-file": "资产配置文件", + "invalid-asset-profile-file-error": "无法导入资产配置:无效的资产配置数据结构。" + }, + "device-profile": { + "device-profile": "设备配置", + "device-profiles": "设备配置", + "all-device-profiles": "全部", + "add": "添加设备配置", + "edit": "编辑设备配置", + "device-profile-details": "设备配置详情", + "no-device-profiles-text": "未找到设备配置", + "search": "查找设备配置", + "selected-device-profiles": "已选择 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }", + "no-device-profiles-matching": "未找到与 '{{entity}}' 匹配的设备配置。", + "device-profile-required": "设备配置必填", + "idCopiedMessage": "设备配置 ID 已复制到剪贴板", + "set-default": "设为默认设备配置", + "delete": "删除设备配置", + "copyId": "复制设备配置 ID", + "name-max-length": "名称长度必须少于256个字符", + "new-device-profile-name": "设备配置名称", + "new-device-profile-name-required": "设备配置名称必填。", + "name": "名称", + "name-required": "名称是必需的。", + "type": "配置类型", + "type-required": "配置类型必填。", + "type-default": "默认", + "image": "设备配置图片", + "transport-type": "传输方式", + "transport-type-required": "传输方式必填。", + "transport-type-default": "默认", + "transport-type-default-hint": "支持基本MQTT、HTTP和CoAP传输", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "启用高级MQTT传输设置", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "启用高级 CoAP 传输设置", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "LWM2M传输类型", + "transport-type-snmp": "SNMP", + "transport-type-snmp-hint": "指定 SNMP 传输配置", + "description": "说明", + "default": "默认", + "profile-configuration": "配置", + "transport-configuration": "传输配置", + "default-rule-chain": "默认规则链", + "mobile-dashboard": "移动端仪表板", + "mobile-dashboard-hint": "被移动端应用用作设备详情仪表板", + "select-queue-hint": "从下拉列表中选择或添加自定义名称。", + "delete-device-profile-title": "确定要删除 '{{deviceProfileName}}' 设备配置吗?", + "delete-device-profile-text": "请注意:确认后,设备配置和所有相关数据将不可恢复。", + "delete-device-profiles-title": "确定要删除 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }吗?", + "delete-device-profiles-text": "请注意:确认后,所有选定的设备配置将被删除,所有相关数据将不可恢复。", + "set-default-device-profile-title": "确定要将设备配置 '{{deviceProfileName}}' 设为默认值吗?", + "set-default-device-profile-text": "确认后,设备配置将被标记为默认,并将用于未指定配置的新设备。", + "no-device-profiles-found": "未找到设备配置。", + "create-new-device-profile": "创建一个新的!", + "mqtt-device-topic-filters": "MQTT 设备 Topic 筛选器", + "mqtt-device-topic-filters-unique": "MQTT设备 Topic 筛选器必须唯一。", + "mqtt-device-payload-type": "MQTT 设备 Payload", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-json-payload-format": "启用与其他payload格式兼容。", + "mqtt-enable-compatibility-with-json-payload-format-hint": "启用后平台将默认使用Protobuf的payload格式,如果解析失败平台将尝试使用JSON的payload格式。对于固件更新期间的向后兼容性很有用,例如固件的初始版本使用Json而新版本使用Protobuf在设备队列的固件更新过程中,需要同时支持Protobuf和JSON。兼容模式会导致一点的性能下降,因此建议在所有设备更新后禁用此模式。", + "mqtt-use-json-format-for-default-downlink-topics": "缺省下行主题采用json格式", + "mqtt-use-json-format-for-default-downlink-topics-hint": "启用后平台将使用Json的playload格式通过以下主题推送属性和RPC:v1/devices/me/attributes/response/$request_id、v1/devices/me/attributes 、v1/devices/me/rpc/request/$request_id、v1/devices/me/rpc/response/$request_id。此设置不会影响使用新(v2)主题发送的属性和rpc订阅:v2/a/res/$request_id、v2/a、v2/r /req/$request_id,v2/r/res/$request_id。其中$request_id是一个整数请求标识符。", + "mqtt-send-ack-on-validation-exception": "发布消息验证失败时发送PUBACK", + "mqtt-send-ack-on-validation-exception-hint": "默认情况下平台将关闭相关消息验证失败的MQTT会话,启用后平台将发布确认而不是关闭会话。", + "snmp-add-mapping": "添加SNMP映射", + "snmp-mapping-not-configured": "没有配置时间序列/属性的OID映射", + "snmp-timseries-or-attribute-name": "映射时间序列/属性名称", + "snmp-timseries-or-attribute-type": "映射时间序列/属性名称", + "snmp-method-pdu-type-get-request": "GetRequest", + "snmp-method-pdu-type-get-next-request": "GetNextRequest", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "Payload 类型必填。", + "coap-device-type": "CoAP 设备类型", + "coap-device-payload-type": "CoAP 设备消息 Payload", + "coap-device-type-required": "CoAP 设备类型必填。", + "coap-device-type-default": "默认", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "支持单[+]和多级[#]通配符。", + "telemetry-topic-filter": "遥测数据 topic 筛选器", + "telemetry-topic-filter-required": "遥测数据 topic 筛选器必填。", + "attributes-topic-filter": "Attributes topic filter", + "attributes-topic-filter-required": "Attributes topic 筛选器必填。", + "telemetry-proto-schema": "遥测数据 proto schema", + "telemetry-proto-schema-required": "遥测数据 proto schema 必填。", + "attributes-proto-schema": "Attributes proto schema", + "attributes-proto-schema-required": "Attributes proto schema 必填。", + "rpc-response-proto-schema": "RPC 响应 proto schema", + "rpc-response-proto-schema-required": "RPC 响应 proto schema 必填。", + "rpc-response-topic-filter": "RPC响应 Topic 筛选器", + "rpc-response-topic-filter-required": "RPC响应 Topic 筛选器必填。", + "rpc-request-proto-schema": "RPC 请求 proto schema", + "rpc-request-proto-schema-required": "RPC 请求 proto schema 必填。", + "rpc-request-proto-schema-hint": "RPC 请求消息应始终包含字段:string method = 1; int32 requestId = 2; 和params = 3的任何数据类型。", + "not-valid-pattern-topic-filter": "无效的 Topic 筛选器模式", + "not-valid-single-character": "单级通配符的使用无效", + "not-valid-multi-character": "多级通配符的使用无效", + "single-level-wildcards-hint": "[+] is suitable for any topic filter level。例如:v1/devices/+/telemetry or +/devices/+/attributes。", + "multi-level-wildcards-hint": "[#]可以替换 topic filter 本身,并且必须是 topic 的最后一个符号。例如:# or v1/devices/me/#。", + "alarm-rules": "告警规则", + "alarm-rules-with-count": "告警规则 ({{count}})", + "no-alarm-rules": "未配置告警规则", + "add-alarm-rule": "添加告警规则", + "edit-alarm-rule": "编辑告警规则", + "alarm-type": "告警类型", + "alarm-type-required": "告警类型必填。", + "alarm-type-unique": "警报类型在设备配置警报规则中必须唯一。", + "alarm-type-max-length": "Alarm type should be less than 256", + "create-alarm-pattern": "创建 {{alarmType}} 告警", + "create-alarm-rules": "创建告警规则", + "no-create-alarm-rules": "未配置创建条件", + "add-create-alarm-rule-prompt": "请添加创建告警规则", + "clear-alarm-rule": "清除告警规则", + "no-clear-alarm-rule": "未配置明确条件", + "add-create-alarm-rule": "添加创建条件", + "add-clear-alarm-rule": "添加清除条件", + "select-alarm-severity": "选择告警严重性", + "alarm-severity-required": "告警严重级别必填。", + "condition-duration": "条件持续时间", + "condition-duration-value": "持续时间值", + "condition-duration-time-unit": "时间单位", + "condition-duration-value-range": "持续时间值应在1到2147483647之间。", + "condition-duration-value-pattern": "持续时间值应为整数。", + "condition-duration-value-required": "持续时间值必填。", + "condition-duration-time-unit-required": "时间单位必填。", + "advanced-settings": "高级设置", + "alarm-rule-details": "详情", + "alarm-rule-details-hint": "提示:使用${keyName}警报条件中属性值或报文关键字。", + "add-alarm-rule-details": "详情模板:", + "alarm-rule-mobile-dashboard": "移动仪表盘", + "alarm-rule-mobile-dashboard-hint": "用于警报详细报告", + "alarm-rule-no-mobile-dashboard": "未选择仪表板", + "propagate-alarm": "传递警报", + "alarm-rule-relation-types-list": "要传递的关联类型", + "alarm-rule-relation-types-list-hint": "如果未选择传递关联类型,则将不按关联类型过滤而传递告警。", + "propagate-alarm-to-owner": "向实体所有者(客户或租户)传播警报", + "propagate-alarm-to-tenant": "向租户传播警报", + "alarm-details": "告警详细信息", + "alarm-rule-condition": "告警规则条件", + "enter-alarm-rule-condition-prompt": "请添加告警规则条件", + "edit-alarm-rule-condition": "编辑告警规则条件", + "device-provisioning": "设备预配置", + "provision-strategy": "预配置策略", + "provision-strategy-required": "预配置策略必填。", + "provision-strategy-disabled": "禁用", + "provision-strategy-created-new": "允许创建新设备", + "provision-strategy-check-pre-provisioned": "检查预配置的设备", + "provision-device-key": "预配置设备密钥名", + "provision-device-key-required": "预配置设备密钥名必填。", + "copy-provision-key": "复制预配置密钥名", + "provision-key-copied-message": "预配置密钥名已复制到剪贴板", + "provision-device-secret": "预配置设备密钥", + "provision-device-secret-required": "预配置设备密钥必填。", + "copy-provision-secret": "复制预配置密钥", + "provision-secret-copied-message": "预配置密钥已复制到剪贴板", + "condition": "条件", + "condition-type": "条件类型", + "condition-type-simple": "简单", + "condition-type-duration": "持续时间", + "condition-during": "在 {{during}} 期间", + "condition-during-dynamic": "在\"{{ attribute }}\" ({{during}})", + "condition-type-repeating": "重复", + "condition-type-required": "条件类型必填。", + "condition-repeating-value": "事件计数", + "condition-repeating-value-range": "事件计数应在1到2147483647之间。", + "condition-repeating-value-pattern": "事件计数应为整数。", + "condition-repeating-value-required": "事件计数值必填。", + "condition-repeat-times": "重复 { count, plural, 1 {# 次} other {# 次} }", + "condition-repeat-times-dynamic": "重复\"{ attribute }\" ({ count, plural, 1 {1 时间} other {# 时间} })", + "schedule-type": "计划程序类型", + "schedule-type-required": "计划类型必填。", + "schedule": "启用规则:", + "edit-schedule": "编辑告警日程表", + "schedule-any-time": "始终启用", + "schedule-specific-time": "定时启用", + "schedule-custom": "自定义启用", + "schedule-day": { + "monday": "星期一", + "tuesday": "星期二", + "wednesday": "星期三", + "thursday": "星期四", + "friday": "星期五", + "saturday": "星期六", + "sunday": "星期日" + }, + "schedule-days": "天", + "schedule-time": "时间", + "schedule-time-from": "从", + "schedule-time-to": "到", + "schedule-days-of-week-required": "每周至少选择一天。", + "create-device-profile": "创建设备配置", + "import": "导入设备配置", + "export": "导出设备配置", + "export-failed-error": "无法导出设备配置文件: {{error}}", + "device-profile-file": "设备配置文件", + "invalid-device-profile-file-error": "无法导入设备配置:无效的设备配置数据结构。", + "power-saving-mode": "节能模式", + "power-saving-mode-type": { + "default": "使用设备配置的节能模式", + "psm": "节能模式(PSM)", + "drx": "非连续接收(DRX)", + "edrx": "连续接收(eDRX)" + }, + "edrx-cycle": "eDRX循环", + "edrx-cycle-required": "eDRX循环必填。", + "edrx-cycle-pattern": "eDRX循环必须是一个正整数。", + "edrx-cycle-min": "eDRX循环的最小值{{ min }}秒。", + "paging-transmission-window": "分页传输窗口", + "paging-transmission-window-required": "分页传输窗口必填。", + "paging-transmission-window-pattern": "分页传输窗口必须是正整数。", + "paging-transmission-window-min": "分页传输窗口的最小值{{ min }}秒。", + "psm-activity-timer": "PSM活动计时器", + "psm-activity-timer-required": "PSM活动计时器必填。", + "psm-activity-timer-pattern": "PSM活动计时器必须是正整数", + "psm-activity-timer-min": "PSM活动计时器的最小数量为{{ min }}秒。", + "lwm2m": { + "object-list": "Object列表", + "object-list-empty": "没有选择边object。", + "no-objects-found": "没有选择边object。", + "no-objects-matching": "没有找到匹配的object'{{object}}'。", + "model-tab": "LWM2M模式", + "add-new-instances": "添加新实例", + "instances-list": "实例列表", + "instances-list-required": "实例列表必填。", + "instance-id-pattern": "实例id必须是一个正整数。", + "instance-id-max": "实例id最大值是{{max}}", + "instance": "实例", + "resource-label": "#I资源D名称", + "observe-label": "观察者", + "attribute-label": "属性", + "telemetry-label": "遥测", + "edit-observe-select": "选择观察者编辑遥测或属性", + "edit-attributes-select": "选择要编辑的遥测或属性", + "no-attributes-set": "没有设置属性", + "key-name": "键名", + "key-name-required": "键名必填", + "attribute-name": "属性名称", + "attribute-name-required": "属性名称必填。", + "attribute-value": "属性值", + "attribute-value-required": "属性值必填。", + "attribute-value-pattern": "属性值必须是一个正整数。", + "edit-attributes": "编辑属性:{{ name }}", + "view-attributes": "查看属性:{{ name }}", + "add-attribute": "添加属性", + "edit-attribute": "编辑属性", + "view-attribute": "查看属性", + "remove-attribute": "移除属性", + "delete-server-text": "请注意确认删除后服务器配置将无法恢复。", + "delete-server-title": "你确定要删除服务器吗?", + "mode": "安全配置模式", + "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Bootstrap Server (ShortId...)", + "lwm2m-server-legend": "LwM2M Server (ShortId...)", + "server": "服务器", + "short-id": "服务器ID", + "short-id-tooltip": "服务器ID用作关联服务器对象实例的链接。", + "short-id-required": "服务器ID必填。", + "short-id-range": "服务器ID应在1到65534范围内。", + "short-id-pattern": "服务器ID必须是一个正整数。", + "lifetime": "客户端注册生命周期", + "lifetime-required": "客户端注册生命周期必填。", + "lifetime-pattern": "客户端注册生命周期必须是一个正整数。", + "default-min-period": "最小期限", + "default-min-period-tooltip": "LWM2M客户端在观察中不包含此参数时使用的默认值。", + "default-min-period-required": "最小期限必填。", + "default-min-period-pattern": "最小期限必须是一个正整数。", + "notification-storing": "禁用或离线时通知存储", + "binding": "绑定", + "binding-type": { + "u": "U: 客户端通过UDP绑定。", + "m": "M: 客户端通过MQTT绑定。", + "h": "H: 客户端通过HTTP绑定。", + "t": "T: 客户端通过TCP绑定。", + "s": "S: 客户端通过SMS绑定。", + "n": "N: 客户端通过非IP绑定将响应发送到请求(支持LWM2M 1.1)。", + "uq": "UQ: 通过UDP队列模式连接(不支持LWM2M 1.1)。", + "uqs": "UQS: 通过UDP和SMS活动连接(不支持LWM2M 1.1)。", + "tq": "TQ: 通过TCP队列模式连接(不支持LWM2M 1.1)。", + "tqs": "TQS: 通过TCP和SMS活动连接(不支持LWM2M 1.1)。", + "sq": "SQ: 通过队列模式的SMS连接(不支持LWM2M 1.1)。" + }, + "binding-tooltip": "这是LwM2M服务器对象的\"绑定\"资源列表 - /1/x/7。\n表示LwM2M客户端中支持的绑定模式。\n此值应与设备对象(/3/0/16)中的\"支持的绑定和模式\"资源。\n虽然支持多个传输但在整个传输会话期间只能使用一个传输绑定。\n 例如:当UDP和SMS都受支持,LwM2M客户端和LwM2M服务器可以选择在整个传输会话期间通过UDP或SMS进行通信。", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", + "include-bootstrap-server": "包含Bootstrap Server更新", + "bootstrap-update-title": "你已经配置了Bootstrap Server,您确定要排除更新吗?", + "bootstrap-update-text": "请注意确认更新后Bootstrap Server配置数据将无法恢复。", + "server-host": "主机", + "server-host-required": "主机必填。", + "server-port": "端口", + "server-port-required": "端口必填。", + "server-port-pattern": "端口必须是一个正整数。", + "server-port-range": "端口应在1到65535范围内。", + "server-public-key": "服务器公钥", + "server-public-key-required": "服务器公钥必填。", + "client-hold-off-time": "停留时间", + "client-hold-off-time-required": "停留时间必填。", + "client-hold-off-time-pattern": "停留时间必须是一个正整数。", + "client-hold-off-time-tooltip": "客户端仅与Bootstrap-Server共用停留时间", + "account-after-timeout": "帐户超时", + "account-after-timeout-required": "帐户超时必填。", + "account-after-timeout-pattern": "帐户超时必须是一个正整数。", + "account-after-timeout-tooltip": "Bootstrap-Server帐户资源的超时值。", + "server-type": "Server type", + "add-new-server-title": "添加新的服务器配置", + "add-server-config": "添加服务器配置", + "add-lwm2m-server-config": "添加LwM2M服务器", + "no-config-servers": "没有服务器配置", + "others-tab": "其它设置", + "client-strategy": "客户端连接策略", + "client-strategy-label": "策略", + "client-strategy-only-observe": "只在初始连接后观察对客户的请求", + "client-strategy-read-all": "注册后阅读所有资源并观察对客户的请求", + "fw-update": "固件升级", + "fw-update-strategy": "固件升级策略", + "fw-update-strategy-data": "发布固件升级二制文件使用Object 19和Resource 0数据。", + "fw-update-strategy-package": "发布固件升级二制文件使用Object 5和Resource 0包", + "fw-update-strategy-package-uri": "自动生成唯一的CoAP地址下载包和发布软件更新作为Object 5和Resource 1(软件包URI)。", + "sw-update": "软件更新", + "sw-update-strategy": "软件更新策略", + "sw-update-strategy-package": "发布二制文件使用Object 9和Resource 2(包)", + "sw-update-strategy-package-uri": "自动生成唯一的CoAP地址下载包和发布软件更新作为Object 9和Resource 3(软件包URI)。", + "fw-update-resource": "固件更新COAP资源", + "fw-update-resource-required": "固件更新COAP资源必填。", + "sw-update-resource": "软件更新COAP资源", + "sw-update-resource-required": "软件更新COAP资源必填。", + "config-json-tab": "设备配置JSON", + "attributes-name": { + "min-period": "最小期限", + "max-period": "最大期限", + "greater-than": "大于", + "less-than": "少于", + "step": "停止", + "min-evaluation-period": "最小期限评估", + "max-evaluation-period": "最大期限评估" + }, + "composite-operations-support": "支持Read/Write/Observe操作" + }, + "snmp": { + "add-communication-config": "添加通信配置", + "add-mapping": "添加映射", + "authentication-passphrase": "身份验证密码", + "authentication-passphrase-required": "身份验证密码必填。", + "authentication-protocol": "身份验证协议", + "authentication-protocol-required": "身份验证协议必填。", + "communication-configs": "通信配置", + "community": "Community字符串", + "community-required": "Community字符串必填。", + "context-name": "上下文名称", + "data-key": "数据键", + "data-key-required": "数据键必填。", + "data-type": "数据类型", + "data-type-required": "数据类型必填。", + "engine-id": "引擎ID", + "host": "主机", + "host-required": "主机必填。", + "oid": "OID", + "oid-pattern": "无效OID格式", + "oid-required": "OID必填。", + "please-add-communication-config": "请添加通信配置", + "please-add-mapping-config": "请添加映射配置", + "port": "端口", + "port-format": "端口格式无效", + "port-required": "端口必填。", + "privacy-passphrase": "私有密码", + "privacy-passphrase-required": "私有密码必填。", + "privacy-protocol": "私有协议", + "privacy-protocol-required": "私有协议必填。", + "protocol-version": "协议版本", + "protocol-version-required": "协议版本必填。", + "querying-frequency": "查询频率(ms)", + "querying-frequency-invalid-format": "查询频率必须是一个正整数。", + "querying-frequency-required": "查询频率必填。", + "retries": "重试", + "retries-invalid-format": "重试必须是一个正整数。", + "retries-required": "重试必填。", + "scope": "范围", + "scope-required": "范围必填。", + "security-name": "Security名称", + "security-name-required": "Security名称必填。", + "timeout-ms": "超时(ms)", + "timeout-ms-invalid-format": "超时必须是一个正整数。", + "timeout-ms-required": "超时必填。", + "user-name": "用户名", + "user-name-required": "用户名必填。" + } + }, + "dialog": { + "close": "关闭对话框" + }, + "direction": { + "column": "列", + "row": "排" + }, + "edge": { + "edge": "边缘", + "edge-instances": "边缘实例", + "edge-file": "边缘文件", + "name-max-length": "名称长度必须少于256个字符", + "label-max-length": "标签长度必须少于256个字符", + "type-max-length": "类型长度必须少于256个字符", + "management": "边缘管理", + "no-edges-matching": "未找到匹配的边缘 '{{entity}}'。", + "add": "增加边缘", + "no-edges-text": "未找到边缘", + "edge-details": "边缘详情", + "add-edge-text": "增加新的边缘", + "delete": "删除边缘", + "delete-edge-title": "确定删除边缘 '{{edgeName}}'吗?", + "delete-edge-text": "当心, 确认后,边缘以及所有关联数据将不可恢复。", + "delete-edges-title": "确定删除 { count, plural, 1 {1 个边缘} other {# 个边缘} }吗?", + "delete-edges-text": "当心, 确认后,选定的边缘以及所有关联数据将不可恢复。", + "name": "名称", + "name-starts-with": "边缘名称前缀", + "name-required": "名称必填。", + "description": "说明", + "details": "详情", + "events": "事件", + "copy-id": "复制边缘编号", + "id-copied-message": "边缘编号已经复制到剪切板", + "sync": "同步边缘", + "edge-required": "边缘必填。", + "edge-type": "边缘类型", + "edge-type-required": "边缘类型必填。", + "event-action": "事件行动", + "entity-id": "实体编号", + "select-edge-type": "选择边缘类型", + "assign-to-customer": "分配给客户", + "assign-to-customer-text": "请选择需要分配给边缘的客户", + "assign-edge-to-customer": "分配边缘给客户", + "assign-edge-to-customer-text": "请选择需要分配给边缘的客户", + "assignedToCustomer": "分配给客户", + "edge-public": "边缘公开", + "assigned-to-customer": "分配给: {{customerTitle}}", + "unassign-from-customer": "取消分配客户", + "unassign-edge-title": "确定取消分配边缘 '{{edgeName}}' 吗?", + "unassign-edge-text": "确定后,边缘将被取消分配,并且客户将无法访问。", + "unassign-edges-title": "确定要取消分配 {count,plural,1 {1 个边缘} other {# 个边缘} } 吗?", + "unassign-edges-text": "确定后,所有选定的边缘将被取消分配,并且客户将无法访问。", + "make-public": "公开", + "make-public-edge-title": "确定要将边缘 '{{edgeName}}' 设为公开吗?", + "make-public-edge-text": "确认后,边缘及其所有数据将被设为公开并可被其他人访问。", + "make-private": "私有", + "public": "公开", + "make-private-edge-title": "确定要将边缘 '{{edgeName}}' 设为私有吗?", + "make-private-edge-text": "确认后,边缘及其所有数据将被设为私有,不被其他人访问。", + "import": "导入边缘", + "label": "标签", + "load-entity-error": "加载数据失败,实体已经被删除。", + "assign-new-edge": "分配新边缘", + "unassign-from-edge": "取消分配边缘", + "edge-key": "边缘键", + "copy-edge-key": "复制边缘键", + "edge-key-copied-message": "边缘键已经被复制到剪切板", + "edge-secret": "边缘密钥", + "copy-edge-secret": "复制边缘密钥", + "edge-secret-copied-message": "边缘密钥已经被复制到剪切板", + "edge-assets": "边缘资产", + "edge-devices": "边缘设备", + "edge-entity-views": "边缘实体视图", + "edge-dashboards": "边缘仪表板", + "edge-rulechains": "边缘规则链", + "assets": "边缘资产", + "devices": "边缘设备", + "entity-views": "边缘实体视图", + "dashboard": "边缘仪表板", + "dashboards": "边缘仪表板", + "rulechain-templates": "规则链模版", + "rulechains": "规则链", + "search": "搜索边缘", + "selected-edges": "{ count, plural, 1 {1 个边缘} other {# 个边缘} } 被选中", + "any-edge": "任何边缘", + "no-edge-types-matching": "未找到匹配的边缘类型 '{{entitySubtype}}'。", + "edge-type-list-empty": "没有选择边缘类型。", + "edge-types": "边缘类型", + "enter-edge-type": "输入边缘类型", + "deployed": "已部署", + "pending": "待定", + "downlinks": "下行", + "no-downlinks-prompt": "未找到下行", + "sync-process-started-successfully": "同步处理开始成功!", + "missing-related-rule-chains-title": "边缘缺少关联规则链", + "missing-related-rule-chains-text": "分配给边缘的规则链使用规则节点将消息转发给未分配给当前边缘的规则链。

              缺少的规则链列表:
              {{missingRuleChains}}", + "widget-datasource-error": "组件只支持边缘实体数据源" + }, + "edge-event": { + "type-dashboard": "仪表板", + "type-asset": "资产", + "type-device": "设备", + "type-device-profile": "设备概要", + "type-asset-profile": "Asset Profile", + "type-entity-view": "实体视图", + "type-alarm": "告警", + "type-rule-chain": "规则链", + "type-rule-chain-metadata": "规则链元数据", + "type-edge": "边缘", + "type-user": "用户", + "type-customer": "客户", + "type-relation": "关联", + "type-widgets-bundle": "部件包", + "type-widgets-type": "部件类型", + "type-admin-settings": "管理员设置", + "action-type-added": "增加", + "action-type-deleted": "删除", + "action-type-updated": "更新", + "action-type-post-attributes": "推送属性", + "action-type-attributes-updated": "属性更新", + "action-type-attributes-deleted": "属性删除", + "action-type-timeseries-updated": "时序更新", + "action-type-credentials-updated": "认证更新", + "action-type-assigned-to-customer": "分配给客户", + "action-type-unassigned-from-customer": "取消分配客户", + "action-type-relation-add-or-update": "关联增加或更新", + "action-type-relation-deleted": "关联删除", + "action-type-rpc-call": "RPC调用", + "action-type-alarm-ack": "告警确认", + "action-type-alarm-clear": "告警清除", + "action-type-assigned-to-edge": "分配给边缘", + "action-type-unassigned-from-edge": "取消分配边缘", + "action-type-credentials-request": "认证请求", + "action-type-entity-merge-request": "实体合并请求" + }, + "error": { + "unable-to-connect": "无法连接到服务器!请检查您的互联网连接。", + "unhandled-error-code": "未处理的错误代码: {{errorCode}}", + "unknown-error": "未知错误" + }, + "entity": { + "entity": "实体", + "entities": "实体", + "entities-count": "实体数量", + "aliases": "实体别名", + "entity-alias": "实体别名", + "unable-delete-entity-alias-title": "无法删除实体别名", + "unable-delete-entity-alias-text": "实体别名 '{{entityAlias}}' 被以下部件使用不能删除:
              {{widgetsList}}", + "duplicate-alias-error": "别名 '{{alias}}' 重复。
              同一仪表板别名必须唯一。", + "missing-entity-filter-error": "别名 '{{alias}}' 缺少筛选器", + "configure-alias": "别名 '{{alias}}' 配置", + "alias": "别名", + "alias-required": "实体别名必填。", + "remove-alias": "移除实体别名", + "add-alias": "添加实体别名", + "entity-list": "实体列表", + "entity-type": "实体类型", + "entity-types": "实体类型", + "entity-type-list": "实体类型列表", + "any-entity": "任意实体", + "enter-entity-type": "输入实体类型", + "no-entities-matching": "未找到匹配 '{{entity}}' 的实体。", + "no-entity-types-matching": "未找到匹配 '{{entityType}}' 类型的实体。", + "name-starts-with": "名称开始于", + "help-text": "根据需要可以使用'%'进行匹配,例如:'%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'。", + "use-entity-name-filter": "用户筛选器", + "entity-list-empty": "没有选择实体。", + "entity-type-list-empty": "没有选择实体类型。", + "entity-name-filter-required": "实体名筛选器必填。", + "entity-name-filter-no-entity-matched": "未找到以 '{{entity}}' 开头的实体", + "all-subtypes": "全部", + "select-entities": "选择实体", + "no-aliases-found": "未找到别名", + "no-alias-matching": "未找到 '{{alias}}'", + "create-new-alias": "创建一个新的!", + "key": "键名", + "key-name": "键名", + "no-keys-found": "未找到键名", + "no-key-matching": "未找到键名 '{{key}}'", + "create-new-key": "创建一个新的!", + "type": "类型", + "type-required": "实体类型必填。", + "type-device": "设备", + "type-devices": "设备", + "list-of-devices": "{ count, plural, 1 {1 个设备} other {# 个设备} }", + "device-name-starts-with": "以 '{{prefix}}' 开头的设备", + "type-device-profile": "设备配置", + "type-device-profiles": "设备配置", + "list-of-device-profiles": "{ count, plural, 1 {1 个设备配置} other {# 个设备配置} }", + "device-profile-name-starts-with": "名称以 '{{prefix}}' 开头的设备配置", + "type-asset-profile": "资产配置", + "type-asset-profiles": "资产配置", + "list-of-asset-profiles": "{ count, plural, 1 {One asset profile} other {List of # asset profiles} }", + "asset-profile-name-starts-with": "Asset profiles whose names start with '{{prefix}}'", + "type-asset": "资产", + "type-assets": "资产", + "list-of-assets": "{ count, plural, 1 {1 个资产} other {# 个资产} }", + "asset-name-starts-with": "以 '{{prefix}}' 开头的资产", + "type-entity-view": "实体视图", + "type-entity-views": "实体视图", + "list-of-entity-views": "{ count, plural, 1 {1 个实体视图} other {# 个实体视图} }", + "entity-view-name-starts-with": "以 '{{prefix}}' 开头的实体视图", + "type-rule": "规则", + "type-rules": "规则", + "list-of-rules": "{ count, plural, 1 {1 个规则} other {# 个规则} }", + "rule-name-starts-with": "以 '{{prefix}}' 开头的规则", + "type-plugin": "插件", + "type-plugins": "插件", + "list-of-plugins": "{ count, plural, 1 {1 个插件} other {# 个插件} }", + "plugin-name-starts-with": "以 '{{prefix}}' 开头的插件", + "type-tenant": "租户", + "type-tenants": "租户", + "list-of-tenants": "{ count, plural, 1 {1 个租户} other {# 个租户} }", + "tenant-name-starts-with": "以 '{{prefix}}' 开头的租户", + "type-tenant-profile": "租户简介", + "type-tenant-profiles": "租户配置", + "list-of-tenant-profiles": "{ count, plural, 1 {1 个租户配置} other {# 个租户配置} }", + "tenant-profile-name-starts-with": "名称以 '{{prefix}}' 开头的租户配置", + "type-customer": "客户", + "type-customers": "客户", + "list-of-customers": "{ count, plural, 1 {1 个客户} other {# 个客户} }", + "customer-name-starts-with": "以 '{{prefix}}' 开头的客户", + "type-user": "用户", + "type-users": "用户", + "list-of-users": "{ count, plural, 1 {1 个用户} other {# 个用户} }", + "user-name-starts-with": "以 '{{prefix}}' 开头的用户", + "type-dashboard": "仪表板", + "type-dashboards": "仪表板", + "list-of-dashboards": "{ count, plural, 1 {1 个仪表板} other {# 个仪表板} }", + "dashboard-name-starts-with": "以 '{{prefix}}' 开头的仪表板", + "type-alarm": "告警", + "type-alarms": "告警", + "list-of-alarms": "{ count, plural, 1 {1 个告警} other {# 个告警} }", + "alarm-name-starts-with": "以 '{{prefix}}' 开头的告警", + "type-rulechain": "规则链", + "type-rulechains": "规则链库", + "list-of-rulechains": "{ count, plural, 1 {1 个规则链} other {# 个规则链} }", + "rulechain-name-starts-with": "规则链前缀名称 '{{prefix}}'", + "type-rulenode": "规则节点", + "type-rulenodes": "规则节点", + "list-of-rulenodes": "{ count, plural, 1 {1 个规则节点} other {# 个规则节点} }", + "rulenode-name-starts-with": "名称以 '{{prefix}}' 开头的规则节点", + "type-current-customer": "当前客户", + "type-current-tenant": "当前租户", + "type-current-user": "当前用户", + "type-current-user-owner": "当前用户所有者", + "type-widgets-bundle": "Widgets bundle", + "type-widgets-bundles": "Widgets bundles", + "list-of-widgets-bundles": "{ count, plural, 1 {1 个部件包} other {列表 # 部件包} }", + "search": "实体检索", + "selected-entities": "已选择 { count, plural, 1 {# 个实体} other {# 个实体} }", + "entity-name": "实体名", + "entity-label": "实体标签", + "details": "实体详情", + "no-entities-prompt": "未找到实体", + "no-data": "无数据", + "columns-to-display": "要显示的列", + "type-api-usage-state": "Api使用状态", + "type-edge": "边缘", + "type-edges": "边缘", + "list-of-edges": "{ count, plural, 1 {1 个边缘} other {列表 # 个边缘} }", + "edge-name-starts-with": "以 '{{prefix}}' 开头的边缘", + "type-tb-resource": "资源", + "type-ota-package": "OTA包" + }, + "entity-field": { + "created-time": "创建时间", + "name": "名称", + "type": "类型", + "first-name": "名字", + "last-name": "姓氏", + "email": "电子邮件", + "title": "标题", + "country": "国家", + "state": "省/州", + "city": "城市", + "address": "地址", + "address2": "地址二", + "zip": "邮政编码", + "phone": "电话", + "label": "标签" + }, + "entity-view": { + "entity-view": "实体视图", + "entity-view-required": "实体视图必填。", + "entity-views": "实体视图", + "management": "实体视图管理", + "view-entity-views": "查看实体视图", + "entity-view-alias": "实体视图别名", + "aliases": "实体视图别名", + "no-alias-matching": "未找到匹配 '{{alias}}' 的别名。", + "no-aliases-found": "未找到别名。", + "no-key-matching": "'{{key}}' 未找到。", + "no-keys-found": "未找到密钥。", + "create-new-alias": "创建一个新的!", + "create-new-key": "创建一个新的!", + "duplicate-alias-error": "找到重复别名 '{{alias}}'。
              实体视图别名必须是唯一的。", + "configure-alias": "配置 '{{alias}}' 别名", + "no-entity-views-matching": "未找到与 '{{entity}}' 匹配的实体视图。", + "public": "公开", + "alias": "别名", + "alias-required": "实体视图别名必填。", + "remove-alias": "删除实体视图别名", + "add-alias": "添加实体视图别名", + "name-starts-with": "名称前缀", + "help-text": "根据需要可以使用'%'进行匹配,例如:'%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'。", + "entity-view-list": "实体视图列表", + "use-entity-view-name-filter": "使用筛选器", + "entity-view-list-empty": "没有被选中的实体视图", + "entity-view-name-filter-required": "实体视图名称筛选器必填。", + "entity-view-name-filter-no-entity-view-matched": "未找到以'{{entityView}}' 开头的实体视图。", + "add": "添加实体视图", + "entity-view-public": "实体视图是公共的", + "assign-to-customer": "分配给客户", + "assign-entity-view-to-customer": "将实体视图分配给客户", + "assign-entity-view-to-customer-text": "请选择要分配给客户的实体视图", + "assign-entity-view-to-edge-title": "将实体视图分配给边缘", + "no-entity-views-text": "未找到实体视图", + "assign-to-customer-text": "请选择客户分配实体视图", + "entity-view-details": "实体视图详细信息", + "add-entity-view-text": "添加新实体视图", + "delete": "删除实体视图", + "assign-entity-views": "分配实体视图", + "assign-entity-views-text": "分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 给客户", + "delete-entity-views": "删除实体视图", + "unassign-from-customer": "取消分配客户", + "unassign-entity-views": "取消分配实体视图", + "unassign-entity-views-action-title": "从客户处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", + "assign-new-entity-view": "分配新实体视图", + "delete-entity-view-title": "确定要删除实体视图 '{{entityViewName}}'吗?", + "delete-entity-view-text": "请注意:确认后实体视图及其所有相关数据将不可恢复。", + "delete-entity-views-title": "确定要删除 { count, plural, 1 {# 实体视图} other {# 实体视图} }吗?", + "delete-entity-views-action-title": "删除 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", + "delete-entity-views-text": "请注意:确认后,所有选定的实体视图将被删除,所有相关的数据将不可恢复。", + "unassign-entity-view-title": "确定要取消对 '{{entityViewName}}' 实体视图的分配吗?", + "unassign-entity-view-text": "确认后,实体视图将未分配,客户无法访问。", + "unassign-entity-view": "未分配实体视图", + "unassign-entity-views-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 吗?", + "unassign-entity-views-text": "确认后,所有选定的实体视图将被分配,客户无法访问。", + "entity-view-type": "实体视图类型", + "entity-view-type-required": "实体视图类型必填。", + "select-entity-view-type": "选择实体视图类型", + "enter-entity-view-type": "输入实体视图类型", + "any-entity-view": "任何实体视图", + "no-entity-view-types-matching": "未找到匹配 '{{entitySubtype}}' 的实体视图类型。", + "entity-view-type-list-empty": "实体视图类型未选择。", + "entity-view-types": "实体视图类型", + "created-time": "创建时间", + "name": "名称", + "name-required": "名称必填。", + "name-max-length": "名称长度必须少于256个字符", + "type-max-length": "视图类型长度必须少于256个字符", + "description": "说明", + "events": "事件", + "details": "详情", + "copyId": "复制实体视图ID", + "idCopiedMessage": "实体视图ID已复制到剪贴板", + "assignedToCustomer": "分配给客户", + "unable-entity-view-device-alias-title": "无法删除实体视图别名", + "unable-entity-view-device-alias-text": "实体视图别名 '{{entityViewAlias}}' 不能够被删除,因为它被下列部件所使用:
              {{widgetsList}}", + "select-entity-view": "选择实体视图", + "make-public": "实体视图设为公开", + "make-private": "实体视图设为私有", + "start-date": "开始日期", + "start-ts": "开始时间", + "end-date": "结束日期", + "end-ts": "结束时间", + "date-limits": "日期限制", + "client-attributes": "客户端属性", + "shared-attributes": "共享属性", + "server-attributes": "服务端属性", + "timeseries": "时间序列", + "client-attributes-placeholder": "客户端属性", + "shared-attributes-placeholder": "共享属性", + "server-attributes-placeholder": "服务端属性", + "timeseries-placeholder": "时间序列", + "target-entity": "目标实体", + "attributes-propagation": "属性传播", + "attributes-propagation-hint": "每次保存或更新这个实体视图时将自动从目标实体复制指定的属性。由于性能原因目标实体属性不会在每次属性更改时传递到实体视图。你可以通过配置\"copy to view\"规则链中的规则节点,并将\"Post attributes\"和\"attributes Updated\"消息链接到新规则节点,从而启用自动传递。", + "timeseries-data": "时间序列数据", + "timeseries-data-hint": "配置目标实体的 Timeseries 数据键,以便实体视图可以访问这些键。此 Timeseries 数据是只读的。", + "search": "查找实体视图", + "selected-entity-views": "已选择 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", + "make-public-entity-view-title": "确定要将实体视图 '{{entityViewName}}' 设为公开吗?", + "make-public-entity-view-text": "确认后,实体视图及其所有数据将被公开并被他人访问。", + "make-private-entity-view-title": "确定要将实体视图 '{{entityViewName}}' 设为私有吗?", + "make-private-entity-view-text": "确认后,实体视图及其所有数据将被私有化,无法被他人访问。", + "assign-entity-view-to-edge": "将实体视图分配给边缘", + "assign-entity-view-to-edge-text": "请选择要分配给边缘的实体视图", + "unassign-entity-view-from-edge-title": "确定要取消对 '{{entityViewName}}' 实体视图的分配吗?", + "unassign-entity-view-from-edge-text": "确认后,实体视图将未分配,边缘无法访问。", + "unassign-entity-views-from-edge-action-title": "从边缘处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", + "unassign-entity-view-from-edge": "未分配实体视图", + "unassign-entity-views-from-edge-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 吗?", + "unassign-entity-views-from-edge-text": "确认后,所有选定的实体视图将被分配,边缘无法访问。" + }, + "event": { + "event-type": "事件类型", + "events-filter": "事件筛选器", + "clean-events": "Clear Events", + "type-error": "错误", + "type-lc-event": "生命周期事件", + "type-stats": "类型统计", + "type-debug-rule-node": "调试", + "type-debug-rule-chain": "调试", + "no-events-prompt": "未找到事件", + "error": "错误", + "alarm": "告警", + "event-time": "事件时间", + "server": "服务器", + "body": "整体", + "method": "方法", + "type": "类型", + "message": "Message", + "message-id": "消息ID", + "copy-message-id": "Copy message Id", + "message-type": "消息类型", + "data-type": "数据类型", + "relation-type": "关联类型", + "metadata": "元数据", + "data": "数据", + "event": "事件", + "status": "状态", + "success": "成功", + "failed": "失败", + "messages-processed": "消息处理", + "max-messages-processed": "最多处理消息", + "min-messages-processed": "最少处理消息", + "errors-occurred": "错误发生", + "max-errors-occurred": "最多错误", + "min-errors-occurred": "最少错误", + "min-value": "最小值是0。", + "all-events": "全部", + "has-error": "有错误", + "entity-id": "实体ID", + "copy-entity-id": "复制实体ID", + "entity-type": "实体类型", + "clear-filter": "清除过滤器", + "clear-request-title": "清除所有事件", + "clear-request-text": "确除清空所有事件?" + }, + "extension": { + "extensions": "扩展", + "selected-extensions": "已选择 { count, plural, 1 {# 个扩展} other {# 个扩展} }", + "type": "类型", + "key": "键名", + "value": "价值", + "id": "ID", + "extension-id": "扩展ID", + "extension-type": "扩展类型", + "transformer-json": "JSON *", + "unique-id-required": "当前扩展ID已经存在。", + "delete": "删除扩展", + "add": "添加扩展", + "edit": "编辑扩展", + "delete-extension-title": "确定要删除扩展 '{{extensionId}}'吗?", + "delete-extension-text": "请注意:确认后,扩展和所有相关数据将不可恢复。", + "delete-extensions-title": "确定要删除 { count, plural, 1 {# 个扩展} other {# 个扩展} }吗?", + "delete-extensions-text": "请注意:确认后,所有选定的扩展将被删除,所有相关数据将不可恢复。", + "converters": "转换器", + "converter-id": "转换器序号", + "configuration": "配置", + "converter-configurations": "转换器的配置", + "token": "安全令牌", + "add-converter": "添加转换器", + "add-config": "添加转换器配置", + "device-name-expression": "设备名称表达式", + "device-type-expression": "设备类型表达式", + "custom": "定制", + "to-double": "加倍", + "transformer": "转换器", + "json-required": "Transformer JSON 必填。", + "json-parse": "无法解析转换器JSON。", + "attributes": "属性", + "add-attribute": "添加属性", + "add-map": "添加映射元素", + "timeseries": "Timeseries", + "add-timeseries": "添加 Timeseries", + "field-required": "必填字段", + "brokers": "代理服务器组", + "add-broker": "添加代理服务器", + "host": "主机", + "port": "端口", + "port-range": "端口应该在1到65535的范围内。", + "ssl": "SSL", + "credentials": "证书", + "username": "用户名", + "password": "密码", + "retry-interval": "重试间隔(毫秒)", + "anonymous": "匿名", + "basic": "Basic", + "pem": "PEM", + "ca-cert": "CA certificate file *", + "private-key": "Private key file *", + "cert": "Certificate file *", + "no-file": "没有选择文件。", + "drop-file": "删除文件或单击以选择要上载的文件。", + "mapping": "映射", + "topic-filter": "Topic筛选器", + "converter-type": "转换类型", + "converter-json": "Json", + "json-name-expression": "设备名称JSON表达式", + "topic-name-expression": "设备名称主题表达式", + "json-type-expression": "设备类型JSON表达式", + "topic-type-expression": "设备类型主题表达式", + "attribute-key-expression": "属性键名表达式", + "attr-json-key-expression": "属性键JSON表达式", + "attr-topic-key-expression": "属性键名Topic表达式", + "request-id-expression": "请求ID表达式", + "request-id-json-expression": "请求ID JSON表达式", + "request-id-topic-expression": "请求ID主题表达式", + "response-topic-expression": "响应主题表达式", + "value-expression": "值表达式", + "topic": "主题", + "timeout": "超时时间(毫秒)", + "converter-json-required": "Converter JSON 必填。", + "converter-json-parse": "无法解析转换JSON。", + "filter-expression": "筛选条件表达式", + "connect-requests": "连接请求", + "add-connect-request": "添加连接请求", + "disconnect-requests": "断开请求", + "add-disconnect-request": "添加断开请求", + "attribute-requests": "属性请求", + "add-attribute-request": "添加属性请求", + "attribute-updates": "属性更新", + "add-attribute-update": "添加属性更新", + "server-side-rpc": "服务端RPC", + "add-server-side-rpc-request": "添加服务端RPC请求", + "device-name-filter": "设备名称筛选器", + "attribute-filter": "属性筛选器", + "method-filter": "方法筛选器", + "request-topic-expression": "请求主题表达式", + "response-timeout": "响应超时(毫秒)", + "topic-expression": "主题表达", + "client-scope": "客户范围", + "add-device": "添加服务器", + "opc-server": "服务器组", + "opc-add-server": "添加服务器", + "opc-add-server-prompt": "请添加服务器", + "opc-application-name": "应用名称", + "opc-application-uri": "应用URI", + "opc-scan-period-in-seconds": "秒级扫描周期", + "opc-security": "安全性", + "opc-identity": "身份", + "opc-keystore": "密钥库", + "opc-type": "类型", + "opc-keystore-type": "类型", + "opc-keystore-location": "Location *", + "opc-keystore-password": "密码", + "opc-keystore-alias": "别名", + "opc-keystore-key-password": "密钥密码", + "opc-device-node-pattern": "设备节点模式", + "opc-device-name-pattern": "设备名称模式", + "modbus-server": "Servers/slaves", + "modbus-add-server": "添加 server/slave", + "modbus-add-server-prompt": "请添加 server/slave", + "modbus-transport": "Transport", + "modbus-tcp-reconnect": "自动重新连接", + "modbus-rtu-over-tcp": "RTU over TCP", + "modbus-port-name": "串口名称", + "modbus-encoding": "编码", + "modbus-parity": "奇偶性", + "modbus-baudrate": "波特率", + "modbus-databits": "数据位", + "modbus-stopbits": "停止位", + "modbus-databits-range": "数据位应该在7到8的范围内。", + "modbus-stopbits-range": "停止位应该在1到2的范围内。", + "modbus-unit-id": "单位编号", + "modbus-unit-id-range": "单位ID应该在1到247的范围内", + "modbus-device-name": "设备名称", + "modbus-poll-period": "轮询周期 (毫秒)", + "modbus-attributes-poll-period": "轮询属性周期 (毫秒)", + "modbus-timeseries-poll-period": "Timeseries 轮询周期 (毫秒)", + "modbus-poll-period-range": "轮询周期应为正值。", + "modbus-tag": "标签", + "modbus-function": "函数", + "modbus-register-address": "寄存器地址", + "modbus-register-address-range": "寄存器地址应该在0到65535的范围内。", + "modbus-register-bit-index": "位索引", + "modbus-register-bit-index-range": "位索引应该在0到15的范围内。", + "modbus-register-count": "寄存器计数", + "modbus-register-count-range": "寄存器计数应该是一个正值。", + "modbus-byte-order": "字节顺序", + "sync": { + "status": "状态", + "sync": "同步", + "not-sync": "不同步", + "last-sync-time": "最后同步时间", + "not-available": "无法使用" + }, + "export-extensions-configuration": "导出扩展配置", + "import-extensions-configuration": "导入扩展配置", + "import-extensions": "导入扩展", + "import-extension": "导入扩展", + "export-extension": "导出扩展", + "file": "扩展文件", + "invalid-file-error": "无效的扩展文件" + }, + "filter": { + "add": "添加筛选器", + "edit": "编辑筛选器", + "name": "筛选器名称", + "name-required": "筛选器名称必填。", + "duplicate-filter": "同名筛选器已存在。", + "filters": "筛选器", + "unable-delete-filter-title": "无法删除筛选器", + "unable-delete-filter-text": "无法删除筛选器 '{{filter}}' ,因为它由以下小部件使用:
              {{widgetsList}}", + "duplicate-filter-error": "找到重复的筛选器 '{{filter}}'。
              筛选器在仪表板中必须是唯一的。", + "missing-key-filters-error": "筛选器 '{{filter}}' 的键名筛选条件缺失。", + "filter": "筛选器", + "editable": "可编辑", + "no-filters-found": "未找到筛选器。", + "no-filter-text": "未指定筛选器", + "add-filter-prompt": "请添加筛选器", + "no-filter-matching": "未找到 '{{filter}}' 。", + "create-new-filter": "请新增!", + "filter-required": "筛选器必填。", + "operation": { + "operation": "操作", + "equal": "等于", + "not-equal": "不等于", + "starts-with": "开始于", + "ends-with": "结束于", + "contains": "包含", + "not-contains": "不包含", + "greater": "大于", + "less": "小于", + "greater-or-equal": "大于或等于", + "less-or-equal": "小于或等于", + "and": "和", + "or": "或", + "in": "匹配", + "not-in": "不匹配" + }, + "ignore-case": "忽略大小写", + "value": "值", + "remove-filter": "删除筛选器", + "preview": "筛选器预览", + "no-filters": "未配置筛选器", + "add-filter": "添加筛选器", + "add-complex-filter": "添加复合筛选器", + "add-complex": "添加复合", + "complex-filter": "复合筛选器", + "edit-complex-filter": "编辑复合筛选器", + "edit-filter-user-params": "编辑筛选器谓词用户参数", + "filter-user-params": "过滤谓词用户参数", + "user-parameters": "用户参数", + "display-label": "要显示的标签", + "autogenerated-label": "自动生成标签", + "order-priority": "字段顺序优先级", + "key-filter": "键名筛选器", + "key-filters": "键名筛选器", + "key-name": "键名", + "key-name-required": "键名必填。", + "key-type": { + "key-type": "键类型", + "attribute": "属性", + "timeseries": "Timeseries", + "entity-field": "实体", + "constant": "常量" + }, + "value-type": { + "value-type": "值类型", + "string": "字符串", + "numeric": "数字", + "boolean": "布尔值", + "date-time": "日期时间" + }, + "value-type-required": "键值类型是必需的。", + "key-value-type-change-title": "确定要更改键值类型吗?", + "key-value-type-change-message": "如果您确认新的值类型,所有输入的键过滤器将被删除。", + "no-key-filters": "未配置键名筛选器", + "add-key-filter": "添加键名筛选器", + "remove-key-filter": "删除键名筛选器", + "edit-key-filter": "编辑键名筛选器", + "date": "日期", + "time": "时间", + "current-tenant": "当前租户", + "current-customer": "当前客户", + "current-user": "当前用户", + "current-device": "当前设备", + "default-value": "默认值", + "dynamic-source-type": "动态源类型", + "dynamic-value": "动态值", + "no-dynamic-value": "无动态值", + "source-attribute": "源属性", + "switch-to-dynamic-value": "切换到动态值", + "switch-to-default-value": "切换到默认值", + "inherit-owner": "从所有者继承", + "source-attribute-not-set": "如果未设置源属性" + }, + "fullscreen": { + "expand": "展开到全屏", + "exit": "退出全屏", + "toggle": "切换全屏模式", + "fullscreen": "全屏" + }, + "function": { + "function": "函数" + }, + "gateway": { + "add-entry": "添加配置", + "connector-add": "添加新连接器", + "connector-enabled": "启用连接器", + "connector-name": "连接器名称", + "connector-name-required": "连接器名称名称必填。", + "connector-type": "连接器类型", + "connector-type-required": "连接器名称类型必填。", + "connectors": "连接器配置", + "create-new-gateway": "创建新网关", + "create-new-gateway-text": "确定要创建名为 '{{gatewayName}}' 的新网关?", + "delete": "删除配置", + "download-tip": "下载配置", + "gateway": "网关", + "gateway-exists": "同名设备已存在。", + "gateway-name": "网关名称", + "gateway-name-required": "网关名称必填。", + "gateway-saved": "已成功保存网关配置。", + "json-parse": "无效的JSON。", + "json-required": "字段不能为空。", + "no-connectors": "无连接器", + "no-data": "没有配置", + "no-gateway-found": "未找到网关。", + "no-gateway-matching": "未找到 '{{item}}' 。", + "path-logs": "日志文件的路径", + "path-logs-required": "路径是必需的。", + "remote": "远程配置", + "remote-logging-level": "日志记录级别", + "remove-entry": "删除配置", + "save-tip": "保存配置", + "security-type": "安全类型", + "security-types": { + "access-token": "访问令牌", + "tls": "TLS" + }, + "storage": "存储", + "storage-max-file-records": "文件中的最大记录数", + "storage-max-files": "最大文件数", + "storage-max-files-min": "最小值为1。", + "storage-max-files-pattern": "数字无效。", + "storage-max-files-required": "数字是必需的。", + "storage-max-records": "存储中的最大记录数", + "storage-max-records-min": "最小记录数为1。", + "storage-max-records-pattern": "数字无效。", + "storage-max-records-required": "最大记录项必填。", + "storage-pack-size": "最大事件包大小", + "storage-pack-size-min": "最小值为1。", + "storage-pack-size-pattern": "数字无效。", + "storage-pack-size-required": "最大事件包大小必填。", + "storage-path": "存储路径", + "storage-path-required": "存储路径必填。", + "storage-type": "存储类型", + "storage-types": { + "file-storage": "文件存储", + "memory-storage": "内存存储" + }, + "thingsboard": "ThingsBoard", + "thingsboard-host": "ThingsBoard主机", + "thingsboard-host-required": "主机必填。", + "thingsboard-port": "ThingsBoard端口", + "thingsboard-port-max": "最大端口号为65535。", + "thingsboard-port-min": "最小端口号为1。", + "thingsboard-port-pattern": "端口无效。", + "thingsboard-port-required": "端口必填。", + "tidy": "整洁", + "tidy-tip": "整理配置JSON", + "title-connectors-json": "连接器 {{typeName}} 配置", + "tls-path-ca-certificate": "网关上CA证书的路径", + "tls-path-client-certificate": "网关上客户端证书的路径", + "tls-path-private-key": "网关上私钥的路径", + "toggle-fullscreen": "切换全屏", + "transformer-json-config": "配置JSON*", + "update-config": "添加/更新配置JSON" + }, + "grid": { + "delete-item-title": "确定要删除此项吗?", + "delete-item-text": "请注意,确认后,项目及其所有相关数据将不可恢复。", + "delete-items-title": "确定删除 { count, plural, 1 {# 项} other {# 项} }吗?", + "delete-items-action-title": "删除 { count, plural, 1 {# 个元素} other {# 个元素} }", + "delete-items-text": "请注意,确认后所有选择的项目将被删除,所有相关数据将不可恢复。", + "add-item-text": "添加新项目", + "no-items-text": "未找到项目", + "item-details": "项目详细信息", + "delete-item": "删除项目", + "delete-items": "删除项目", + "scroll-to-top": "滚动到顶部" + }, + "help": { + "goto-help-page": "查看帮助", + "show-help": "显示帮助" + }, + "home": { + "home": "首页", + "profile": "属性", + "logout": "注销", + "menu": "菜单", + "avatar": "头像", + "open-user-menu": "打开用户菜单" + }, + "file-input": { + "browse-file": "浏览文件", + "browse-files": "浏览文件" + }, + "image-input": { + "drop-image-or": "拖拽图片或", + "drop-images-or": "拖拽图片或", + "no-images": "没有图片", + "images": "图片" + }, + "import": { + "no-file": "没有选择文件", + "drop-file": "拖动一个JSON文件或者单击以选择要上传的文件。", + "drop-json-file-or": "拖拽JSON文件或", + "drop-file-csv": "拖动一个CSV文件或单击以选择要上载的文件。", + "drop-file-csv-or": "拖拽CSV文件或", + "column-value": "数值", + "column-title": "标题", + "column-example": "示例值数据", + "column-key": "属性/遥测键", + "credentials": "Credentials", + "csv-delimiter": "CSV分隔符", + "csv-first-line-header": "第一行包含列名", + "csv-update-data": "更新属性/遥测", + "details": "Details", + "import-csv-number-columns-error": "一个文件至少应该包含两列", + "import-csv-invalid-format-error": "文件格式无效。行: '{{line}}'", + "column-type": { + "name": "名称", + "type": "类型", + "label": "标签", + "column-type": "列类型", + "client-attribute": "客户端属性", + "shared-attribute": "共享属性", + "server-attribute": "服务器属性", + "timeseries": "Timeseries", + "entity-field": "实体字段", + "access-token": "访问令牌", + "x509": "X.509", + "mqtt": { + "client-id": "MQTT客户端ID", + "user-name": "MQTT用户名", + "password": "MQTT密码" + }, + "lwm2m": { + "client-endpoint": "客户端终节点名称", + "security-config-mode": "安全配置模式", + "client-identity": "客户标识", + "client-key": "客户端公钥", + "client-cert": "客户端证书", + "bootstrap-server-security-mode": "LwM2M bootstrap server安全模式", + "bootstrap-server-secret-key": "LwM2M bootstrap server密钥", + "bootstrap-server-public-key-id": "LwM2M bootstrap server公钥", + "lwm2m-server-security-mode": "LwM2M server安全模式", + "lwm2m-server-secret-key": "LwM2M server证书密钥", + "lwm2m-server-public-key-id": "LwM2M server公钥" + }, + "isgateway": "是否网关", + "activity-time-from-gateway-device": "网关设备活动时间", + "description": "说明", + "routing-key": "边缘键", + "secret": "边缘密钥" + }, + "stepper-text": { + "select-file": "选择一个文件", + "configuration": "导入配置", + "column-type": "选择列类型", + "creat-entities": "创建新实体" + }, + "message": { + "create-entities": "{{count}} 个新实体已成功创建。", + "update-entities": "{{count}} 个实体已成功更新。", + "error-entities": "创建 {{count}} 个实体时出错。" + } + }, + "item": { + "selected": "选择" + }, + "js-func": { + "no-return-error": "函数必须返回值!", + "return-type-mismatch": "函数必须返回 '{{type}}' 类型的值!", + "tidy": "整洁", + "mini": "迷你" + }, + "key-val": { + "key": "键名", + "value": "数值", + "remove-entry": "删除条目", + "add-entry": "增加条目", + "no-data": "没有条目" + }, + "layout": { + "layout": "布局", + "manage": "布局管理", + "settings": "布局设置", + "color": "颜色", + "main": "主体", + "right": "右侧", + "left": "左", + "select": "选择目标布局", + "percentage-width": "百分比宽度(%)", + "fixed-width": "固定(px)", + "left-width": "左列(%)", + "right-width": "右列(%)", + "pick-fixed-side": "固定侧: ", + "layout-fixed-width": "固定宽度(px)", + "value-min-error": "值是必须大于{{min}}{{unit}}", + "value-max-error": "值是必须小于{{max}}{{unit}}", + "layout-fixed-width-required": "固定宽度必填", + "right-width-percentage-required": "右侧百分比宽度必填", + "left-width-percentage-required": "左侧百分比宽度必填", + "divider": "分隔线", + "right-side": "右侧布局", + "left-side": "左侧布局" + }, + "legend": { + "direction": "图例方向", + "position": "图例位置", + "sort-legend": "在图例中排序数据键", + "show-max": "显示最大值", + "show-min": "显示最小值", + "show-avg": "显示平均值", + "show-total": "显示总数", + "show-latest": "显示最新数据值", + "settings": "图例设置", + "min": "最小值", + "max": "最大值", + "avg": "平均值", + "total": "总数", + "latest": "latest", + "comparison-time-ago": { + "previousInterval": "(历史间隔)", + "customInterval": "(自定义间隔)", + "days": "(一天前)", + "weeks": "(一周前)", + "months": "(一个月前)", + "years": "(一年前)" + } + }, + "login": { + "login": "登录", + "request-password-reset": "请求密码重置", + "reset-password": "重置密码", + "create-password": "创建密码", + "two-factor-authentication": "双重因素身份验证", + "passwords-mismatch-error": "输入的密码必须相同!", + "password-again": "再次输入密码", + "sign-in": "登录 ", + "username": "用户名(电子邮件)", + "remember-me": "记住我", + "forgot-password": "忘记密码?", + "password-reset": "密码重置", + "expired-password-reset-message": "您的凭据已过期!请创建新密码。", + "new-password": "新密码", + "new-password-again": "再次输入新密码", + "password-link-sent-message": "密码重置链接已成功发送!", + "email": "电子邮件", + "login-with": "使用 {{name}} 登录", + "or": "或", + "error": "登录错误", + "verify-your-identity": "身份验证", + "select-way-to-verify": "选择验证方式", + "resend-code": "重发验证码", + "resend-code-wait": "{ time, plural, 1 {1 秒} other {# 秒} }后重发验证码", + "try-another-way": "尝试其他方法", + "totp-auth-description": "请从验证APP中查看验证码。", + "totp-auth-placeholder": "验证码", + "sms-auth-description": "验证码已发送到手机号码 {{contact}}。", + "sms-auth-placeholder": "SMS 验证码", + "email-auth-description": "验证码已发送到电子邮箱地址 {{contact}}。", + "email-auth-placeholder": "电子邮件验证码", + "backup-code-auth-description": "请输入一个备份验证码。", + "backup-code-auth-placeholder": "备份验证码" + }, + "markdown": { + "edit": "编辑", + "preview": "预览", + "copy-code": "单击拷贝", + "copied": "已拷贝!" + }, + "ota-update": { + "add": "添加包", + "assign-firmware": "分配的固件", + "assign-firmware-required": "分配的固件必填", + "assign-software": "分配的软件", + "assign-software-required": "分配的软件必填", + "auto-generate-checksum": "自动生成校验和", + "checksum": "校验和", + "checksum-hint": "如果校验和为空,会自动生成", + "checksum-algorithm": "校验和算法", + "checksum-copied-message": "包校验和已复制到剪贴板", + "change-firmware": "固件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", + "change-software": "软件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", + "chose-compatible-device-profile": "上传的包仅适用于具有所选配置文件的设备。", + "chose-firmware-distributed-device": "选择将分发到设备的固件", + "chose-software-distributed-device": "选择将分发到设备的软件", + "content-type": "内容类型", + "copy-checksum": "复制校验和", + "copy-direct-url": "复制直接URL", + "copyId": "复制包ID", + "copied": "已复制!", + "delete": "删除包", + "delete-ota-update-text": "请注意:确认后,OTA升级将不可恢复。", + "delete-ota-update-title": "确定要删除 '{{title}}' OTA升级吗?", + "delete-ota-updates-text": "请注意:确认后,所有选中的OTA升级将被删除。", + "delete-ota-updates-title": "确定要删除 { count, plural, 1 {1 OTA升级} other {# OTA升级} } 吗?", + "description": "说明", + "direct-url": "直接URL", + "direct-url-copied-message": "包直接URL已复制到剪贴板", + "direct-url-required": "直接URL必填", + "download": "下载包", + "drop-file": "拖放打包文件或点击选择要上传的文件。", + "drop-package-file-or": "拖拽文件或", + "file-name": "文件名", + "file-size": "文件大小", + "file-size-bytes": "文件大小(以字节为单位)", + "idCopiedMessage": "包ID已被复制到剪贴板", + "no-firmware-matching": "未找到与'{{entity}}'匹配的兼容固件OTA升级包。", + "no-firmware-text": "没有提供兼容的固件OTA升级包。", + "no-packages-text": "未找到包", + "no-software-matching": "未找到匹配 '{{entity}}' 的兼容软件OTA升级包。", + "no-software-text": "没有提供兼容的软件OTA升级包。", + "ota-update": "OTA 升级", + "ota-update-details": "OTA 升级详情", + "ota-updates": "OTA 升级", + "package-type": "包类型", + "packages-repository": "包仓库", + "search": "搜索包", + "selected-package": "{ count, plural, 1 {1 个包} other {# 个包} } 选中", + "title": "标题", + "title-required": "标题必填。", + "title-max-length": "标题长度必须少于256个字符", + "types": { + "firmware": "固件", + "software": "软件" + }, + "upload-binary-file": "上传二进制文件", + "use-external-url": "使用外部URL", + "version": "版本", + "version-required": "版本必填。", + "version-tag": "版本标签", + "version-tag-hint": "自定义标签应与您设备报告的软件包版本相匹配。", + "version-max-length": "版本长度必须少于256个字符", + "warning-after-save-no-edit": "上传包后,您将无法修改标题、版本、设备配置文件和包类型。" + }, + "position": { + "top": "顶部", + "bottom": "底部", + "left": "左侧", + "right": "右侧" + }, + "profile": { + "profile": "属性", + "last-login-time": "最后登录", + "change-password": "更改密码", + "current-password": "当前密码", + "copy-jwt-token": "复制 JWT 令牌", + "jwt-token": "JWT 令牌", + "token-valid-till": "令牌有效期至", + "tokenCopiedSuccessMessage": "JWT 令牌已复制到剪贴板", + "tokenCopiedWarnMessage": "JWT 令牌已过期!请刷新页面。" + }, + "profiles": { + "profiles": "配置" + }, + "security": { + "security": "安全", + "2fa": { + "2fa": "双因素身份验证", + "2fa-description": "双因素身份验证可保护您的帐户免受未经授权的访问。在登录时必须输入安全验证码。", + "authenticate-with": "可以使用以下身份验证:", + "disable-2fa-provider-text": "禁用 {{ name }} 会降低帐户的安全性", + "disable-2fa-provider-title": "确定要禁用 {{ name }} 吗?", + "get-new-code": "获取新验证码", + "main-2fa-method": "用作主要的双因素身份验证方法", + "dialog": { + "activation-step-description-email": "下次登录时,系统将提示您输入电子邮件中的验证码。", + "activation-step-description-sms": "下次登录时,系统将提示您输入短信中的验证码。", + "activation-step-description-totp": "下次登录时,您需要提供一个双因素身份验证码。", + "activation-step-label": "激活", + "backup-code-description": "打印出验证码,以便在您需要时使用它们登录帐户。每个备份验证码可以使用一次。", + "backup-code-warn": "离开此页后,这些代码将无法再次显示。使用以下选项安全存放。", + "download-txt": "下载(txt)", + "email-step-description": "输入用作身份验证的电子邮件", + "email-step-label": "电子邮件", + "enable-email-title": "启用电子邮件验证", + "enable-sms-title": "启用SMS验证", + "enable-totp-title": "启用验证APP", + "enter-verification-code": "输入6位验证码", + "get-backup-code-title": "获取备份验证码", + "next": "下一步", + "scan-qr-code": "使用验证APP扫描二维码", + "send-code": "发送验证码", + "sms-step-description": "输入用作身份验证的手机号码", + "sms-step-label": "手机号码", + "success": "操作成功!", + "totp-step-description-install": "可以安装像Google Authenticator、Authy或Duo这样的应用程序。", + "totp-step-description-open": "在手机上打开验证APP。", + "totp-step-label": "获取APP", + "verification-code": "6位验证码", + "verification-code-invalid": "验证码格式无效", + "verification-code-incorrect": "验证码不正确", + "verification-code-many-request": "请求过多,请检查验证码", + "verification-step-description": "输入发送到 {{ address }} 的6位代码", + "verification-step-label": "验证" + }, + "provider": { + "email": "电子邮件", + "email-description": "使用您电子邮件中的验证码进行身份验证。", + "email-hint": "身份验证码通过电子邮件发送到 {{ info }}", + "sms": "SMS", + "sms-description": "使用短信进行身份验证。当登录时,系统会通过短信向您发送验证码。", + "sms-hint": "身份验证码通过短信发送到 {{ info }}", + "totp": "验证APP", + "totp-description": "使用手机上的Google Authenticator、Authy或Duo等应用程序进行身份验证,它将生成用于登录的验证码。", + "totp-hint": "已为您的帐户设置验证APP", + "backup_code": "备份验证码", + "backup-code-description": "这些可打印的一次性密码允许您在离开手机时登录,比如正在旅行。", + "backup-code-hint": "{{ info }}个一次性代码处于激活状态" + } + }, + "password-requirement": { + "at-least": "至少:", + "character": "{ count, plural, 1 {1 位字符} other {# 位字符} }", + "digit": "{ count, plural, 1 {1 位数字} other {# 位数字} }", + "incorrect-password-try-again": "密码不正确。再试一次", + "lowercase-letter": "{ count, plural, 1 {1 位小写字母} other {# 位小写字母} }", + "new-passwords-not-match": "新密码不匹配", + "password-should-not-contain-spaces": "密码不应包含空格", + "password-not-meet-requirements": "密码不符合要求", + "password-requirements": "密码要求", + "password-should-difference": "新密码应与当前密码不同", + "special-character": "{ count, plural, 1 {1 位特殊字符} other {# 位特殊字符} }", + "uppercase-letter": "{ count, plural, 1 {1 位大写字母} other {# 位大写字母} }" + } + }, + "relation": { + "relations": "关联", + "direction": "方向", + "search-direction": { + "FROM": "从", + "TO": "到" + }, + "direction-type": { + "FROM": "从", + "TO": "到" + }, + "from-relations": "向外的关联", + "to-relations": "向内的关联", + "selected-relations": "已选择{ count, plural, 1 {# 个关联} other {# 个关联} }", + "type": "类型", + "to-entity-type": "到实体类型", + "to-entity-name": "到实体名称", + "from-entity-type": "从实体类型", + "from-entity-name": "从实体类型", + "to-entity": "到实体", + "from-entity": "从实体", + "delete": "删除关联", + "relation-type": "关联类型", + "relation-type-required": "关联类型必填", + "relation-type-max-length": "关联类型长度必须少于256个字符", + "any-relation-type": "任何类型", + "add": "添加关联", + "edit": "编辑关联", + "delete-to-relation-title": "确定要删除实体 '{{entityName}}' 的关联吗?", + "delete-to-relation-text": "确定删除后实体 '{{entityName}}' 将取消与当前实体的关联关系。", + "delete-to-relations-title": "确定要删除 { count, plural, 1 {# 个关联} other {# 个关联} }吗?", + "delete-to-relations-text": "确定删除所有选择的关联关系后,与当前实体对应的所有关联关系将被移除。", + "delete-from-relation-title": "确定要从实体 '{{entityName}}' 删除关联吗?", + "delete-from-relation-text": "确定删除后,当前实体将与实体 '{{entityName}}' 取消关联", + "delete-from-relations-title": "确定删除 { count, plural, 1 {# 个关联} other {# 个关联} } 吗?", + "delete-from-relations-text": "确定删除所有选择的关联关系后,当前实体将与对应的实体取消关联", + "remove-relation-filter": "移除关联筛选器", + "add-relation-filter": "添加关联筛选器", + "any-relation": "任意关联", + "relation-filters": "关联筛选器", + "additional-info": "附加信息 (JSON)", + "invalid-additional-info": "无法解析附加信息JSON。", + "no-relations-text": "未找到关联" + }, + "resource": { + "add": "添加资源", + "copyId": "复制资源ID", + "delete": "删除资源", + "delete-resource-text": "请注意:确认后,资源将不可恢复。", + "delete-resource-title": "确定要删除资源 '{{resourceTitle}}' 吗?", + "delete-resources-action-title": "删除 { count, plural, 1 {# 个资源} other {# 个资源} }", + "delete-resources-text": "请注意:确认后,所有选定的资源将被删除。", + "delete-resources-title": "确定要删除 { count, plural, 1 {# 个资源} other {# 个资源} }吗?", + "download": "Download resource", + "drop-file": "拖拽资源文件或单击以选择要上传的文件。", + "drop-resource-file-or": "Drag and drop a resource file or", + "empty": "资源为空", + "file-name": "File name", + "idCopiedMessage": "拖拽资源文件或", + "no-resource-matching": "未找到与 '{{widgetsBundle}}' 匹配的资源。", + "no-resource-text": "未找到资源", + "open-widgets-bundle": "打开部件库", + "resource": "资源", + "resource-library-details": "资源库详情", + "resource-type": "资源类型", + "resources-library": "资源库", + "search": "查找资源", + "selected-resources": "已选择{ count, plural, 1 {# 个资源} other {# 个资源} }", + "system": "系统", + "title": "标题", + "title-required": "标题是必填项。", + "title-max-length": "标题长度必须少于256个字符" + }, + "rulechain": { + "rulechain": "规则链", + "rulechains": "规则链库", + "root": "是否根链", + "delete": "删除规则链", + "name": "名称", + "name-required": "名称必填。", + "name-max-length": "名称长度必须少于256个字符", + "description": "说明", + "add": "添加规则链", + "set-root": "设置为根规则链", + "set-root-rulechain-title": "确定要设置'{{ruleChainName}}'为根规则链吗?", + "set-root-rulechain-text": "确认后,规则链将变为根规格链,并将处理所有传入的传输消息。", + "delete-rulechain-title": " 确定要删除规则链'{{ruleChainName}}'吗?", + "delete-rulechain-text": "请注意,确认后,规则链和所有相关数据将不可恢复。", + "delete-rulechains-title": "确定要删除{count, plural, 1 { 1 个规则链} other {# 个规则链} }吗?", + "delete-rulechains-action-title": "删除 { count, plural, 1 {# 个规则链} other {# 个规则链} }", + "delete-rulechains-text": "请注意:确认后,所有选定的规则链将被删除,所有相关的数据将不可恢复。", + "add-rulechain-text": "添加新的规则链", + "no-rulechains-text": "未找到规则链", + "rulechain-details": "规则链详情", + "details": "详情", + "events": "事件", + "system": "系统", + "import": "导入规则链", + "export": "导出规则链", + "export-failed-error": "无法导出规则链:{{error}}", + "create-new-rulechain": "创建新的规则链", + "rulechain-file": "规则链文件", + "invalid-rulechain-file-error": "不能导入规则链:无效的规则链数据格式。", + "copyId": "复制规则链ID", + "idCopiedMessage": "规则ID已经复制到粘贴板", + "select-rulechain": "选择规则链", + "no-rulechains-matching": "没有发现匹配'{{entity}}'的规则链。", + "rulechain-required": "规则链必填", + "management": "规则集管理", + "debug-mode": "调试模式", + "search": "查找规则链", + "selected-rulechains": "已选择 { count, plural, 1 {# 个规则链} other {# 个规则链} }", + "open-rulechain": "打开规则链", + "assign-new-rulechain": "Assign new rulechain", + "edge-template-root": "模版根链", + "assign-to-edge": "分配给边缘", + "edge-rulechain": "边缘规则链", + "unassign-rulechain-from-edge-text": "确认后,规则链将会取消分配,边缘无法访问。", + "unassign-rulechains-from-edge-title": "确定要取消分配 { count, plural, 1 {1 个规则链} other {# 个规则链} }吗?", + "unassign-rulechains-from-edge-text": "确认后,选定的规则链将会取消分配,边缘无法访问。", + "assign-rulechain-to-edge-title": "分配规则链给边缘", + "assign-rulechain-to-edge-text": "请选择要分配给边缘的规则链", + "set-edge-template-root-rulechain": "设置为边缘模版根规则链", + "set-edge-template-root-rulechain-title": "确定将 '{{ruleChainName}}' 设置为边缘模版根规则链吗?", + "set-edge-template-root-rulechain-text": "确认后,将会成为边缘模版根规则链,且它会成为新创建边缘的根规则链。", + "invalid-rulechain-type-error": "不能导入规则链:无效的规则链类型。期望类型为{{expectedRuleChainType}}。", + "set-auto-assign-to-edge": "将规则链分配给新创建的边缘", + "set-auto-assign-to-edge-title": "确定将规则链'{{ruleChainName}}'自动分配给新创建的边缘吗?", + "set-auto-assign-to-edge-text": "确认后,将自动分配规则链给新创建的边缘。", + "unset-auto-assign-to-edge": "不将规则链分配给边缘", + "unset-auto-assign-to-edge-title": "确定不再将规则链'{{ruleChainName}}'自动分配给新创建的边缘吗?", + "unset-auto-assign-to-edge-text": "确认后,将不再自动分配规则链给新创建的边缘。", + "unassign-rulechain-title": "你确定要取消分配规则链'{{ruleChainName}}'?", + "unassign-rulechains": "取消分配规则链" + }, + "rulenode": { + "details": "详情", + "events": "事件", + "search": "查找节点", + "open-node-library": "打开节点库", + "add": "添加规则节点", + "name": "名称", + "name-required": "名称必填。", + "name-max-length": "名称长度必须少于256个字符", + "type": "类型", + "description": "说明", + "delete": "删除规则节点", + "select-all-objects": "选择所有节点和连接", + "deselect-all-objects": "取消选择所有节点和连接", + "delete-selected-objects": "删除选定的节点和连接", + "delete-selected": "删除选定", + "create-nested-rulechain": "创建嵌套规则链", + "select-all": "选择全部", + "copy-selected": "选择副本", + "deselect-all": "取消选择", + "rulenode-details": "规则节点详情", + "debug-mode": "调试模式", + "configuration": "配置", + "link": "链接", + "link-details": "规则节点链接详情", + "add-link": "添加链接", + "link-label": "链接标签", + "link-label-required": "链接标签必填", + "custom-link-label": "自定义链接标签", + "custom-link-label-required": "自定义链接标签必填", + "link-labels": "链接标签", + "link-labels-required": "链接标签必填。", + "no-link-labels-found": "未找到链接标签", + "no-link-label-matching": "未找到匹配 '{{label}}' 的链接标签。", + "create-new-link-label": "创建一个新的!", + "type-filter": "筛选器", + "type-filter-details": "使用配置条件筛选传入消息", + "type-enrichment": "属性集", + "type-enrichment-details": "向消息元数据中添加附加信息", + "type-transformation": "变换", + "type-transformation-details": "更改消息 Payload 和元数据", + "type-action": "动作", + "type-action-details": "执行特别动作", + "type-external": "外部的", + "type-external-details": "与外部系统交互", + "type-rule-chain": "规则链", + "type-rule-chain-details": "将传入消息转发到指定的规则链", + "type-flow": "流", + "type-flow-details": "组织消息流", + "type-input": "输入", + "type-input-details": "规则链的逻辑输入,将传入消息转发到下一个相关规则节点", + "type-unknown": "未知", + "type-unknown-details": "未解析的规则节点", + "directive-is-not-loaded": "定义的配置指令 '{{directiveName}}' 不可用。", + "ui-resources-load-error": "加载配置UI资源失败。", + "invalid-target-rulechain": "无法解析目标规则链!", + "test-script-function": "测试脚本功能", + "script-lang-java-script": "Java Script", + "script-lang-tbel": "TBEL", + "message": "消息", + "message-type": "消息类型", + "select-message-type": "选择消息类型", + "message-type-required": "消息类型必填", + "metadata": "元数据", + "metadata-required": "元数据项不能为空。", + "output": "输出", + "test": "测试", + "help": "帮助", + "reset-debug-mode": "重置所有节点中的调试模式" + }, + "timezone": { + "timezone": "时区", + "select-timezone": "选择时区", + "no-timezones-matching": "找不到匹配的'{{timezone}}'时区。", + "timezone-required": "时区必填。", + "browser-time": "浏览器时间" + }, + "queue": { + "queue-name": "队列", + "no-queues-found": "未找到队列", + "no-queues-matching": "未找到匹配 '{{queue}}' 的队列", + "select-name": "选择队列名称", + "name": "名称", + "name-required": "队列名称必填。", + "name-unique": "队列名称必须唯一。", + "name-pattern": "队列名称不能包含ASCII字母数字以外的字符, '.', '_' 和 '-'等。", + "queue-required": "队列必填。", + "topic-required": "队列主题必填。", + "poll-interval-required": "轮询间隔必填。", + "poll-interval-min-value": "轮询间隔不能小于1", + "partitions-required": "分区必填。", + "partitions-min-value": "分区不能小于1", + "pack-processing-timeout-required": "处理超时时间必填。", + "pack-processing-timeout-min-value": "处理超时时间不能小于1", + "batch-size-required": "批量处理大小必填。", + "batch-size-min-value": "批量处理大小不能小于1", + "retries-required": "重试次数必填。", + "retries-min-value": "重试次数不能为负", + "failure-percentage-required": "失败百分比必填。", + "failure-percentage-min-value": "失败百分比值不能小于0", + "failure-percentage-max-value": "失败百分比值不能大于100", + "pause-between-retries-required": "重试间隔必填。", + "pause-between-retries-min-value": "重试间隔不能小于1", + "max-pause-between-retries-required": "最大重试间隔必填。", + "max-pause-between-retries-min-value": "最大重试间隔不能小于1", + "submit-strategy-type-required": "提交策略类型必填。", + "processing-strategy-type-required": "处理策略类型必填。", + "queues": "队列", + "selected-queues": "已选择 { count, plural, 1 {1 个队列} other {# 个队列} }", + "delete-queue-title": "确定要删除 '{{queueName}}' 队列吗?", + "delete-queues-title": "确定要删除 { count, plural, 1 {1 个队列} other {# 个队列} }吗?", + "delete-queue-text": "请注意:确认后,队列和所有相关数据将不可恢复。", + "delete-queues-text": "确认后,所有选定队列都将被删除,无法访问。", + "search": "搜索队列", + "add": "添加队列", + "details": "队列详情", + "topic": "主题", + "submit-settings": "提交设置", + "submit-strategy": "Strategy type *", + "grouping-parameter": "分组参数", + "processing-settings": "重试处理设置", + "processing-strategy": "Processing type *", + "retries-settings": "重试设置", + "polling-settings": "轮询设置", + "batch-processing": "批量处理", + "poll-interval": "轮询间隔", + "partitions": "分区", + "immediate-processing": "即时处理", + "consumer-per-partition": "每个分区消费者单独轮询消息", + "consumer-per-partition-hint": "每个分区启用单独的消费者", + "processing-timeout": "处理超时(毫秒)", + "batch-size": "批量处理大小", + "retries": "重试次数 (0 – 无限制)", + "failure-percentage": "跳过重试的失败消息百分比", + "pause-between-retries": "重试间隔(秒)", + "max-pause-between-retries": "最大重试间隔(秒)", + "delete": "删除队列", + "copyId": "复制队列ID", + "idCopiedMessage": "队列ID已复制到剪贴板", + "description": "说明", + "description-hint": "此文本将显示在队列说明中,而不是所选策略中", + "alt-description": "提交策略:{{submitStrategy}},处理策略:{{processingStrategy}}", + "strategies": { + "sequential-by-originator-label": "按发起者顺序处理", + "sequential-by-originator-hint": "在确认设备A的前一条消息之前,不会提交设备A的新消息", + "sequential-by-tenant-label": "按租户顺序处理", + "sequential-by-tenant-hint": "在确认租户A的前一条消息之前,不会提交租户A的新消息", + "sequential-label": "顺序处理", + "sequential-hint": "在确认前一条消息之前,不会提交新消息", + "burst-label": "突发处理", + "burst-hint": "所有消息都按到达的顺序提交到规则链", + "batch-label": "批量处理", + "batch-hint": "在确认前一批消息之前,不会提交新批", + "skip-all-failures-label": "跳过所有失败", + "skip-all-failures-hint": "忽略所有失败", + "skip-all-failures-and-timeouts-label": "跳过所有失败和超时", + "skip-all-failures-and-timeouts-hint": "忽略所有失败和超时", + "retry-all-label": "全部重试", + "retry-all-hint": "重试处理包中的所有消息", + "retry-failed-label": "失败重试", + "retry-failed-hint": "重试处理包中的所有失败消息", + "retry-timeout-label": "超时重试", + "retry-timeout-hint": "重试处理包中的所有超时消息", + "retry-failed-and-timeout-label": "失败与超时重试", + "retry-failed-and-timeout-hint": "重试处理包中所有失败和超时的消息" + } + }, + "server-error": { + "general": "一般服务器错误", + "authentication": "授权错误", + "jwt-token-expired": "JWT令牌已过期", + "tenant-trial-expired": "租户过期", + "credentials-expired": "凭据过期", + "permission-denied": "没有权限", + "invalid-arguments": "无效参数", + "bad-request-params": "请求无效", + "item-not-found": "找不到项目", + "too-many-requests": "请求过于频繁", + "too-many-updates": "更新过于频繁" + }, + "tenant": { + "tenant": "租户", + "tenants": "租户", + "management": "租户管理", + "add": "添加租户", + "admins": "管理员", + "manage-tenant-admins": "管理租户管理员", + "delete": "删除租户", + "add-tenant-text": "添加新租户", + "no-tenants-text": "未找到租户", + "tenant-details": "租客详情", + "title-max-length": "标题长度必须少于256个字符", + "delete-tenant-title": "确定要删除租户'{{tenantTitle}}'吗?", + "delete-tenant-text": "请注意:确认后,租户和所有相关数据将不可恢复。", + "delete-tenants-title": "确定要删除 {count,plural,1 {# 个租户} other {# 个租户} } 吗?", + "delete-tenants-action-title": "删除 { count, plural, 1 {# 个租户} other {# 个租户} }", + "delete-tenants-text": "请注意:确认后,所有选定的租户将被删除,所有相关数据将不可恢复。", + "title": "标题", + "title-required": "标题必填。", + "description": "说明", + "details": "详情", + "events": "事件", + "copyId": "复制租户ID", + "idCopiedMessage": "租户ID已经复制到粘贴板", + "select-tenant": "选择租户", + "no-tenants-matching": "未找到匹配 '{{entity}}' 的租户", + "tenant-required": "租户必填", + "search": "查找租户", + "selected-tenants": "已选择 { count, plural, 1 {# 个租户} other {# 个租户} }", + "isolated-tb-rule-engine": "使用独立的规则引擎服务", + "isolated-tb-rule-engine-details": "每个独立租户需要单独的规则引擎微服务" + }, + "tenant-profile": { + "tenant-profile": "租户配置", + "tenant-profiles": "租户配置", + "add": "添加租户配置", + "edit": "编辑租户配置", + "tenant-profile-details": "租户配置详细信息", + "no-tenant-profiles-text": "未找到租户配置", + "name-max-length": "名称长度必须少于256个字符", + "search": "查找租户配置", + "selected-tenant-profiles": "已选择 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }", + "no-tenant-profiles-matching": "未找到与 '{{entity}}' 匹配的租户配置。", + "tenant-profile-required": "租户配置必填", + "idCopiedMessage": "租户配置ID已复制到剪贴板", + "set-default": "设置该租户配置为默认", + "delete": "删除租户配置", + "copyId": "复制租户配置ID", + "name": "名称", + "name-required": "名称必填。", + "data": "配置数据", + "profile-configuration": "配置设置", + "description": "说明", + "default": "默认", + "delete-tenant-profile-title": "确定要删除租户配置 '{{tenantProfileName}}'吗?", + "delete-tenant-profile-text": "请注意:确认后,租户配置和所有相关数据将不可恢复。", + "delete-tenant-profiles-title": "确定要删除 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }吗?", + "delete-tenant-profiles-text": "请注意:确认后,所有选定的租户配置将被删除,所有相关数据将不可恢复。", + "set-default-tenant-profile-title": "确定要将租户配置 '{{tenantProfileName}}' 设为默认值吗?", + "set-default-tenant-profile-text": "确认后,此租户配置将被标记为默认配置,并将用于未指定配置的新租户。", + "no-tenant-profiles-found": "未找到租户配置。", + "create-new-tenant-profile": "创建一个新的!", + "create-tenant-profile": "创建新的租户配置", + "import": "导入租户配置", + "export": "导出租户配置", + "export-failed-error": "无法导出租户配置: {{error}}", + "tenant-profile-file": "租户配置文件", + "invalid-tenant-profile-file-error": "无法导入租户配置:无效的租户配置数据结构。", + "advanced-settings": "高级设置", + "entities": "实体", + "rule-engine": "规则引擎", + "time-to-live": "TTL", + "alarms-and-notifications": "告警与通知", + "ota-files-in-bytes": "OTA文件(字节)", + "ws-title": "WS", + "unlimited": "(0 - 无限制)", + "maximum-devices": "最大设备数", + "maximum-devices-required": "最大设备数必填。", + "maximum-devices-range": "最大设备数不能为负数", + "maximum-assets": "最大资产数", + "maximum-assets-required": "最大资产数必填。", + "maximum-assets-range": "最大资产数不能为负数", + "maximum-customers": "最大客户数", + "maximum-customers-required": "最大客户数必填。", + "maximum-customers-range": "最大客户数不能为负数", + "maximum-users": "最大用户数", + "maximum-users-required": "最大用户数必填。", + "maximum-users-range": "最大用户数不能为负数", + "maximum-dashboards": "最大仪表板数", + "maximum-dashboards-required": "最大仪表板数必填。", + "maximum-dashboards-range": "最大仪表板数不能为负数", + "maximum-rule-chains": "最大规则链数", + "maximum-rule-chains-required": "最大规则链数必填。", + "maximum-rule-chains-range": "最大规则链数不能为负数", + "maximum-resources-sum-data-size": "资源文件总大小", + "maximum-resources-sum-data-size-required": "资源文件总大小必填。", + "maximum-resources-sum-data-size-range": "资源文件总大小不能为负数", + "maximum-ota-packages-sum-data-size": "OTA包文件总大小", + "maximum-ota-package-sum-data-size-required": "OTA包文件总大小必填。", + "maximum-ota-package-sum-data-size-range": "OTA包文件总大小不能为负数", + "transport-tenant-msg-rate-limit": "租户消息", + "transport-tenant-telemetry-msg-rate-limit": "租户遥测消息", + "transport-tenant-telemetry-data-points-rate-limit": "租户遥测数据点", + "transport-device-msg-rate-limit": "设备消息", + "transport-device-telemetry-msg-rate-limit": "设备遥测数据点", + "transport-device-telemetry-data-points-rate-limit": "设备遥测消息", + "tenant-entity-export-rate-limit": "实体版本创建", + "tenant-entity-import-rate-limit": "实体版本加载", + "max-transport-messages": "最大传输消息数", + "max-transport-messages-required": "最大传输消息数必填。", + "max-transport-messages-range": "最大传输消息数不能为负数", + "max-transport-data-points": "最大传输数据点数", + "max-transport-data-points-required": "最大传输数据点数必填。", + "max-transport-data-points-range": "最大传输数据点数不能为负", + "max-r-e-executions": "最大规则引擎执行数", + "max-r-e-executions-required": "最大规则引擎执行数必填。", + "max-r-e-executions-range": "最大规则引擎执行数不能为负", + "max-j-s-executions": "最大 JavaScript 执行数", + "max-j-s-executions-required": "最大 JavaScript 执行数必填。", + "max-j-s-executions-range": "最大 JavaScript 执行数不能为负数", + "max-d-p-storage-days": "最大存储点天", + "max-d-p-storage-days-required": "最大存储点天必填。", + "max-d-p-storage-days-range": "最大存储点天不能为负数", + "default-storage-ttl-days": "默认存储TTL天数", + "default-storage-ttl-days-required": "默认存储TTL天数必填。.", + "default-storage-ttl-days-range": "默认存储TTL天数不能为负数", + "alarms-ttl-days": "告警TTL天数", + "alarms-ttl-days-required": "告警TTL天数必填。", + "alarms-ttl-days-days-range": "告警TTL天数不能为负数", + "rpc-ttl-days": "RPC TTL天数", + "rpc-ttl-days-required": "RPC TTL天数必填。", + "rpc-ttl-days-days-range": "RPC TTL天数不能为负数", + "max-rule-node-executions-per-message": "每条消息的最大规则节点执行数", + "max-rule-node-executions-per-message-required": "每个消息的最大规则节点执行数必填。", + "max-rule-node-executions-per-message-range": "每条消息的最大规则节点执行数不能为负", + "max-emails": "最大电子邮件发送数", + "max-emails-required": "最大电子邮件发送数必填。", + "max-emails-range": "最大电子邮件发送数不能为负", + "max-sms": "最大短信发送数", + "max-sms-required": "最大短信发送数必填。", + "max-sms-range": "最大短信发送数不能为负", + "max-created-alarms": "最大创建告警数", + "max-created-alarms-required": "最大创建告警数必填。", + "max-created-alarms-range": "最大创建告警数不能为负数", + "no-queue": "未配置队列", + "add-queue": "添加队列", + "queues-with-count": "队列 ({{count}})", + "tenant-rest-limits": "租户REST请求", + "customer-rest-limits": "客户REST请求", + "incorrect-pattern-for-rate-limits": "格式为以冒号分割容量与周期(秒)并以逗号分割配置对,例如 100:1,2000:60", + "too-small-value-zero": "数值必须大于0", + "too-small-value-one": "数值必须大于1", + "cassandra-tenant-limits-configuration": "租户Cassandra查询", + "ws-limit-max-sessions-per-tenant": "租户最大会话数", + "ws-limit-max-sessions-per-customer": "客户最大会话数", + "ws-limit-max-sessions-per-regular-user": "普通用户最大会话数", + "ws-limit-max-sessions-per-public-user": "公共用户最大会话数", + "ws-limit-queue-per-session": "会话最大消息队列大小", + "ws-limit-max-subscriptions-per-tenant": "租户最大订阅数", + "ws-limit-max-subscriptions-per-customer": "客户最大订阅数", + "ws-limit-max-subscriptions-per-regular-user": "普通用户最大订阅数", + "ws-limit-max-subscriptions-per-public-user": "公共用户最大订阅数", + "ws-limit-updates-per-session": "会话WS更新", + "rate-limits": { + "add-limit": "添加限制", + "advanced-settings": "高级设置", + "edit-limit": "编辑限制", + "but-less-than": "但小于", + "edit-transport-tenant-msg-title": "编辑传输租户消息速率限制", + "edit-transport-tenant-telemetry-msg-title": "编辑传输租户遥测消息速率限制", + "edit-transport-tenant-telemetry-data-points-title": "编辑传输租户遥测数据点速率限制", + "edit-transport-device-msg-title": "编辑传输设备消息速率限制", + "edit-transport-device-telemetry-msg-title": "编辑传输设备遥测消息速率限制", + "edit-transport-device-telemetry-data-points-title": "编辑传输设备遥测数据点速率限制", + "edit-transport-tenant-msg-rate-limit-title": "编辑传输租户消息速率限制", + "edit-customer-rest-limits-title": "编辑客户REST请求速率限制", + "edit-ws-limit-updates-per-session-title": "编辑会话WS更新速率限制", + "edit-cassandra-tenant-limits-configuration-title": "编辑租户Cassandra查询速率限制", + "edit-tenant-entity-export-rate-limit-title": "编辑实体版本创建速率限制", + "edit-tenant-entity-import-rate-limit-title": "编辑实体版本加载速率限制", + "messages-per": "条消息每", + "not-set": "未配置", + "number-of-messages": "消息数量", + "number-of-messages-required": "消息数量必填。", + "number-of-messages-min": "最小值为1。", + "preview": "预览", + "per-seconds": "每秒", + "per-seconds-required": "时间比率必填。", + "per-seconds-min": "最小值为1。", + "rate-limits": "速率限制", + "remove-limit": "删除限制", + "transport-tenant-msg": "传输租户消息", + "transport-tenant-telemetry-msg": "传输租户遥测消息", + "transport-tenant-telemetry-data-points": "传输租户遥测数据点", + "transport-device-msg": "传输设备消息", + "transport-device-telemetry-msg": "传输设备遥测消息", + "transport-device-telemetry-data-points": "传输设备遥测数据点", + "sec": "秒" + } + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, 1 {# 秒} other {# 秒} }", + "minutes-interval": "{ minutes, plural, 1 {# 分} other {# 分} }", + "hours-interval": "{ hours, plural, 1 {# 小时} other {# 小时} }", + "days-interval": "{ days, plural, 1 {# 天} other {# 天} }", + "days": "天", + "hours": "小时", + "minutes": "分钟", + "seconds": "秒", + "advanced": "高级", + "predefined": { + "yesterday": "昨天", + "day-before-yesterday": "前天", + "this-day-last-week": "前一周的这一天", + "previous-week": "前一周(周日至周六)", + "previous-week-iso": "前一周(周一至周日)", + "previous-month": "前一个月", + "previous-year": "前一年", + "current-hour": "当前小时", + "current-day": "当前天", + "current-day-so-far": "当天到目前为止", + "current-week": "本周(周日至周六)", + "current-week-iso": "本周(周一至周日)", + "current-week-so-far": "本周到目前为止(周日至周六)", + "current-week-iso-so-far": "本周到目前为止(周一至周日)", + "current-month": "本月", + "current-month-so-far": "本月到目前为止", + "current-year": "本年", + "current-year-so-far": "本年到目前为止" + } + }, + "timeunit": { + "milliseconds": "毫秒", + "seconds": "秒", + "minutes": "分钟", + "hours": "小时", + "days": "天" + }, + "timewindow": { + "days": "{ days, plural, 1 {# 天 } other {# 天 } }", + "hours": "{ hours, plural, 0 {- 小时 } 1 {# 小时 } other {# 小时 } }", + "minutes": "{ minutes, plural, 0 {- 分 } 1 {# 分 } other {# 分 } }", + "seconds": "{ seconds, plural, 0 {- 秒 } 1 {# 秒 } other {# 秒 } }", + "realtime": "实时", + "history": "历史", + "last-prefix": "最后", + "period": "从 {{ startTime }} 到 {{ endTime }}", + "edit": "编辑时间窗口", + "date-range": "日期范围", + "last": "最后", + "time-period": "时间段", + "hide": "隐藏", + "interval": "区间" + }, + "user": { + "user": "用户", + "users": "用户", + "customer-users": "客户用户", + "tenant-admins": "租户管理员", + "sys-admin": "系统管理员", + "tenant-admin": "租户管理员", + "customer": "客户", + "anonymous": "匿名", + "add": "添加用户", + "delete": "删除用户", + "add-user-text": "添加新用户", + "no-users-text": "未找到用户", + "user-details": "用户详细信息", + "delete-user-title": "确定要删除用户 '{{userEmail}}' 吗?", + "delete-user-text": "请注意:确认后,用户和所有相关数据将不可恢复。", + "delete-users-title": "确定要删除 { count, plural, 1 {# 个用户} other {# 个用户} } 吗?", + "delete-users-action-title": "删除 { count, plural, 1 {# 个用户} other {# 个用户} }", + "delete-users-text": "请注意:确认后,所有选定的用户将被删除,所有相关数据将不可恢复。", + "activation-email-sent-message": "激活电子邮件已成功发送!", + "resend-activation": "重新发送激活", + "email": "电子邮件", + "email-required": "电子邮件必填。", + "invalid-email-format": "无效的邮件格式。", + "first-name": "名字", + "last-name": "姓氏", + "description": "说明", + "default-dashboard": "默认面板", + "always-fullscreen": "始终全屏", + "select-user": "选择用户", + "no-users-matching": "未找到匹配 '{{entity}}' 的用户。", + "user-required": "用户必填", + "activation-method": "激活方式", + "display-activation-link": "显示激活链接", + "send-activation-mail": "发送激活邮件", + "activation-link": "用户激活链接", + "activation-link-text": "使用该链接 激活 激活用户:", + "copy-activation-link": "复制用户激活链接", + "activation-link-copied-message": "用户激活链接已经复制到粘贴板", + "details": "详情", + "login-as-tenant-admin": "以租户管理员身份登录", + "login-as-customer-user": "以客户用户身份登录", + "search": "查找用户", + "selected-users": "已选择 { count, plural, 1 {# 个用户} other {# 个用户} }", + "disable-account": "禁用用户帐户", + "enable-account": "启用用户帐户", + "enable-account-message": "已成功启用用户帐户!", + "disable-account-message": "已成功禁用用户帐户!", + "copyId": "复制用户Id", + "idCopiedMessage": "用户ID已经复制到粘贴板" + }, + "value": { + "type": "值类型", + "string": "字符串", + "string-value": "字符串值", + "string-value-required": "字符串值必填", + "integer": "数字", + "integer-value": "数字值", + "integer-value-required": "整数值必填", + "invalid-integer-value": "整数值无效", + "double": "双精度小数", + "double-value": "双精度小数值", + "double-value-required": "需要双精度值", + "boolean": "布尔值", + "boolean-value": "布尔值", + "false": "假", + "true": "真", + "long": "Long", + "json": "JSON", + "json-value": "JSON值", + "json-value-invalid": "JSON值的格式无效", + "json-value-required": "JSON值必填。" + }, + "version-control": { + "version-control": "版本控制", + "management": "版本控制管理", + "search": "搜索版本", + "branch": "分支", + "default": "默认", + "select-branch": "选择分支", + "branch-required": "分支必填", + "create-entity-version": "创建实体版本", + "version-name": "版本名称", + "version-name-required": "版本名称必填", + "author": "作者", + "export-relations": "导出关联", + "export-attributes": "导出属性", + "export-credentials": "导出凭据", + "entity-versions": "实体版本", + "versions": "版本", + "created-time": "创建时间", + "version-id": "版本ID", + "no-entity-versions-text": "未找到实体版本", + "no-versions-text": "未找到版本", + "copy-full-version-id": "复制完整版本ID", + "create-version": "创建版本", + "creating-version": "请稍候,正在创建版本...", + "nothing-to-commit": "没有要提交的更改", + "restore-version": "还原版本", + "restore-entity-from-version": "从版本 '{{versionName}}' 还原实体", + "restoring-entity-version": "请稍候,正在还原实体版本...", + "load-relations": "加载关联", + "load-attributes": "加载属性", + "load-credentials": "加载凭据", + "compare-with-current": "与当前比较", + "diff-entity-with-version": "与实体版本 '{{versionName}}' 不同", + "previous-difference": "上一个差异", + "next-difference": "下一个差异", + "current": "当前", + "differences": "{ count, plural, 1 {1 个差异} other {# 个差异} }", + "create-entities-version": "创建实体版本", + "default-sync-strategy": "默认同步策略", + "sync-strategy-merge": "合并", + "sync-strategy-overwrite": "覆盖", + "entities-to-export": "导出的实体", + "entities-to-restore": "还原的实体", + "sync-strategy": "同步策略", + "all-entities": "所有实体", + "no-entities-to-export-prompt": "请指定要导出的实体", + "no-entities-to-restore-prompt": "请指定要还原的实体", + "add-entity-type": "添加实体类型", + "remove-all": "全部删除", + "version-create-result": "{ added, plural, 0 {没有实体} 1 {1 个实体} other {# 个实体} } 被添加。
              { modified, plural, 0 {没有实体} 1 {1 个实体} other {# 个实体} } 被修改。
              { removed, plural, 0 {没有实体} 1 {1 个实体} other {# 个实体} } 被删除。", + "remove-other-entities": "删除其他实体", + "find-existing-entity-by-name": "按名称查找现有实体", + "restore-entities-from-version": "从版本 '{{versionName}}' 还原实体", + "restoring-entities-from-version": "请稍候,正在还原实体...", + "no-entities-restored": "未还原任何实体", + "created": "{{created}} 创建", + "updated": "{{updated}} 更新", + "deleted": "{{deleted}} 删除", + "remove-other-entities-confirm-text": "请注意!在还原版本中不存在的当前实体
              将被永久 删除。

              请输入 remove other entities 进行确认。", + "auto-commit-to-branch": "自动提交到 {{ branch }} 分支", + "default-create-entity-version-name": "{{entityName}} 更新", + "sync-strategy-merge-hint": "创建或更新选定的实体,仓库其他实体均不修改。", + "sync-strategy-overwrite-hint": "创建或更新选定的实体,仓库其他实体将被删除。", + "device-credentials-conflict": "无法加载外部ID为 {{entityId}} 的设备
              因为数据库中已存在相同的凭据。
              请考虑禁用还原表单中的 加载凭据 设置。", + "missing-referenced-entity": "无法加载外部ID为 {{sourceEntityId}} 的 {{sourceEntityTypeName}}
              因为它引用了缺失的 {{targetEntityTypeName}} (ID:{{targetEntityId}}).", + "runtime-failed": "失败: {{message}}", + "auto-commit-settings-read-only-hint": "自动提交功能不适用于存储库设置中启用的只读选项。" + }, + "widget": { + "widget-library": "部件库", + "widget-bundle": "部件包", + "all-bundles": "All bundles", + "select-widgets-bundle": "选择部件包", + "management": "管理部件", + "editor": "部件编辑器", + "widget-type-not-found": "加载部件配置出错。
              可能关联的部件已经删除了。", + "widget-type-load-error": "由于以下错误未加载小部件:", + "remove": "删除部件", + "edit": "编辑部件", + "remove-widget-title": "确定要删除 '{{widgetTitle}}'部件吗?", + "remove-widget-text": "确认后,控件和所有相关数据将变得不可恢复。", + "timeseries": "Timeseries", + "search-data": "查找数据", + "no-data-found": "未找到数据", + "latest": "最新值", + "rpc": "控件部件", + "alarm": "告警部件", + "static": "静态部件", + "select-widget-type": "选择窗口部件类型", + "missing-widget-title-error": "部件标题必须指定!", + "widget-saved": "部件已保存", + "unable-to-save-widget-error": "无法保存部件!控件有错误!", + "save": "保存部件", + "saveAs": "部件另存为", + "save-widget-type-as": "部件类型另存为", + "save-widget-type-as-text": "请输入新的部件标题或选择目标部件包", + "toggle-fullscreen": "切换全屏", + "run": "运行部件", + "title": "部件标题", + "title-required": "部件标题必填。", + "type": "部件类型", + "resources": "资源", + "resource-url": "JavaScript/CSS URL", + "resource-is-module": "是否模块", + "remove-resource": "删除资源", + "add-resource": "添加资源", + "html": "HTML", + "tidy": "Tidy", + "css": "CSS", + "settings-schema": "设置模式", + "datakey-settings-schema": "数据键设置模式", + "latest-datakey-settings-schema": "最新数据键设置模式", + "widget-settings": "部件设置", + "description": "描述", + "image-preview": "图片预览", + "settings-form-selector": "设置表单选择器", + "data-key-settings-form-selector": "数据键设置表单选择器", + "latest-data-key-settings-form-selector": "最新数据键设置表单选择器", + "javascript": "Javascript", + "js": "JS", + "remove-widget-type-title": "确定要删除部件类型 '{{widgetName}}'吗?", + "remove-widget-type-text": "确认后,窗口部件类型和所有相关数据将不可恢复。", + "remove-widget-type": "删除部件类型", + "add-widget-type": "添加新的部件类型", + "widget-type-load-failed-error": "无法加载部件类型!", + "widget-template-load-failed-error": "无法加载部件模板!", + "add": "添加部件", + "undo": "撤消部件更改", + "export": "导出部件", + "no-data": "小部件上没有要显示的数据", + "data-overflow": "部件显示 {{count}}之外{{total}} 实体", + "alarm-data-overflow": "窗口部件显示{{allowedEntities}}(最大允许的)实的警报{{totalEntities}}实体", + "search": "搜索部件", + "filter": "部件类型过滤", + "loading-widgets": "加载部件..." + }, "widget-action": { - "action-cell-button": "动作单元格按钮", - "element-click": "点击HTML元素时", - "marker-click": "点击标记时", - "node-selected": "选择节点时", - "pie-slice-click": "点击切片时", - "polygon-click": "单击多边形", - "row-click": "点击行时", - "row-double-click": "双击行时", - "tooltip-tag-action": "Tooltip tag action" - } - }, - "customer": { - "add": "添加客户", - "add-customer-text": "添加新客户", - "assets": "客户资产", - "copyId": "复制客户ID", - "customer": "客户", - "customer-details": "客户详情", - "customer-required": "客户必填", - "customers": "客户", - "dashboard": "客户仪表板", - "dashboards": "客户仪表板", - "default-customer": "默认客户", - "default-customer-required": "为了调试租户级别上的仪表板,需要默认客户。", - "delete": "删除此客户", - "delete-customer-text": "请注意:确认后,客户及其所有相关数据将不可恢复。", - "delete-customer-title": "您确定要删除客户'{{customerTitle}}'吗?", - "delete-customers-action-title": "删除 { count, plural, 1 {# 个客户} other {# 个客户} }", - "delete-customers-text": "请注意:确认后,所有选定的客户将被删除,所有相关数据将不可恢复。", - "delete-customers-title": "您确定要删除 { count, plural, 1 {# 个客户} other {# 个客户} }吗?", - "description": "说明", - "details": "详情", - "devices": "客户设备", - "edges": "客户边缘实例", - "entity-views": "客户实体视图", - "events": "事件", - "idCopiedMessage": "客户ID已复制到粘贴板", - "manage-assets": "管理资产", - "manage-customer-assets": "管理客户资产", - "manage-customer-dashboards": "管理客户仪表板", - "manage-customer-devices": "管理客户设备", - "manage-customer-edges": "管理客户边缘", - "manage-customer-users": "管理客户用户", - "manage-dashboards": "管理仪表板", - "manage-devices": "管理设备", - "manage-edges": "管理边缘", - "manage-public-assets": "管理公共资产", - "manage-public-dashboards": "管理公共仪表板", - "manage-public-devices": "管理公共设备", - "manage-public-edges": "管理公共边缘", - "manage-users": "管理用户", - "management": "客户管理", - "no-customers-matching": "没有找到匹配 '{{entity}}' 的客户。", - "no-customers-text": "没有找到客户", - "public-assets": "公共资产", - "public-dashboards": "公共仪表板", - "public-devices": "公共设备", - "public-entity-views": "公共实体视图", - "public-edges": "公共边缘", - "search": "查找客户", - "select-customer": "选择客户", - "select-default-customer": "选择默认的客户", - "selected-customers": "已选择 { count, plural, 1 {# 个客户} other {# 个客户} }", - "title": "标题", - "title-required": "标题必填。" - }, - "dashboard": { - "add": "添加仪表板", - "add-dashboard-text": "添加新的仪表板", - "add-state": "添加仪表板状态", - "add-widget": "添加新的部件", - "alias-resolution-error-title": "仪表板别名配置错误", - "assign-dashboard-to-customer": "将仪表板分配给客户", - "assign-dashboard-to-customer-text": "请选择要分配给客户的仪表板", - "assign-dashboard-to-edge": "将仪表板分配给边缘", - "assign-dashboard-to-edge-text": "请选择要分配给边缘的仪表板", - "assign-dashboard-to-edge-title": "将仪表板分配给边缘", - "assign-dashboards": "分配仪表板", - "assign-dashboards-text": "分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", - "assign-new-dashboard": "分配新的仪表板", - "assign-to-customer": "分配给客户", - "assign-to-customer-text": "请选择客户分配仪表板", - "assign-to-customers": "将仪表板分配给客户", - "assign-to-customers-text": "请选择客户指定仪表板", - "assigned-customers": "已分配的客户", - "assignedToCustomer": "分配给客户", - "assignedToCustomers": "分配给客户", - "autofill-height": "自动填充布局高度", - "background-color": "背景颜色", - "background-image": "背景图片", - "background-size-mode": "背景大小模式", - "cannot-upload-file": "无法上传文件", - "close-toolbar": "关闭工具栏", - "columns-count": "列数", - "columns-count-required": "需要列数。", - "configuration-error": "配置错误", - "copy-public-link": "复制公共链接", - "create-new": "创建新的仪表板", - "create-new-dashboard": "创建新的仪表板", - "create-new-widget": "创建新部件", - "dashboard": "仪表板", - "dashboard-details": "仪表板详情", - "dashboard-file": "仪表板文件", - "dashboard-import-missing-aliases-title": "配置导入仪表板使用的别名", - "dashboard-logo-image": "仪表板 Logo 图片", - "dashboard-required": "仪表板必填。", - "dashboards": "仪表板库", - "delete": "删除仪表板", - "delete-dashboard-text": "请注意:确认后仪表板及其所有相关数据将不可恢复。", - "delete-dashboard-title": "您确定要删除仪表板 '{{dashboardTitle}}'吗?", - "delete-dashboards": "删除仪表板", - "delete-dashboards-action-title": "删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", - "delete-dashboards-text": "请注意:确认后所有选定的仪表板将被删除,所有相关数据将不可恢复。", - "delete-dashboards-title": "确定要删除 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }吗?", - "delete-state": "删除仪表板状态", - "delete-state-text": "确定要删除仪表板状态 '{{stateName}}' 吗?", - "delete-state-title": "删除仪表板状态", - "description": "说明", - "details": "详情", - "display-dashboard-export": "显示导出", - "display-dashboard-logo": "在仪表板全屏模式下显示 Logo", - "display-dashboard-timewindow": "显示时间窗口", - "display-dashboards-selection": "显示仪表板选项", - "display-entities-selection": "显示实体选项", - "display-filters": "显示筛选器", - "display-title": "显示仪表板标题", - "drop-image": "拖拽图像或单击以选择要上传的文件。", - "maximum-upload-file-size": "最大上传文件大小: {{ size }}", - "edit-state": "仪表板状态编辑", - "export": "导出仪表板", - "export-failed-error": "无法导出仪表板: {{error}}", - "hide-details": "隐藏详情", - "home-dashboard": "首页仪表板", - "home-dashboard-hide-toolbar": "隐藏首页仪表板工具栏", - "horizontal-margin": "水平边距", - "horizontal-margin-required": "需要水平边距值。", - "import": "导入仪表板", - "import-widget": "导入部件", - "invalid-aliases-config": "无法找到与某些别名筛选器匹配的任何设备。
              请联系您的管理员以解决此问题。", - "invalid-dashboard-file-error": "无法导入仪表板: 仪表板数据结构无效。", - "invalid-widget-file-error": "无法导入窗口部件: 窗口部件数据结构无效。", - "is-root-state": "根状态", - "make-private": "仪表板设为私有", - "make-private-dashboard": "仪表板设为私有", - "make-private-dashboard-text": "确认后,仪表板将被设为私有,不能被其他人访问。", - "make-private-dashboard-title": "您确定要将仪表板 '{{dashboardTitle}}' 设为私有吗?", - "make-public": "仪表板设为公开", - "manage-assigned-customers": "管理已分配的客户", - "manage-states": "仪表板状态管理", - "management": "仪表板管理", - "margin-required": "边距值必填。", - "max-columns-count-message": "只允许最多1000列", - "max-horizontal-margin-message": "只允许50作为最大水平边距值。", - "max-margin-message": "仅允许50作为最大边距值。", - "max-mobile-row-height-message": "移动端行高距最多200px。", - "max-vertical-margin-message": "只允许50作为最大垂直边距值。", - "min-columns-count-message": "只允许最少10列", - "min-horizontal-margin-message": "只允许0作为最小水平边距值。", - "min-margin-message": "最小边距值只允许为0。", - "min-mobile-row-height-message": "移动端行高距至少5px。", - "min-vertical-margin-message": "只允许0作为最小垂直边距值。", - "mobile-layout": "移动端布局设置", - "mobile-row-height": "移动端行高距(px)", - "mobile-row-height-required": "移动端行高距必填。", - "new-dashboard-title": "新仪表板标题", - "no-dashboards-matching": "找不到符合 '{{entity}}' 的仪表板。", - "no-dashboards-text": "没有找到仪表板", - "no-image": "无图像选择", - "no-states-text": "找不到状态", - "no-widgets": "没有配置部件", - "open-dashboard": "打开仪表板", - "open-toolbar": "打开仪表板工具栏", - "public": "公开", - "public-dashboard-notice": "提示: 不要忘记将相关设备公开以访问其数据。", - "public-dashboard-text": "你的仪表板 {{dashboardTitle}} 已被公开,可通过如下 链接访问:", - "public-dashboard-title": "仪表板现已公开", - "public-link": "公共链接", - "public-link-copied-message": "仪表板的公共链接已被复制到剪贴板", - "search": "查找仪表板", - "search-states": "仪表板状态检索", - "select-dashboard": "选择仪表板", - "select-devices": "选择设备", - "select-existing": "选择现有仪表板", - "select-state": "选择目标状态", - "select-widget-subtitle": "可用的部件类型列表", - "select-widget-title": "选择部件", - "select-widget-value": "{{title}}: 选择部件", - "selected-dashboards": "已选择 { count, plural, 1 {# 个仪表盘} other {# 个仪表盘} }", - "selected-states": "已选择 { count, plural, 1 {# 个仪表板状态} other {# 个仪表板状态} }", - "set-background": "设置背景", - "settings": "设置", - "show-details": "显示详情", - "socialshare-text": "'{{dashboardTitle}}' 由Thingsboard提供支持", - "socialshare-title": "'{{dashboardTitle}}' 由Thingsboard提供支持", - "state": "仪表板状态", - "state-controller": "状态控制", - "state-id": "状态ID", - "state-id-exists": "仪表板状态ID已经存在。", - "state-id-required": "仪表板状态ID必填。", - "state-name": "名称", - "state-name-required": "仪表板状态名必填。", - "states": "仪表板状态", - "title": "标题", - "image": "仪表板图片", - "mobile-app-settings": "移动应用设置", - "mobile-order": "移动应用中的仪表板订单", - "mobile-hide": "在移动应用中隐藏仪表板", - "title-color": "标题颜色", - "title-required": "标题必填。", - "toolbar-always-open": "工具栏常驻", - "unassign-dashboard": "取消分配仪表板", - "unassign-dashboard-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", - "unassign-dashboard-text": "确认后,面板将被取消分配,客户将无法访问。", - "unassign-dashboard-title": "您确定要取消分配仪表板 '{{dashboardTitle}}'吗?", - "unassign-dashboards": "取消分配仪表板", - "unassign-dashboards-action-text": "取消分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", - "unassign-dashboards-action-title": "取消分配此客户 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", - "unassign-dashboards-text": "确认后,所有选定的仪表板将被取消分配,客户将无法访问。", - "unassign-dashboards-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", - "unassign-dashboards-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", - "unassign-dashboards-from-edge-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", - "unassign-from-customer": "取消分配客户", - "unassign-from-customers": "客户未分配仪表板", - "unassign-from-customers-text": "请选择从仪表板中取消分配的客户", - "vertical-margin": "垂直边距", - "vertical-margin-required": "需要垂直边距值。", - "view-dashboards": "查看仪表板", - "widget-file": "部件文件", - "widget-import-missing-aliases-title": "配置导入的窗口部件使用的别名", - "widgets-margins": "部件间边距" - }, - "datakey": { - "advanced": "高级", - "alarm": "报警字段", - "alarm-fields-required": "警告字段必填。", - "alarm-fields-timeseries-or-attributes-required": "报警字段或实体 Timeseries/属性必填。", - "attributes": "属性", - "color": "颜色", - "configuration": "数据键配置", - "data-generation-func": "数据生成功能", - "decimals": "小数位数", - "entity-field": "实体字段", - "function-types": "函数类型", - "function-types-required": "需要函数类型。", - "label": "标签", - "maximum-function-types": "最多允许 { count, plural, 1 {# 个函数类型} other {# 个函数类型} }", - "maximum-timeseries-or-attributes": "最多允许 { count, plural, 1 {# 个 timeseries/属性。} other {# 个 timeseries/属性。} }", - "prev-orig-value-description": "先前的原始值;", - "prev-value-description": "上一次函数调用的结果;", - "settings": "设置", - "time-description": "当前值的时间戳;", - "time-prev-description": "上一个值的时间戳;", - "timeseries": "Timeseries", - "timeseries-or-attributes-required": "实体 Timeseries/属性必填。", - "timeseries-required": "实体 Timeseries 必填。", - "units": "单位符号", - "use-data-post-processing-func": "使用数据后处理功能", - "value-description": "当前值;" - }, - "datasource": { - "add-datasource-prompt": "请添加数据源", - "label": "标签", - "name": "名称", - "type": "数据源类型" - }, - "datetime": { - "date-from": "日期从", - "date-to": "日期到", - "time-from": "时间从", - "time-to": "时间到" - }, - "details": { - "details": "详情", - "edit-json": "编辑JSON", - "edit-mode": "编辑模式", - "toggle-edit-mode": "切换编辑模式" - }, - "device-profile": { - "add": "添加设备配置", - "add-alarm-rule": "添加报警规则", - "add-alarm-rule-details": "详情模板:", - "add-clear-alarm-rule": "添加清除条件", - "add-create-alarm-rule": "添加创建条件", - "add-create-alarm-rule-prompt": "请添加创建报警规则", - "advanced-settings": "高级设置", - "alarm-details": "报警详细信息", - "alarm-rule-condition": "报警规则条件", - "alarm-rule-details": "详情", - "alarm-rule-relation-types-list": "要传递的关联类型", - "alarm-rule-relation-types-list-hint": "如果未选择传递关联类型,则将不按关联类型过滤而传递报警。", - "alarm-rules": "报警规则", - "alarm-rules-with-count": "报警规则 ({{count}})", - "alarm-severity-required": "报警严重级别必填。", - "alarm-type": "报警类型", - "alarm-type-required": "报警类型必填。", - "alarm-type-unique": "警报类型在设备配置警报规则中必须唯一。", - "all-device-profiles": "全部", - "attributes-proto-schema": "Attributes proto schema", - "attributes-proto-schema-required": "Attributes proto schema 必填。", - "attributes-topic-filter": "Attributes topic filter", - "attributes-topic-filter-required": "Attributes topic 筛选器必填。", - "clear-alarm-rule": "清除报警规则", - "coap-device-payload-type": "CoAP 设备消息 Payload", - "coap-device-type": "CoAP 设备类型", - "coap-device-type-default": "默认", - "coap-device-type-efento": "Efento NB-IoT", - "coap-device-type-required": "CoAP 设备类型必填。", - "condition": "条件", - "condition-duration": "条件持续时间", - "condition-duration-time-unit": "时间单位", - "condition-duration-time-unit-required": "时间单位必填。", - "condition-duration-value": "持续时间值", - "condition-duration-value-pattern": "持续时间值应为整数。", - "condition-duration-value-range": "持续时间值应在1到2147483647之间。", - "condition-duration-value-required": "持续时间值必填。", - "condition-during": "在 {{during}} 期间", - "condition-repeat-times": "重复 { count, plural, 1 {# 次} other {# 次} }", - "condition-repeating-value": "事件计数", - "condition-repeating-value-pattern": "事件计数应为整数。", - "condition-repeating-value-range": "事件计数应在1到2147483647之间。", - "condition-repeating-value-required": "事件计数值必填。", - "condition-type": "条件类型", - "condition-type-duration": "持续时间", - "condition-type-repeating": "重复", - "condition-type-required": "条件类型必填。", - "condition-type-simple": "简单", - "copy-provision-key": "复制预配置密钥名", - "copy-provision-secret": "复制预配置密钥", - "copyId": "复制设备配置 ID", - "create-alarm-pattern": "创建 {{alarmType}} 报警", - "create-alarm-rules": "创建报警规则", - "create-device-profile": "创建设备配置", - "create-new-device-profile": "创建一个新的!", - "default": "默认", - "default-rule-chain": "默认规则链", - "mobile-dashboard": "移动仪表板", - "mobile-dashboard-hint": "被移动应用用作设备详情仪表板", - "delete": "删除设备配置", - "delete-device-profile-text": "请注意:确认后设备配置和所有相关数据将不可恢复。", - "delete-device-profile-title": "是否确实要删除设备配置 '{{deviceProfileName}}'?", - "delete-device-profiles-text": "请注意:确认后,所有选定的设备配置将被删除,所有相关数据将不可恢复。", - "delete-device-profiles-title": "确定要删除 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }?", - "description": "说明", - "device-profile": "设备配置", - "device-profile-details": "设备配置详情", - "device-profile-file": "设备配置文件", - "device-profile-required": "设备配置必填", - "device-profiles": "设备配置", - "device-provisioning": "设备预配置", - "edit": "编辑设备配置", - "edit-alarm-rule": "编辑报警规则", - "edit-alarm-rule-condition": "编辑报警规则条件", - "edit-schedule": "编辑报警日程表", - "enter-alarm-rule-condition-prompt": "请添加报警规则条件", - "export": "导出设备配置", - "export-failed-error": "无法导出设备配置文件: {{error}}", - "idCopiedMessage": "设备配置 ID 已复制到剪贴板", - "import": "导入设备配置", - "invalid-device-profile-file-error": "无法导入设备配置文件:无效的设备配置文件数据结构。", - "mqtt-device-payload-type": "MQTT 设备 Payload", - "mqtt-device-payload-type-json": "JSON", - "mqtt-device-payload-type-proto": "Protobuf", - "mqtt-device-topic-filters": "MQTT 设备 Topic 筛选器", - "mqtt-device-topic-filters-unique": "MQTT设备 Topic 筛选器必须唯一。", - "mqtt-payload-type-required": "Payload 类型必填。", - "multi-level-wildcards-hint": "[#]可以替换 topic filter 本身,并且必须是 topic 的最后一个符号。例如:# or v1/devices/me/#。", - "name": "名称", - "name-required": "名称是必需的。", - "new-device-profile-name": "设备配置名称", - "new-device-profile-name-required": "设备配置名称必填。", - "no-alarm-rules": "未配置报警规则", - "no-clear-alarm-rule": "未配置明确条件", - "no-create-alarm-rules": "未配置创建条件", - "no-device-profiles-found": "找不到设备配置。", - "no-device-profiles-matching": "找不到与 '{{entity}}' 匹配的设备配置。", - "no-device-profiles-text": "找不到设备配置", - "not-valid-multi-character": "多级通配符的使用无效", - "not-valid-pattern-topic-filter": "无效的 Topic 筛选器模式", - "not-valid-single-character": "单级通配符的使用无效", - "profile-configuration": "配置", - "propagate-alarm": "传递警报", - "provision-device-key": "预配置设备密钥名", - "provision-device-key-required": "预配置设备密钥名必填。", - "provision-device-secret": "预配置设备密钥", - "provision-device-secret-required": "预配置设备密钥必填。", - "provision-key-copied-message": "预配置密钥名已复制到剪贴板", - "provision-secret-copied-message": "预配置密钥已复制到剪贴板", - "provision-strategy": "预配置策略", - "provision-strategy-check-pre-provisioned": "检查预配置的设备", - "provision-strategy-created-new": "允许创建新设备", - "provision-strategy-disabled": "禁用", - "provision-strategy-required": "预配置策略必填。", - "rpc-request-proto-schema": "RPC 请求 proto schema", - "rpc-request-proto-schema-hint": "RPC 请求消息应始终包含字段:string method = 1; int32 requestId = 2; 和params = 3的任何数据类型。", - "rpc-request-proto-schema-required": "RPC 请求 proto schema 必填。", - "rpc-response-proto-schema": "RPC 响应 proto schema", - "rpc-response-proto-schema-required": "RPC 响应 proto schema 必填。", - "rpc-response-topic-filter": "RPC响应 Topic 筛选器", - "rpc-response-topic-filter-required": "RPC响应 Topic 筛选器必填。", - "schedule": "启用规则:", - "schedule-any-time": "始终启用", - "schedule-custom": "自定义启用", - "schedule-day": { - "friday": "星期五", - "monday": "星期一", - "saturday": "星期六", - "sunday": "星期日", - "thursday": "星期四", - "tuesday": "星期二", - "wednesday": "星期三" - }, - "schedule-days": "天", - "schedule-days-of-week-required": "每周至少选择一天。", - "schedule-specific-time": "定时启用", - "schedule-time": "时间", - "schedule-time-from": "从", - "schedule-time-to": "到", - "schedule-type": "计划程序类型", - "schedule-type-required": "计划类型必填。", - "search": "查找设备配置", - "select-alarm-severity": "选择报警严重性", - "select-queue-hint": "从下拉列表中选择或添加自定义名称。", - "selected-device-profiles": "已选择 { count, plural, 1 {# 个设备配置} other {# 个设备配置} }", - "set-default": "设为默认设备配置", - "set-default-device-profile-text": "确认后,设备配置将被标记为默认,并将用于未指定配置的新设备。", - "set-default-device-profile-title": "确实要将设备配置 '{{deviceProfileName}}' 设为默认值吗?", - "single-level-wildcards-hint": "[+] is suitable for any topic filter level。例如:v1/devices/+/telemetry or +/devices/+/attributes。", - "support-level-wildcards": "支持单[+]和多级[#]通配符。", - "telemetry-proto-schema": "遥测数据 proto schema", - "telemetry-proto-schema-required": "遥测数据 proto schema 必填。", - "telemetry-topic-filter": "遥测数据 topic 筛选器", - "telemetry-topic-filter-required": "遥测数据 topic 筛选器必填。", - "transport-configuration": "传输配置", - "transport-type": "传输方式", - "transport-type-coap-hint": "启用高级 CoAP 传输设置", - "transport-type-default": "默认", - "transport-type-default-hint": "支持基本MQTT、HTTP和CoAP传输", - "transport-type-lwm2m": "LWM2M", - "transport-type-lwm2m-hint": "LWM2M传输类型", - "transport-type-mqtt": "MQTT", - "transport-type-mqtt-hint": "启用高级MQTT传输设置", - "transport-type-required": "传输方式必填。", - "transport-type-snmp-hint": "指定 SNMP 传输配置", - "type": "配置类型", - "type-default": "默认", - "type-required": "配置类型必填。", - "image": "设备配置图片" - }, - "device": { - "access-token": "访问令牌", - "access-token-invalid": "访问令牌长度必须为1到32个字符。", - "access-token-required": "访问令牌必填", - "accessTokenCopiedMessage": "设备访问令牌已复制到剪贴板", - "add": "添加设备", - "add-alias": "添加设备别名", - "add-device-text": "添加新设备", - "alias": "别名", - "alias-required": "设备别名必填。", - "aliases": "设备别名", - "any-device": "任意设备", - "assign-device-to-customer": "将设备分配给客户", - "assign-device-to-customer-text": "请选择要分配给客户的设备", - "assign-device-to-edge-text":"请选择要分配给边缘的设备", - "assign-device-to-edge-title": "将设备分配给边缘", - "assign-devices": "分配设备", - "assign-devices-text": "将 {count,plural,1 {# 个设备} other {# 个设备} }分配给客户", - "assign-new-device": "分配新设备", - "assign-to-customer": "分配给客户", - "assign-to-customer-text": "请选择客户分配设备", - "assignedToCustomer": "分配给客户", - "client-id": "客户端ID", - "client-id-or-user-name-necessary": "客户端ID和/或用户名是必需的", - "client-id-pattern": "包含无效字符。", - "configure-alias": "配置 '{{alias}}' 别名", - "copy-mqtt-authentication": "复制MQTT凭据", - "copyAccessToken": "复制访问令牌", - "copyId": "复制设备ID", - "create-new-alias": "创建一个新的!", - "create-new-key": "创建一个新的!", - "credentials": "凭据", - "credentials-type": "凭据类型", - "delete": "删除设备", - "delete-device-text": "请注意:确认后设备及其所有相关数据将不可恢复。", - "delete-device-title": "您确定要删除设备的{{deviceName}}吗?", - "delete-devices": "删除设备", - "delete-devices-action-title": "删除 {count,plural,1 {# 个设备} other {# 个设备} }", - "delete-devices-text": "请注意:确认后所有选定的设备将被删除,所有相关数据将不可恢复。", - "delete-devices-title": "确定要删除{count,plural,1 {# 个设备} other {# 个设备} } 吗?", - "description": "说明", - "details": "详情", - "device": "设备", - "device-alias": "设备别名", - "device-configuration": "设备配置", - "device-credentials": "设备凭据", - "device-details": "设备详细信息", - "device-file": "设备文件", - "device-list": "设备列表", - "device-list-empty": "没有被选中的设备", - "device-name-filter-no-device-matched": "找不到以'{{device}}' 开头的设备。", - "device-name-filter-required": "设备名称筛选器必填。", - "device-public": "设备公开", - "device-required": "设备必填", - "device-type": "设备类型", - "device-type-list-empty": "未选择设备类型", - "device-type-required": "设备类型必填。", - "device-types": "设备类型", - "devices": "设备", - "duplicate-alias-error": "找到重复别名 '{{alias}}'。
              设备别名必须是唯一的。", - "enter-device-type": "输入设备类型", - "events": "事件", - "idCopiedMessage": "设备ID已复制到剪贴板", - "import": "导入设备", - "is-gateway": "是否网关", - "label": "标签", - "make-private": "私有", - "make-private-device-text": "确认后,设备及其所有数据将被设为私有,不被其他人访问。", - "make-private-device-title": "您确定要将设备 '{{deviceName}}' 设为私有吗?", - "make-public": "公开", - "make-public-device-text": "确认后,设备及其所有数据将被设为公开并可被其他人访问。", - "make-public-device-title": "您确定要将设备 '{{deviceName}}' 设为公开吗?", - "manage-credentials": "管理凭据", - "management": "设备管理", - "mqtt-authentication-copied-message": "设备MQTT身份验证已复制到剪贴板", - "name": "名称", - "name-required": "名称必填。", - "name-starts-with": "名称前缀", - "no-alias-matching": "'{{alias}}' 没有找到。", - "no-aliases-found": "找不到别名。", - "no-device-types-matching": "没有找到符合 '{{entitySubtype}}' 的设备类型。", - "no-devices-matching": "找不到与 '{{entity}}' 匹配的设备。", - "no-devices-text": "找不到设备", - "no-key-matching": "'{{key}}' 没有找到。", - "no-keys-found": "找不到密钥。", - "overwrite-activity-time": "覆盖已连接设备的活动时间", - "password": "密码", - "public": "公开", - "remove-alias": "删除设备别名", - "search": "查找设备", - "secret": "密钥", - "secret-required": "密钥必填", - "select-device": "选择设备", - "select-device-type": "选择设备类型", - "selected-devices": "已选择 { count, plural, 1 {# 个设备} other {# 个设备} }", - "transport-configuration": "传输配置", - "unable-delete-device-alias-text": "设备别名 '{{deviceAlias}}' 不能够被删除,因为它被下列部件所使用:
              {{widgetsList}}", - "unable-delete-device-alias-title": "无法删除设备别名", - "unassign-device": "取消分配设备", - "unassign-device-text": "确认后,设备将被取消分配,客户将无法访问。", - "unassign-device-title": "您确定要取消分配设备 '{{deviceName}}'?", - "unassign-device-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", - "unassign-device-from-edge-title": "您确定要取消分配设备 '{{deviceName}}'?", - "unassign-devices": "取消分配设备", - "unassign-devices-action-title": "取消分配此客户 {count,plural,1 {# 个设备} other {# 个设备} }", - "unassign-devices-from-edge": "取消分配边缘", - "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", - "unassign-devices-from-edge-title": "您确定要取消分配 { count, plural, 1 {1个 设备} other {# 个设备} } 吗?", - "unassign-devices-text": "确认后,所有选定的设备将被取消分配,并且客户将无法访问。", - "unassign-devices-title": "确定要取消分配 {count,plural,1 {# 个设备} other {# 个设备} } 吗?", - "unassign-from-customer": "取消分配客户", - "use-device-name-filter": "使用筛选器", - "user-name": "用户名", - "user-name-required": "用户名必填。", - "view-credentials": "查看凭据", - "view-devices": "查看设备", - "wizard": { - "add-credentials": "添加凭据", - "customer-to-assign-device": "客户分配设备", - "device-details": "设备详细信息", - "device-wizard": "设备向导", - "existing-device-profile": "选择已有设备配置", - "new-device-profile": "新建设备配置", - "specific-configuration": "指定配置" - } - }, - "dialog": { - "close": "关闭对话框" - }, - "direction": { - "column": "列", - "row": "排" - }, - "edge": { - "add": "增加边缘", - "add-edge-text": "增加新的边缘", - "any-edge": "任何边缘", - "assets": "边缘资产", - "assign-edge-to-customer": "分配边缘给客户", - "assign-edge-to-customer-text": "请选择需要分配给边缘的客户", - "assign-new-edge": "分配新边缘", - "assign-to-customer": "分配给客户", - "assign-to-customer-text": "请选择需要分配给边缘的客户", - "assigned-to-customer": "分配给: {{customerTitle}}", - "assignedToCustomer": "分配给客户", - "copy-edge-key": "复制边缘键", - "copy-edge-secret": "复制边缘密钥", - "copy-id": "复制边缘编号", - "dashboard": "边缘仪表板", - "dashboards": "边缘仪表板", - "delete": "删除边缘", - "delete-edge-text": "当心, 确认后,边缘以及所有关联数据将不可恢复。", - "delete-edge-title": "您确定删除边缘 '{{edgeName}}'?", - "delete-edges-text": "当心, 确认后,选定的边缘以及所有关联数据将不可恢复。", - "delete-edges-title": "您确认删除边缘 { count, plural, 1 {1 个边缘} other {# 个边缘} }?", - "deployed": "已部署", - "description": "描述", - "details": "详情", - "devices": "边缘设备", - "downlinks": "下行", - "edge": "边缘", - "edge-assets": "边缘资产", - "edge-dashboards": "边缘仪表板", - "edge-details": "边缘详情", - "edge-devices": "边缘设备", - "edge-entity-views": "边缘实体视图", - "edge-file": "边缘文件", - "edge-instances": "边缘实例", - "edge-key": "边缘键", - "edge-key-copied-message": "边缘键已经被复制到剪切板", - "edge-public": "边缘公开", - "edge-required": "边缘必填。", - "edge-rulechains": "边缘规则链", - "edge-secret": "边缘密钥", - "edge-secret-copied-message": "边缘密钥已经被复制到剪切板", - "edge-type": "边缘类型", - "edge-type-list-empty": "没有选择边缘类型。", - "edge-type-required": "边缘类型必填。", - "edge-types": "边缘类型", - "enter-edge-type": "输入边缘类型", - "entity-id": "实体编号", - "entity-views": "边缘实体视图", - "event-action": "事件行动", - "events": "事件", - "id-copied-message": "边缘编号已经复制到剪切板", - "import": "导入边缘", - "label": "标签", - "label-max-length": "标签长度必须少于256个字符", - "load-entity-error": "加载数据失败,实体已经被删除。", - "make-private": "私有", - "make-private-edge-text": "确认后,边缘及其所有数据将被设为私有,不被其他人访问。", - "make-private-edge-title": "您确定要将边缘 '{{edgeName}}' 设为私有?", - "make-public": "公开", - "make-public-edge-text": "确认后,边缘及其所有数据将被设为公开并可被其他人访问。", - "make-public-edge-title": "您确定要将边缘 '{{edgeName}}' 设为公开吗?", - "management": "边缘管理", - "missing-related-rule-chains-text": "分配给边缘的规则链使用规则节点将消息转发给未分配给当前边缘的规则链。

              缺少的规则链列表:
              {{missingRuleChains}}", - "missing-related-rule-chains-title": "边缘缺少关联规则链", - "name": "名称", - "name-max-length": "名称长度必须少于256个字符", - "name-required": "名称必填。", - "name-starts-with": "边缘名称前缀", - "no-downlinks-prompt": "没有找到下行", - "no-edge-types-matching": "没有找到匹配的边缘类型 '{{entitySubtype}}'。", - "no-edges-matching": "没有找到匹配的边缘 '{{entity}}'。", - "no-edges-text": "没有找到边缘", - "pending": "待定", - "public": "公开", - "rulechain-templates": "规则链模版", - "rulechains": "规则链", - "search": "搜索边缘", - "select-edge-type": "选择边缘类型", - "selected-edges": "{ count, plural, 1 {1 个边缘} other {# 个边缘} } 被选中", - "sync": "同步边缘", - "sync-process-started-successfully": "同步处理开始成功!", - "type-max-length": "类型长度必须少于256个字符", - "unassign-edge-text": "确定后,边缘将被取消分配,并且客户将无法访问。", - "unassign-edge-title": "您确定取消分配边缘 '{{edgeName}}'?", - "unassign-edges-text": "确定后,所有选定的边缘将被取消分配,并且客户将无法访问。", - "unassign-edges-title": "您确定要取消分配 {count,plural,1 {1 个边缘} other {# 个边缘} } 吗?", - "unassign-from-customer": "取消分配客户", - "unassign-from-edge": "取消分配边缘", - "widget-datasource-error": "组件只支持边缘实体数据源" - }, - "edge-event": { - "action-type-added": "增加", - "action-type-alarm-ack": "警告确认", - "action-type-alarm-clear": "警告清除", - "action-type-assigned-to-customer": "分配给客户", - "action-type-assigned-to-edge": "分配给边缘", - "action-type-attributes-deleted": "属性删除", - "action-type-attributes-updated": "属性更新", - "action-type-credentials-request": "认证请求", - "action-type-credentials-updated": "认证更新", - "action-type-deleted": "删除", - "action-type-entity-merge-request": "实体合并请求", - "action-type-post-attributes": "推送属性", - "action-type-relation-add-or-update": "关联增加或更新", - "action-type-relation-deleted": "关联删除", - "action-type-rpc-call": "RPC调用", - "action-type-timeseries-updated": "时序更新", - "action-type-unassigned-from-customer": "取消分配客户", - "action-type-unassigned-from-edge": "取消分配边缘", - "action-type-updated": "更新", - "type-admin-settings": "管理员设置", - "type-alarm": "告警", - "type-asset": "资产", - "type-customer": "客户", - "type-dashboard": "仪表板", - "type-device": "设备", - "type-device-profile": "设备概要", - "type-edge": "边缘", - "type-entity-view": "实体视图", - "type-relation": "关联", - "type-rule-chain": "规则链", - "type-rule-chain-metadata": "规则链元数据", - "type-user": "用户", - "type-widgets-bundle": "部件包", - "type-widgets-type": "部件类型" - }, - "entity-field": { - "address": "地址", - "address2": "地址2", - "city": "城市", - "country": "国家", - "created-time": "创建时间", - "email": "电子邮件", - "first-name": "名字", - "label": "标签", - "last-name": "姓", - "name": "名称", - "phone": "电话", - "state": "省/州", - "title": "标题", - "type": "类型", - "zip": "邮政编码" - }, - "entity-view": { - "add": "添加实体视图", - "add-alias": "添加实体视图别名", - "add-entity-view-text": "添加新实体视图", - "alias": "别名", - "alias-required": "实体视图别名必填。", - "aliases": "实体视图别名", - "any-entity-view": "任何实体视图", - "assign-entity-view-to-customer": "将实体视图分配给客户", - "assign-entity-view-to-customer-text": "请选择要分配给客户的实体视图", - "assign-entity-view-to-edge": "将实体视图分配给边缘", - "assign-entity-view-to-edge-text": "请选择要分配给边缘的实体视图", - "assign-entity-view-to-edge-title": "将实体视图分配给边缘", - "assign-entity-views": "分配实体视图", - "assign-entity-views-text": "分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 给客户", - "assign-new-entity-view": "分配新实体视图", - "assign-to-customer": "分配给客户", - "assign-to-customer-text": "请选择客户分配实体视图", - "assignedToCustomer": "分配给客户", - "attributes-propagation": "属性传播", - "attributes-propagation-hint": "每次保存或更新这个实体视图时,实体视图将自动从目标实体复制指定的属性。由于性能原因,目标实体属性不会在每次属性更改时传递到实体视图。您可以通过配置\"copy to view\"规则链中的规则节点,并将\"Post attributes\"和\"attributes Updated\"消息链接到新规则节点,从而启用自动传递。", - "client-attributes": "客户端属性", - "client-attributes-placeholder": "客户端属性", - "configure-alias": "配置 '{{alias}}' 别名", - "copyId": "复制实体视图ID", - "create-new-alias": "创建一个新的!", - "create-new-key": "创建一个新的!", - "created-time": "创建时间", - "date-limits": "日期限制", - "delete": "删除实体视图", - "delete-entity-view-text": "请注意:确认后实体视图及其所有相关数据将不可恢复。", - "delete-entity-view-title": "确定要删除实体视图 '{{entityViewName}}'?", - "delete-entity-views": "删除实体视图", - "delete-entity-views-action-title": "删除 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", - "delete-entity-views-text": "请注意:确认后,所有选定的实体视图将被删除,所有相关的数据将变得不可恢复。", - "delete-entity-views-title": "确定要删除 { count, plural, 1 {# 实体视图} other {# 实体视图} }?", - "description": "说明", - "details": "详情", - "duplicate-alias-error": "找到重复别名 '{{alias}}'。
              实体视图别名必须是唯一的。", - "end-date": "结束日期", - "end-ts": "结束时间", - "enter-entity-view-type": "输入实体视图类型", - "entity-view": "实体视图", - "entity-view-alias": "实体视图别名", - "entity-view-details": "实体视图详细信息", - "entity-view-list": "实体视图列表", - "entity-view-list-empty": "没有被选中的实体视图", - "entity-view-name-filter-no-entity-view-matched": "找不到以'{{entityView}}' 开头的实体视图。", - "entity-view-name-filter-required": "实体视图名称筛选器必填。", - "entity-view-public": "实体视图是公共的", - "entity-view-required": "实体视图必填。", - "entity-view-type": "实体视图类型", - "entity-view-type-list-empty": "实体视图类型未选择。", - "entity-view-type-required": "实体视图类型必填。", - "entity-view-types": "实体视图类型", - "entity-views": "实体视图", - "events": "事件", - "idCopiedMessage": "实体视图Id已复制到剪贴板", - "make-private": "实体视图设为私有", - "make-private-entity-view-text": "确认后,实体视图及其所有数据将被私有化,无法被他人访问。", - "make-private-entity-view-title": "你确定你想创建私有 '{{entityViewName}}' 实体视图?", - "make-public": "实体视图设为公开", - "make-public-entity-view-text": "确认后,实体视图 及其所有数据将被公开并被他人访问。", - "make-public-entity-view-title": "你确定你想创建公开 '{{entityViewName}}' 实体视图?", - "management": "实体视图管理", - "name": "名称", - "name-required": "名称必填。", - "name-starts-with": "名称前缀", - "no-alias-matching": "'{{alias}}' 没有找到。", - "no-aliases-found": "找不到别名。", - "no-entity-view-types-matching": "没有找到匹配 '{{entitySubtype}}' 的实体视图类型。", - "no-entity-views-matching": "找不到与 '{{entity}}' 匹配的实体视图。", - "no-entity-views-text": "找不到实体视图", - "no-key-matching": "'{{key}}' 没有找到。", - "no-keys-found": "找不到密钥。", - "public": "公开", - "remove-alias": "删除实体视图别名", - "search": "查找实体视图", - "select-entity-view": "选择实体视图", - "select-entity-view-type": "选择实体视图类型", - "selected-entity-views": "已选择 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }", - "server-attributes": "服务端属性", - "server-attributes-placeholder": "服务端属性", - "shared-attributes": "共享属性", - "shared-attributes-placeholder": "共享属性", - "start-date": "开始日期", - "start-ts": "开始时间", - "target-entity": "目标实体", - "timeseries": "时间序列", - "timeseries-data": "时间序列数据", - "timeseries-data-hint": "配置目标实体的 Timeseries 数据键,以便实体视图可以访问这些键。此 Timeseries 数据是只读的。", - "timeseries-placeholder": "时间序列", - "unable-entity-view-device-alias-text": "实体视图别名 '{{entityViewAlias}}' 不能够被删除,因为它被下列部件所使用:
              {{widgetsList}}", - "unable-entity-view-device-alias-title": "无法删除实体视图别名", - "unassign-entity-view": "未分配实体视图", - "unassign-entity-view-text": "确认后,实体视图将未分配,客户无法访问。", - "unassign-entity-view-title": "您确定要取消对 '{{entityViewName}}'实体视图的分配吗?", - "unassign-entity-view-from-edge": "未分配实体视图", - "unassign-entity-view-from-edge-text": "确认后,实体视图将未分配,边缘无法访问。", - "unassign-entity-view-from-edge-title": "您确定要取消对 '{{entityViewName}}'实体视图的分配吗?", - "unassign-entity-views": "取消分配实体视图", - "unassign-entity-views-action-title": "从客户处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", - "unassign-entity-views-from-edge-action-title": "从边缘处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", - "unassign-entity-views-from-edge-text": "确认后,所有选定的实体视图将被分配,边缘无法访问。", - "unassign-entity-views-from-edge-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }吗?", - "unassign-entity-views-text": "确认后,所有选定的实体视图将被分配,客户无法访问。", - "unassign-entity-views-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }吗?", - "unassign-from-customer": "取消分配客户", - "use-entity-view-name-filter": "使用筛选器", - "view-entity-views": "查看实体视图" - }, - "entity": { - "add-alias": "添加实体别名", - "alarm-name-starts-with": "以 '{{prefix}}' 开头的警告", - "alias": "别名", - "alias-required": "实体别名必填。", - "aliases": "实体别名", - "all-subtypes": "全部", - "any-entity": "任意实体", - "asset-name-starts-with": "以 '{{prefix}}' 开头的资产", - "columns-to-display": "要显示的列", - "configure-alias": "别名 '{{alias}}' 配置", - "create-new-alias": "创建一个新的!", - "create-new-key": "创建一个新的!", - "customer-name-starts-with": "以 '{{prefix}}' 开头的客户", - "dashboard-name-starts-with": "以 '{{prefix}}' 开头的仪表板", - "details": "实体详情", - "device-name-starts-with": "以 '{{prefix}}' 开头的设备", - "device-profile-name-starts-with": "名称以 '{{prefix}}' 开头的设备配置", - "duplicate-alias-error": "别名 '{{alias}}' 重复。
              同一仪表板别名必须唯一。", - "enter-entity-type": "输入实体类型", - "entities": "实体", - "entities-count": "实体数量", - "entity": "实体", - "entity-alias": "实体别名", - "entity-label": "实体标签", - "entity-list": "实体列表", - "entity-list-empty": "没有选择实体。", - "entity-name": "实体名", - "entity-name-filter-no-entity-matched": "没有找到以 '{{entity}}' 开头的实体", - "entity-name-filter-required": "实体名筛选器必填。", - "entity-type": "实体类型", - "entity-type-list": "实体类型列表", - "entity-type-list-empty": "没有选择实体类型。", - "entity-types": "实体类型", - "entity-view-name-starts-with": "以 '{{prefix}}' 开头的实体视图", - "key": "键名", - "key-name": "Key name", - "list-of-alarms": "{ count, plural, 1 {个警告} other {# 个警告} }", - "list-of-assets": "{ count, plural, 1 {个资产} other {# 个资产} }", - "list-of-customers": "{ count, plural, 1 {个客户} other {# 个客户} }", - "list-of-dashboards": "{ count, plural, 1 {个仪表板} other {# 个仪表板} }", - "list-of-device-profiles": "{ count, plural, 1 {个设备配置} other {# 个设备配置} }", - "list-of-devices": "{ count, plural, 1 {个设备} other {# 个设备} }", - "list-of-entity-views": "{ count, plural, 1 {个实体视图} other {# 个实体视图} }", - "list-of-plugins": "{ count, plural, 1 {个插件} other {# 个插件} }", - "list-of-rulechains": "{ count, plural, 1 {个规则链} other {# 个规则链} }", - "list-of-rulenodes": "{ count, plural, 1 {个规则节点} other {# 个规则节点} }", - "list-of-rules": "{ count, plural, 1 {个规则} other {# 个规则} }", - "list-of-tenant-profiles": "{ count, plural, 1 {个租户配置} other {# 个租户配置} }", - "list-of-tenants": "{ count, plural, 1 {个租户} other {# 个租户} }", - "list-of-users": "{ count, plural, 1 {个用户} other {# 个用户} }", - "missing-entity-filter-error": "别名 '{{alias}}' 缺少筛选器", - "name-starts-with": "名称开始于", - "no-alias-matching": "没有找到 '{{alias}}'", - "no-aliases-found": "没有找到别名", - "no-data": "无数据", - "no-entities-matching": "没有找到符合 '{{entity}}' 的实体。", - "no-entities-prompt": "没有找到实体", - "no-entity-types-matching": "没有找到符合 '{{entityType}}' 类型的实体。", - "no-key-matching": "没有找到键 '{{key}}'", - "no-keys-found": "没有找到键", - "plugin-name-starts-with": "以 '{{prefix}}' 开头的插件", - "remove-alias": "移除实体别名", - "rule-name-starts-with": "以 '{{prefix}}' 开头的规则", - "rulechain-name-starts-with": "规则链前缀名称 '{{prefix}}'", - "rulenode-name-starts-with": "名称以 '{{prefix}}' 开头的规则节点", - "search": "实体检索", - "select-entities": "选择实体", - "selected-entities": "已选择 { count, plural, 1 {# 个实体} other {# 个实体} }", - "tenant-name-starts-with": "以 '{{prefix}}' 开头的租户", - "tenant-profile-name-starts-with": "名称以 '{{prefix}}' 开头的租户配置", - "type": "类型", - "type-alarm": "警告", - "type-alarms": "警告", - "type-api-usage-state": "Api使用状态", - "type-asset": "资产", - "type-assets": "资产", - "type-current-customer": "当前客户", - "type-current-tenant": "当前租户", - "type-current-user": "当前用户", - "type-current-user-owner": "当前用户所有者", - "type-customer": "客户", - "type-customers": "客户", - "type-dashboard": "仪表板", - "type-dashboards": "仪表板", - "type-device": "设备", - "type-device-profile": "设备配置", - "type-device-profiles": "设备配置", - "type-devices": "设备", - "type-entity-view": "实体视图", - "type-entity-views": "实体视图", - "type-plugin": "插件", - "type-plugins": "插件", - "type-required": "实体类型必填。", - "type-rule": "规则", - "type-rulechain": "规则链", - "type-rulechains": "规则链库", - "type-rulenode": "规则节点", - "type-rulenodes": "规则节点", - "type-rules": "规则", - "type-tenant": "租户", - "type-tenant-profile": "租户简介", - "type-tenant-profiles": "租户配置", - "type-tenants": "租户", - "type-user": "用户", - "type-users": "用户", - "unable-delete-entity-alias-text": "实体别名 '{{entityAlias}}' 被以下部件使用不能删除:
              {{widgetsList}}", - "unable-delete-entity-alias-title": "无法删除实体别名", - "use-entity-name-filter": "用户筛选器", - "user-name-starts-with": "以 '{{prefix}}' 开头的用户", - "type-edge": "边缘", - "type-edges": "边缘", - "list-of-edges": "{ count, plural, 1 {1 个边缘} other {列表 # 个边缘} }", - "edge-name-starts-with": "以 '{{prefix}}' 开头的边缘" - }, - "error": { - "unable-to-connect": "无法连接到服务器!请检查您的互联网连接。", - "unhandled-error-code": "未处理的错误代码: {{errorCode}}", - "unknown-error": "未知错误" - }, - "event": { - "alarm": "报警", - "body": "整体", - "data": "数据", - "data-type": "数据类型", - "entity-id": "实体ID", - "error": "错误", - "errors-occurred": "错误发生", - "event": "事件", - "event-time": "事件时间", - "event-type": "事件类型", - "events-filter": "事件筛选器", - "failed": "失败", - "has-error": "有错误", - "message-id": "消息ID", - "message-type": "消息类型", - "messages-processed": "消息处理", - "metadata": "元数据", - "method": "方法", - "no-events-prompt": "找不到事件", - "relation-type": "关联类型", - "server": "服务器", - "status": "状态", - "success": "成功", - "type": "类型", - "type-debug-rule-chain": "调试", - "type-debug-rule-node": "调试", - "type-error": "错误", - "type-lc-event": "生命周期事件", - "type-stats": "类型统计", - "all-events": "全部", - "entity-type": "实体类型" - }, - "extension": { - "add": "添加扩展", - "add-attribute": "添加属性", - "add-attribute-request": "添加属性请求", - "add-attribute-update": "添加属性更新", - "add-broker": "添加代理服务器", - "add-config": "添加转换器配置", - "add-connect-request": "添加连接请求", - "add-converter": "添加转换器", - "add-device": "添加服务器", - "add-disconnect-request": "添加断开请求", - "add-map": "添加映射元素", - "add-server-side-rpc-request": "添加服务端RPC请求", - "add-timeseries": "添加 Timeseries", - "anonymous": "匿名", - "attr-json-key-expression": "属性键JSON表达式", - "attr-topic-key-expression": "属性键名Topic表达式", - "attribute-filter": "属性筛选器", - "attribute-key-expression": "属性键名表达式", - "attribute-requests": "属性请求", - "attribute-updates": "属性更新", - "attributes": "属性", - "basic": "Basic", - "brokers": "代理服务器组", - "ca-cert": "CA证书文件 *", - "cert": "证书文件 *", - "client-scope": "客户范围", - "configuration": "配置", - "connect-requests": "连接请求", - "converter-configurations": "转换器的配置", - "converter-id": "转换器序号", - "converter-json": "Json", - "converter-json-parse": "无法解析转换JSON。", - "converter-json-required": "Converter JSON 必填。", - "converter-type": "转换类型", - "converters": "转换器", - "credentials": "证书", - "custom": "定制", - "delete": "删除扩展", - "delete-extension-text": "请注意:确认后,扩展和所有相关数据将变得不可恢复。", - "delete-extension-title": "确实要删除扩展名'{{extensionId}}'吗?", - "delete-extensions-text": "请注意:确认后,所有选定的扩展将被删除。", - "delete-extensions-title": "确定要删除 { count, plural, 1 {# 个扩展} other {# 个扩展} }吗?", - "device-name-expression": "设备名称表达式", - "device-name-filter": "设备名称筛选器", - "device-type-expression": "设备类型表达式", - "disconnect-requests": "断开请求", - "drop-file": "删除文件或单击以选择要上载的文件。", - "edit": "编辑扩展", - "export-extension": "导出扩展", - "export-extensions-configuration": "导出扩展配置", - "extension-id": "扩展ID", - "extension-type": "扩展类型", - "extensions": "扩展", - "field-required": "必填字段", - "file": "扩展文件", - "filter-expression": "筛选条件表达式", - "host": "主机", - "id": "ID", - "import-extension": "导入扩展", - "import-extensions": "导入扩展", - "import-extensions-configuration": "导入扩展配置", - "invalid-file-error": "无效的扩展文件", - "json-name-expression": "设备名称JSON表达式", - "json-parse": "无法解析转换器JSON。", - "json-required": "Transformer JSON 必填。", - "json-type-expression": "设备类型JSON表达式", - "key": "键名", - "mapping": "映射", - "method-filter": "方法筛选器", - "modbus-add-server": "添加 server/slave", - "modbus-add-server-prompt": "请添加 server/slave", - "modbus-attributes-poll-period": "轮询属性周期 (ms)", - "modbus-baudrate": "波特率", - "modbus-byte-order": "字节顺序", - "modbus-databits": "数据位", - "modbus-databits-range": "数据位应该在7到8的范围内。", - "modbus-device-name": "设备名称", - "modbus-encoding": "编码", - "modbus-function": "函数", - "modbus-parity": "奇偶性", - "modbus-poll-period": "轮询周期 (ms)", - "modbus-poll-period-range": "轮询周期应为正值。", - "modbus-port-name": "串口名称", - "modbus-register-address": "寄存器地址", - "modbus-register-address-range": "寄存器地址应该在0到65535的范围内。", - "modbus-register-bit-index": "位索引", - "modbus-register-bit-index-range": "位索引应该在0到15的范围内。", - "modbus-register-count": "寄存器计数", - "modbus-register-count-range": "寄存器计数应该是一个正值。", - "modbus-rtu-over-tcp": "RTU over TCP", - "modbus-server": "Servers/slaves", - "modbus-stopbits": "停止位", - "modbus-stopbits-range": "停止位应该在1到2的范围内。", - "modbus-tag": "标签", - "modbus-tcp-reconnect": "自动重新连接", - "modbus-timeseries-poll-period": "Timeseries 轮询周期 (ms)", - "modbus-transport": "Transport", - "modbus-unit-id": "单位编号", - "modbus-unit-id-range": "单位ID应该在1到247的范围内", - "no-file": "没有选择文件。", - "opc-add-server": "添加服务器", - "opc-add-server-prompt": "请添加服务器", - "opc-application-name": "应用名称", - "opc-application-uri": "应用URI", - "opc-device-name-pattern": "设备名称模式", - "opc-device-node-pattern": "设备节点模式", - "opc-identity": "身份", - "opc-keystore": "密钥库", - "opc-keystore-alias": "别名", - "opc-keystore-key-password": "密钥密码", - "opc-keystore-location": "位置 *", - "opc-keystore-password": "密码", - "opc-keystore-type": "类型", - "opc-scan-period-in-seconds": "秒级扫描周期", - "opc-security": "安全性", - "opc-server": "服务器组", - "opc-type": "类型", - "password": "密码", - "pem": "PEM", - "port": "端口", - "port-range": "端口应该在1到65535的范围内。", - "private-key": "私钥文件 *", - "request-id-expression": "请求ID表达式", - "request-id-json-expression": "请求ID JSON表达式", - "request-id-topic-expression": "请求ID主题表达式", - "request-topic-expression": "请求主题表达式", - "response-timeout": "毫秒内响应超时", - "response-topic-expression": "响应主题表达式", - "retry-interval": "以毫秒为单位的重试间隔", - "selected-extensions": "已选择 { count, plural, 1 {# 个扩展} other {# 个扩展} }", - "server-side-rpc": "服务端RPC", - "ssl": "Ssl", - "sync": { - "last-sync-time": "最后同步时间", - "not-available": "无法使用", - "not-sync": "不同步", - "status": "状态", - "sync": "同步" - }, - "timeout": "毫秒超时", - "timeseries": "Timeseries", - "to-double": "加倍", - "token": "安全令牌", - "topic": "主题", - "topic-expression": "主题表达", - "topic-filter": "Topic筛选器", - "topic-name-expression": "设备名称主题表达式", - "topic-type-expression": "设备类型主题表达式", - "transformer": "转换器", - "transformer-json": "JSON *", - "type": "类型", - "unique-id-required": "当前扩展ID已经存在。", - "username": "用户名", - "value": "价值", - "value-expression": "值表达式" - }, - "filter": { - "add": "添加筛选器", - "add-complex": "添加复合", - "add-complex-filter": "添加复合筛选器", - "add-filter": "添加筛选器", - "add-filter-prompt": "请添加筛选器", - "add-key-filter": "添加键名筛选器", - "autogenerated-label": "自动生成标签", - "complex-filter": "复合筛选器", - "create-new-filter": "请新增!", - "current-customer": "当前客户", - "current-device": "当前设备", - "current-tenant": "当前租户", - "current-user": "当前用户", - "date": "日期", - "default-value": "默认值", - "display-label": "要显示的标签", - "duplicate-filter": "同名筛选器已存在。", - "duplicate-filter-error": "找到重复的筛选器 '{{filter}}'。
              筛选器在仪表板中必须是唯一的。", - "dynamic-source-type": "动态源类型", - "edit": "编辑筛选器", - "edit-complex-filter": "编辑复合筛选器", - "edit-filter-user-params": "编辑筛选器谓词用户参数", - "edit-key-filter": "编辑键名筛选器", - "editable": "可编辑", - "filter": "筛选器", - "filter-required": "筛选器必填。", - "filter-user-params": "过滤谓词用户参数", - "filters": "筛选器", - "ignore-case": "忽略大小写", - "key-filter": "键名筛选器", - "key-filters": "键名筛选器", - "key-name": "键名", - "key-name-required": "键名必填。", - "key-type": { - "attribute": "属性", - "constant": "常量", - "entity-field": "实体", - "key-type": "键类型", - "timeseries": "Timeseries" - }, - "key-value-type-change-message": "如果您确认新的值类型,所有输入的键过滤器将被删除。", - "key-value-type-change-title": "是否确实要更改键值类型?", - "missing-key-filters-error": "筛选器 '{{filter}}' 的键名筛选条件缺失。", - "name": "筛选器名称", - "name-required": "筛选器名称必填。", - "no-dynamic-value": "无动态值", - "no-filter-matching": "找不到 '{{filter}}' 。", - "no-filter-text": "未指定筛选器", - "no-filters": "未配置筛选器", - "no-filters-found": "找不到筛选器。", - "no-key-filters": "未配置键名筛选器", - "operation": { - "and": "和", - "contains": "包含", - "ends-with": "结束于", - "equal": "等于", - "greater": "大于", - "greater-or-equal": "大于或等于", - "less": "小于", - "less-or-equal": "小于或等于", - "not-contains": "不包含", - "not-equal": "不等于", - "operation": "操作", - "or": "或", - "starts-with": "开始于" - }, - "order-priority": "字段顺序优先级", - "preview": "筛选器预览", - "remove-filter": "删除筛选器", - "remove-key-filter": "删除键名筛选器", - "source-attribute": "源属性", - "switch-to-default-value": "切换到默认值", - "switch-to-dynamic-value": "切换到动态值", - "time": "时间", - "unable-delete-filter-text": "无法删除筛选器 '{{filter}}' ,因为它由以下小部件使用:
              {{widgetsList}}", - "unable-delete-filter-title": "无法删除筛选器", - "user-parameters": "用户参数", - "value": "值", - "value-type-required": "键值类型是必需的。", - "value-type": { - "boolean": "布尔值", - "date-time": "日期时间", - "numeric": "数字", - "string": "字符串", - "value-type": "值类型" - } - }, - "firmware": { - "add": "添加固件", - "checksum": "校验和", - "checksum-algorithm": "校验和算法", - "checksum-copied-message": "固件校验和已复制到剪贴板", - "checksum-required": "校验和为必填项。", - "content-type": "Content type", - "copy-checksum": "复制校验和", - "copyId": "复制固件ID", - "delete": "删除固件", - "delete-firmware-text": "请注意:确认后固件将无法恢复。", - "delete-firmware-title": "确定要删除固件'{{firmwareTitle}}'?", - "delete-firmwares-action-title": "Delete { count, plural, 1 {# 个固件} other {# 个固件} }", - "delete-firmwares-text": "请注意:确认后所有选定的资源都将被删除。", - "delete-firmwares-title": "确定要删除固件 { count, plural, 1 {# 个固件} other {# 个固件} }?", - "description": "描述", - "download": "下载固件", - "drop-file": "拖拽固件文件或单击以选择要上传的文件。", - "empty": "固件为空", - "file-name": "文件名", - "file-size": "文件大小", - "file-size-bytes": "文件大小(字节)", - "firmware": "固件", - "firmware-details": "固件详情", - "firmware-required": "固件为必选项。", - "idCopiedMessage": "固件ID已复制到剪贴板", - "no-firmware-matching": "找不到与 '{{entity}}' 匹配的固件。", - "no-firmware-text": "没有找到固件", - "no-software-matching": "找不到与 '{{entity}}' 匹配的软件。", - "no-software-text": "没有找到软件", - "search": "查找固件", - "selected-firmware": "已选择{ count, plural, 1 {# 个固件} other {# 个固件}", - "software": "软件", - "software-required": "软件为必选项。", - "title": "标题", - "title-required": "标题为必填项。", - "type": "固件类型", - "types": { - "firmware": "固件", - "software": "软件" - }, - "version": "版本号", - "version-required": "版本号为必填项。", - "warning-after-save-no-edit": "保存固件后,将无法更改标题和版本号。" -}, - "fullscreen": { - "exit": "退出全屏", - "expand": "展开到全屏", - "fullscreen": "全屏", - "toggle": "切换全屏模式" - }, - "function": { - "function": "函数" - }, - "gateway": { - "add-entry": "添加配置", - "connector-add": "添加新连接器", - "connector-enabled": "启用连接器", - "connector-name": "连接器名称", - "connector-name-required": "Connector 名称必填。", - "connector-type": "连接器类型", - "connector-type-required": "Connector 类型必填。", - "connectors": "连接器配置", - "create-new-gateway": "创建新网关", - "create-new-gateway-text": "是否确实要创建名为 '{{gatewayName}}' 的新网关?", - "delete": "删除配置", - "download-tip": "下载配置", - "gateway": "网关", - "gateway-exists": "同名设备已存在。", - "gateway-name": "网关名称", - "gateway-name-required": "网关名称必填。", - "gateway-saved": "已成功保存网关配置。", - "json-parse": "无效的JSON。", - "json-required": "字段不能为空。", - "no-connectors": "无连接器", - "no-data": "没有配置", - "no-gateway-found": "找不到网关。", - "no-gateway-matching": "找不到 '{{item}}' 。", - "path-logs": "日志文件的路径", - "path-logs-required": "路径是必需的。", - "remote": "远程配置", - "remote-logging-level": "日志记录级别", - "remove-entry": "删除配置", - "save-tip": "保存配置", - "security-type": "安全类型", - "security-types": { - "access-token": "访问令牌", - "tls": "TLS" - }, - "storage": "存储", - "storage-max-file-records": "文件中的最大记录数", - "storage-max-files": "最大文件数", - "storage-max-files-min": "最小值为1。", - "storage-max-files-pattern": "数字无效。", - "storage-max-files-required": "数字是必需的。", - "storage-max-records": "存储中的最大记录数", - "storage-max-records-min": "最小记录数为1。", - "storage-max-records-pattern": "数字无效。", - "storage-max-records-required": "最大记录项必填。", - "storage-pack-size": "最大事件包大小", - "storage-pack-size-min": "最小值为1。", - "storage-pack-size-pattern": "数字无效。", - "storage-pack-size-required": "最大事件包大小必填。", - "storage-path": "存储路径", - "storage-path-required": "存储路径必填。", - "storage-type": "存储类型", - "storage-types": { - "file-storage": "文件存储", - "memory-storage": "内存存储" - }, - "thingsboard": "ThingsBoard", - "thingsboard-host": "ThingsBoard主机", - "thingsboard-host-required": "主机必填。", - "thingsboard-port": "ThingsBoard端口", - "thingsboard-port-max": "最大端口号为65535。", - "thingsboard-port-min": "最小端口号为1。", - "thingsboard-port-pattern": "端口无效。", - "thingsboard-port-required": "端口必填。", - "tidy": "整洁", - "tidy-tip": "整理配置JSON", - "title-connectors-json": "连接器 {{typeName}} 配置", - "tls-path-ca-certificate": "网关上CA证书的路径", - "tls-path-client-certificate": "网关上客户端证书的路径", - "tls-path-private-key": "网关上私钥的路径", - "toggle-fullscreen": "切换全屏", - "transformer-json-config": "配置JSON*", - "update-config": "添加/更新配置JSON" - }, - "grid": { - "add-item-text": "添加新项目", - "delete-item": "删除项目", - "delete-item-text": "注意,确认后此项及其所有相关数据将变得不可恢复。", - "delete-item-title": "您确定要删除此项吗?", - "delete-items": "删除项目", - "delete-items-action-title": "删除 { count, plural, 1 {# 个元素} other {# 个元素} }", - "delete-items-text": "注意,确认后所有选择的项目将被删除,所有相关数据将不可恢复。", - "delete-items-title": "确定你要删除 { count, plural, 1 {# 项} other {# 项} }吗?", - "item-details": "项目详细信息", - "no-items-text": "没有找到项目", - "scroll-to-top": "滚动到顶部" - }, - "help": { - "goto-help-page": "转到帮助页面" - }, - "home": { - "avatar": "头像", - "home": "首页", - "logout": "注销", - "menu": "菜单", - "open-user-menu": "打开用户菜单", - "profile": "属性" - }, - "icon": { - "icon": "图标", - "material-icons": "素材图标", - "select-icon": "选择图标", - "show-all": "显示所有图标" - }, - "import": { - "column-example": "示例值数据", - "column-key": "属性/遥测键", - "column-title": "标题", - "column-type": { - "access-token": "访问令牌", - "client-attribute": "客户端属性", - "column-type": "列类型", - "description": "说明", - "entity-field": "实体字段", - "isgateway": "Is网关", - "label": "标签", - "name": "名称", - "routing-key": "边缘键", - "secret": "边缘密钥", - "server-attribute": "服务器属性", - "shared-attribute": "共享属性", - "timeseries": "Timeseries", - "type": "类型" - }, - "column-value": "价值", - "csv-delimiter": "CSV分隔符", - "csv-first-line-header": "第一行包含列名", - "csv-update-data": "更新属性/遥测", - "drop-file": "拖动一个JSON文件或者单击以选择要上传的文件。", - "drop-file-csv": "删除CSV文件或单击以选择要上载的文件。", - "import-csv-invalid-format-error": "文件格式无效。行: '{{line}}'", - "import-csv-number-columns-error": "一个文件至少应该包含两列", - "message": { - "create-entities": "{{count}} 个新实体已成功创建。", - "error-entities": "创建 {{count}} 个实体时出错。", - "update-entities": "{{count}} 个实体已成功更新。" - }, - "no-file": "没有选择文件", - "stepper-text": { - "column-type": "选择列类型", - "configuration": "导入配置", - "creat-entities": "创建新实体", - "done": "多恩", - "select-file": "选择一个文件" - } - }, - "item": { - "selected": "选择" - }, - "js-func": { - "mini": "迷你", - "no-return-error": "函数必须返回值!", - "return-type-mismatch": "函数必须返回 '{{type}}' 类型的值!", - "tidy": "整洁" - }, - "key-val": { - "add-entry": "增加条目", - "key": "键名", - "no-data": "没有条目", - "remove-entry": "删除条目", - "value": "价值" - }, - "language": { - "language": "语言" - }, - "layout": { - "color": "颜色", - "layout": "布局", - "main": "主体", - "manage": "布局管理", - "right": "右侧", - "select": "选择目标布局", - "settings": "布局设置" - }, - "legend": { - "avg": "平均值", - "comparison-time-ago": { - "days": "(一天前)", - "months": "(一个月前)", - "weeks": "(一周前)", - "years": "(一年前)" - }, - "direction": "图例方向", - "max": "最大值", - "min": "最小值", - "position": "图例位置", - "settings": "图例设置", - "show-avg": "显示平均值", - "show-max": "显示最大值", - "show-min": "显示最小值", - "show-total": "显示总数", - "sort-legend": "在图例中排序数据键", - "total": "总数" - }, - "login": { - "create-password": "创建密码", - "email": "电子邮件", - "error": "登录错误", - "expired-password-reset-message": "您的凭据已过期!请创建新密码。", - "forgot-password": "忘记密码?", - "login": "登录", - "login-with": "使用 {{name}} 登录", - "new-password": "新密码", - "new-password-again": "再次输入新密码", - "or": "或", - "password-again": "再次输入密码", - "password-link-sent-message": "密码重置链接已成功发送!", - "password-reset": "密码重置", - "passwords-mismatch-error": "输入的密码必须相同!", - "remember-me": "记住我", - "request-password-reset": "请求密码重置", - "reset-password": "重置密码", - "sign-in": "登录 ", - "username": "用户名(电子邮件)" - }, - "ota-update": { - "add": "添加包", - "assign-firmware": "分配的固件", - "assign-firmware-required": "分配的固件必填", - "assign-software": "分配的软件", - "assign-software-required": "分配的软件必填", - "auto-generate-checksum": "自动生成校验和", - "checksum": "校验和", - "checksum-hint": "如果校验和为空,会自动生成", - "checksum-algorithm": "校验和算法", - "checksum-copied-message": "包校验和已复制到剪贴板", - "change-firmware": "固件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", - "change-software": "软件的更改可能会导致 { count, plural, 1 {1 个设备} other {# 个设备} } 的更新。", - "chose-compatible-device-profile": "上传的包仅适用于具有所选配置文件的设备。", - "chose-firmware-distributed-device": "选择将分发到设备的固件", - "chose-software-distributed-device": "选择将分发到设备的软件", - "content-type": "内容类型", - "copy-checksum": "复制校验和", - "copy-direct-url": "复制直接URL", - "copyId": "复制包ID", - "copied": "已复制!", - "delete": "删除包", - "delete-ota-update-text": "小心,OTA升级确认后不可恢复。", - "delete-ota-update-title": "您确定要删除OTA升级'{{title}}'吗?", - "delete-ota-updates-text": "小心,确认后所有选中的OTA升级将被删除。", - "delete-ota-updates-title": "您确定要删除 { count, plural, 1 {1 OTA升级} other {# OTA升级} } 吗?", - "description": "描述", - "direct-url": "直接URL", - "direct-url-copied-message": "包直接URL已复制到剪贴板", - "direct-url-required": "直接URL必填", - "download": "下载包", - "drop-file": "拖放打包文件或点击选择要上传的文件。", - "file-name": "文件名", - "file-size": "文件大小", - "file-size-bytes": "文件大小(以字节为单位)", - "idCopiedMessage": "包ID已被复制到剪贴板", - "no-firmware-matching": "没有找到与'{{entity}}'匹配的兼容固件OTA升级包。", - "no-firmware-text": "没有提供兼容的固件OTA升级包。", - "no-packages-text": "没有找到包", - "no-software-matching": "没有找到匹配 '{{entity}}' 的兼容软件OTA升级包。", - "no-software-text": "没有提供兼容的软件OTA升级包。", - "ota-update": "OTA 升级", - "ota-update-details": "OTA 升级详情", - "ota-updates": "OTA 升级", - "package-type": "包类型", - "packages-repository": "包仓库", - "search": "搜索包", - "selected-package": "{ count, plural, 1 {1 个包} other {# 个包} } 选中", - "title": "标题", - "title-required": "标题必填。", - "types": { - "firmware": "固件", - "software": "软件" - }, - "upload-binary-file": "上传二进制文件", - "use-external-url": "使用外部URL", - "version": "版本", - "version-required": "版本必填。", - "version-tag": "版本标签", - "version-tag-hint": "自定义标签应与您设备报告的软件包版本相匹配。", - "warning-after-save-no-edit": "上传包后,您将无法修改标题、版本、设备配置文件和包类型。" - }, - "position": { - "bottom": "底部", - "left": "左侧", - "right": "右侧", - "top": "顶部" - }, - "profile": { - "change-password": "更改密码", - "current-password": "当前密码", - "last-login-time": "最后登录", - "profile": "属性", - "copy-jwt-token": "复制 JWT 令牌", - "tokenCopiedSuccessMessage": "JWT 令牌已复制到剪贴板", - "tokenCopiedWarnMessage": "JWT 令牌已过期!请刷新页面。" - }, - "queue": { - "name": "队列名称", - "name_required": "队列名称必填!", - "select_name": "选择队列名称" - }, - "relation": { - "add": "添加关联", - "add-relation-filter": "添加关联筛选器", - "additional-info": "附加信息 (JSON)", - "any-relation": "任意关联", - "any-relation-type": "任何类型", - "delete": "删除关联", - "delete-from-relation-text": "确定删除后,当前实体将与实体 '{{entityName}}' 取消关联", - "delete-from-relation-title": "确定要从实体 '{{entityName}}' 删除关联吗?", - "delete-from-relations-text": "确定删除所有选择的关联关系后,当前实体将与对应的实体取消关联", - "delete-from-relations-title": "确定删除 { count, plural, 1 {# 个关联} other {# 个关联} } 吗?", - "delete-to-relation-text": "确定删除后实体 '{{entityName}}' 将取消与当前实体的关联关系。", - "delete-to-relation-title": "确定要删除实体 '{{entityName}}' 的关联吗?", - "delete-to-relations-text": "确定删除所有选择的关联关系后,与当前实体对应的所有关联关系将被移除。", - "delete-to-relations-title": "确定要删除 { count, plural, 1 {# 个关联} other {# 个关联} }?", - "direction": "方向", - "direction-type": { - "FROM": "从", - "TO": "到" - }, - "edit": "编辑关联", - "from-entity": "从实体", - "from-entity-name": "从实体类型", - "from-entity-type": "从实体类型", - "from-relations": "向外的关联", - "invalid-additional-info": "无法解析附加信息JSON。", - "no-relations-text": "未找到关联", - "relation-filters": "关联筛选器", - "relation-type": "关联类型", - "relation-type-required": "关联类型必填", - "relations": "关联", - "remove-relation-filter": "移除关联筛选器", - "search-direction": { - "FROM": "从", - "TO": "到" - }, - "selected-relations": "已选择{ count, plural, 1 {# 个关联} other {# 个关联} }", - "to-entity": "到实体", - "to-entity-name": "到实体名称", - "to-entity-type": "到实体类型", - "to-relations": "向内的关联", - "type": "类型" - }, - "resource": { - "add": "添加资源", - "delete": "删除资源", - "delete-resource-text": "请注意:确认后资源将不可恢复。", - "delete-resource-title": "确定要删除资源 '{{resourceTitle}}' 吗?", - "delete-resources-action-title": "删除 { count, plural, 1 {# 个资源} other {# 个资源} }", - "delete-resources-text": "请注意:确认后所有选定的资源都将被删除。", - "delete-resources-title": "确定要删除 { count, plural, 1 {# 个资源} other {# 个资源} }?", - "drop-file": "拖拽资源文件或单击以选择要上传的文件。", - "empty": "资源为空", - "no-resource-matching": "找不到与 '{{widgetsBundle}}' 匹配的资源。", - "no-resource-text": "找不到资源", - "open-widgets-bundle": "打开部件库", - "resource": "资源", - "resource-library-details": "资源库详情", - "resource-type": "资源类型", - "resources-library": "资源库", - "search": "查找资源", - "selected-resources": "已选择{ count, plural, 1 {# 个资源} other {# 个资源} }", - "system": "系统", - "title": "标题", - "title-required": "标题是必填项。" -}, - "rulechain": { - "add": "添加规则链", - "add-rulechain-text": "添加新的规则链", - "assign-to-edge": "分配规则链给边缘", - "assign-rulechain-to-edge-title": "分配规则链给边缘", - "assign-rulechain-to-edge-text": "请选择要分配给边缘的规则链", - "copyId": "复制规则链ID", - "create-new-rulechain": "创建新的规则链", - "debug-mode": "调试模式", - "delete": "删除规则链", - "delete-rulechain-text": "小心,在确认规则链和所有相关数据将变得不可恢复。", - "delete-rulechain-title": " 确实要删除规则链'{{ruleChainName}}'吗?", - "delete-rulechains-action-title": "删除 { count, plural, 1 {# 个规则链} other {# 个规则链} }", - "delete-rulechains-text": "请注意:确认后,所有选定的规则链将被删除,所有相关的数据将变得不可恢复。", - "delete-rulechains-title": "确实要删除{count, plural, 1 { 1 个规则链} other {# 个规则链} }吗?", - "description": "说明", - "details": "详情", - "edge-rulechain": "边缘规则链", - "edge-template-root": "根模版", - "events": "事件", - "export": "导出规则链", - "export-failed-error": "无法导出规则链:{{error}}", - "idCopiedMessage": "规则ID已经复制到粘贴板", - "import": "导入规则链", - "invalid-rulechain-file-error": "不能导入规则链:无效的规则链数据格式。", - "invalid-rulechain-type-error": "不能导入规则链:无效的规则链类型。期望类型为{{expectedRuleChainType}}。", - "management": "规则集管理", - "name": "名称", - "name-required": "名称必填。", - "no-rulechains-matching": "没有发现匹配'{{entity}}'的规则链。", - "no-rulechains-text": "未找到规则链", - "open-rulechain": "打开规则链", - "root": "是否根链", - "rulechain": "规则链", - "rulechain-details": "规则链详情", - "rulechain-file": "规则链文件", - "rulechain-required": "规则链必填", - "rulechains": "规则链库", - "search": "查找规则链", - "select-rulechain": "选择规则链", - "selected-rulechains": "已选择 { count, plural, 1 {# 个规则链} other {# 个规则链} }", - "set-auto-assign-to-edge": "创建时分配规则链给边缘", - "set-auto-assign-to-edge-text": "确认后,创建时规则链将自动分配给边缘。", - "set-auto-assign-to-edge-title": "您确定创建时将规则链'{{ruleChainName}}'自动分配给边缘吗", - "set-edge-template-root-rulechain": "设置规则链为边缘模版根", - "set-edge-template-root-rulechain-text": "确认后,规则链将将会成为边缘模版根,且它会成为新创建边缘的根规则链。", - "set-edge-template-root-rulechain-title": "您确定将规则链 '{{ruleChainName}}' 设置为边缘模版根吗?", - "set-root": "设置为根规则链", - "set-root-rulechain-text": "确认之后,规则链将变为根规格链,并将处理所有传入的传输消息。", - "set-root-rulechain-title": "您确定要生成规则链'{{ruleChainName}}'根吗?", - "system": "系统", - "unassign-rulechain-from-edge-text": "确认后,规则链将会取消分配,边缘无法访问。", - "unassign-rulechains-from-edge-text": "确认后,选定的规则链将会取消分配,边缘无法访问。", - "unassign-rulechains-from-edge-title": "您确定要取消分配规则链 { count, plural, 1 {1 个规则链} other {# 个规则链} }?", - "unset-auto-assign-to-edge": "创建时分配规则链给边缘", - "unset-auto-assign-to-edge-text": "确认后,创建时规则链将不再自动分配给边缘。", - "unset-auto-assign-to-edge-title": "您确定取消创建时将规则链'{{ruleChainName}}'自动分配给边缘吗?" - }, - "rulenode": { - "add": "添加规则节点", - "add-link": "添加链接", - "configuration": "配置", - "copy-selected": "选择副本", - "create-new-link-label": "创建一个新的!", - "custom-link-label": "自定义链接标签", - "custom-link-label-required": "自定义链接标签必填", - "debug-mode": "调试模式", - "delete": "删除规则节点", - "delete-selected": "删除选定", - "delete-selected-objects": "删除选定的节点和连接", - "description": "说明", - "deselect-all": "取消选择", - "deselect-all-objects": "取消选择所有节点和连接", - "details": "详情", - "directive-is-not-loaded": "定义的配置指令 '{{directiveName}}' 不可用。", - "events": "事件", - "help": "帮助", - "invalid-target-rulechain": "无法解析目标规则链!", - "link": "链接", - "link-details": "规则节点链接详情", - "link-label": "链接标签", - "link-label-required": "链接标签必填", - "link-labels": "链接标签", - "link-labels-required": "链接标签必填。", - "message": "消息", - "message-type": "消息类型", - "message-type-required": "消息类型必填", - "metadata": "元数据", - "metadata-required": "元数据项不能为空。", - "name": "名称", - "name-required": "名称必填。", - "no-link-label-matching": "找不到'{{label}}'。", - "no-link-labels-found": "找不到链接标签", - "open-node-library": "打开节点库", - "output": "输出", - "reset-debug-mode": "重置所有节点中的调试模式", - "rulenode-details": "规则节点详情", - "search": "查找节点", - "select-all": "选择全部", - "select-all-objects": "选择所有节点和连接", - "select-message-type": "选择消息类型", - "test": "测试", - "test-script-function": "测试脚本功能", - "type": "类型", - "type-action": "动作", - "type-action-details": "执行特别动作", - "type-enrichment": "属性集", - "type-enrichment-details": "向消息元数据中添加附加信息", - "type-external": "外部的", - "type-external-details": "与外部系统交互", - "type-filter": "筛选器", - "type-filter-details": "使用配置条件筛选传入消息", - "type-input": "输入", - "type-input-details": "规则链的逻辑输入,将传入消息转发到下一个相关规则节点", - "type-rule-chain": "规则链", - "type-rule-chain-details": "将传入消息转发到指定的规则链", - "type-transformation": "变换", - "type-transformation-details": "更改消息 Payload 和元数据", - "type-unknown": "未知", - "type-unknown-details": "未解析的规则节点", - "ui-resources-load-error": "加载配置UI资源失败。" - }, - "tenant-profile": { - "add": "添加租户配置", - "copyId": "复制租户配置Id", - "create-new-tenant-profile": "创建一个新的!", - "data": "纵断面数据", - "default": "默认", - "default-storage-ttl-days": "默认存储 TTL 天数(0-无限制)", - "default-storage-ttl-days-range": "不能为负存储天数", - "default-storage-ttl-days-required": "默认存储 TTL 天数必填。", - "delete": "删除租户配置", - "delete-tenant-profile-text": "请注意:确认后,租户配置和所有相关数据将不可。", - "delete-tenant-profile-title": "确实要删除租户配置 '{{tenantProfileName}}'吗?", - "delete-tenant-profiles-text": "请注意:确认后,所有选定的租户配置将被删除,所有相关数据将不可恢复。", - "delete-tenant-profiles-title": "确定要删除 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }?", - "description": "说明", - "edit": "编辑租户配置", - "idCopiedMessage": "租户配置Id已复制到剪贴板", - "max-d-p-storage-days": "最大日存储数据点数(0-无限制)", - "max-d-p-storage-days-range": "最大日存储数据点数不能为负数", - "max-d-p-storage-days-required": "最大日存储数据点数必填。", - "max-emails": "发送的最大电子邮件数(0-无限制)", - "max-emails-range": "发送的最大电子邮件数不能为负数", - "max-emails-required": "最大电子邮件发送数必填。", - "max-j-s-executions": "最大JavaScript执行数(0-不受限制)", - "max-j-s-executions-range": "JavaScript的最大执行数不能为负数", - "max-j-s-executions-required": "最大JavaScript执行数必填。", - "max-r-e-executions": "最大规则引擎执行数(0-不受限制)", - "max-r-e-executions-range": "规则引擎执行的最大数目不能为负", - "max-r-e-executions-required": "最大规则引擎执行数必填。", - "max-rule-node-executions-per-message": "每条消息的最大规则节点执行数(0-无限制)", - "max-rule-node-executions-per-message-range": "每条消息的最大规则节点执行数不能为负", - "max-rule-node-executions-per-message-required": "每个消息的最大规则节点执行数必填。", - "max-sms": "发送的最大短信数(0-无限制)", - "max-sms-range": "发送的最大短信数不能为负数", - "max-sms-required": "最大短信发送数必填。", - "max-transport-data-points": "传输数据点的最大数量(0-无限制)", - "max-transport-data-points-range": "传输数据点的最大数目不能为负", - "max-transport-data-points-required": "最大传输数据点数必填。", - "max-transport-messages": "最大传输消息数(0-无限制)", - "max-transport-messages-range": "传输消息的最大数目不能为负数", - "max-transport-messages-required": "最大传输消息数必填。", - "maximum-assets": "最大资产数量(0-无限)", - "maximum-assets-range": "最大资产数不能为负数", - "maximum-assets-required": "最大资产数必填。", - "maximum-customers": "最大客户数(0-无限制)", - "maximum-customers-range": "最大客户数不能为负数", - "maximum-customers-required": "最大客户数必填。", - "maximum-dashboards": "仪表板的最大数量(0-无限制)", - "maximum-dashboards-range": "仪表板的最大数量不能为负数", - "maximum-dashboards-required": "最大仪表板数必填。", - "maximum-devices": "最大设备数(0-无限制)", - "maximum-devices-range": "最小设备数不能为负数", - "maximum-devices-required": "最大设备数必填。", - "maximum-rule-chains": "最大规则链数(0-无限制)", - "maximum-rule-chains-range": "最大规则链数不能为负数", - "maximum-rule-chains-required": "最大规则链数必填。", - "maximum-users": "最大用户数(0-无限制)", - "maximum-users-range": "最大用户数不能为负数", - "maximum-users-required": "最大用户数必填。", - "name": "名称", - "name-required": "名称必填。", - "no-tenant-profiles-found": "找不到租户配置。", - "no-tenant-profiles-matching": "找不到与 '{{entity}}' 匹配的租户配置。", - "no-tenant-profiles-text": "找不到租户配置", - "profile-configuration": "配置设置", - "search": "查找租户配置", - "selected-tenant-profiles": "已选择 { count, plural, 1 {# 个租户配置} other {# 个租户配置} }", - "set-default": "设置该租户配置为默认", - "set-default-tenant-profile-text": "确认后,此租户配置将被标记为默认配置,并将用于未指定配置的新租户。", - "set-default-tenant-profile-title": "确实要将租户配置 '{{tenantProfileName}}' 设为默认值吗?", - "tenant-profile": "租户简介", - "tenant-profile-details": "租户配置详细信息", - "tenant-profile-required": "租户配置必填", - "tenant-profiles": "租户配置", - "transport-device-msg-rate-limit": "传输设备消息速率限制。", - "transport-device-telemetry-data-points-rate-limit": "设备遥测数据点速率限制。", - "transport-device-telemetry-msg-rate-limit": "设备遥测消息速率限制。", - "transport-tenant-msg-rate-limit": "传输租户消息速率限制。", - "transport-tenant-telemetry-data-points-rate-limit": "租户遥测数据点速率限制。", - "transport-tenant-telemetry-msg-rate-limit": "租户遥测消息速率限制。" - }, - "tenant": { - "add": "添加租户", - "add-tenant-text": "添加新租户", - "admins": "管理员", - "copyId": "复制租户ID", - "delete": "删除租户", - "delete-tenant-text": "请注意:确认后,租户和所有相关数据将不可恢复。", - "delete-tenant-title": "您确定要删除租户'{{tenantTitle}}'吗?", - "delete-tenants-action-title": "删除 { count, plural, 1 {# 个租户} other {# 个租户} }", - "delete-tenants-text": "请注意:确认后,所有选定的租户将被删除,所有相关数据将不可恢复。", - "delete-tenants-title": "确定要删除 {count,plural,1 {# 个租户} other {# 个租户} } 吗?", - "description": "说明", - "details": "详情", - "events": "事件", - "idCopiedMessage": "租户ID已经复制到粘贴板", - "isolated-tb-rule-engine": "在独立的ThingsBoard规则引擎容器中处理", - "isolated-tb-rule-engine-details": "每个独立租户需要单独的微服务", - "manage-tenant-admins": "管理租户管理员", - "management": "租户管理", - "no-tenants-matching": "没有找到符合 '{{entity}}' 的租户", - "no-tenants-text": "没有找到租户", - "search": "查找租户", - "select-tenant": "选择租户", - "selected-tenants": "已选择 { count, plural, 1 {# 个租户} other {# 个租户} }", - "tenant": "租户", - "tenant-details": "租客详情", - "tenant-required": "租户必填", - "tenants": "租户", - "title": "标题", - "title-required": "标题必填。" - }, - "timeinterval": { - "advanced": "高级", - "days": "天", - "days-interval": "{ days, plural, 1 {# 天} other {# 天} }", - "hours": "小时", - "hours-interval": "{ hours, plural, 1 {# 小时} other {# 小时} }", - "minutes": "分钟", - "minutes-interval": "{ minutes, plural, 1 {# 分} other {# 分} }", - "seconds": "秒", - "seconds-interval": "{ seconds, plural, 1 {# 秒} other {# 秒} }" - }, - "timeunit": { - "days": "天", - "hours": "小时", - "minutes": "分钟", - "seconds": "秒" - }, - "timewindow": { - "date-range": "日期范围", - "days": "{ days, plural, 1 {# 天 } other {# 天 } }", - "edit": "编辑时间窗口", - "hide": "隐藏", - "history": "历史", - "hours": "{ hours, plural, 0 {- 小时 } 1 {# 小时 } other {# 小时 } }", - "last": "最后", - "last-prefix": "最后", - "minutes": "{ minutes, plural, 0 {- 分 } 1 {# 分 } other {# 分 } }", - "period": "从 {{ startTime }} 到 {{ endTime }}", - "realtime": "实时", - "seconds": "{ seconds, plural, 0 {- 秒 } 1 {# 秒 } other {# 秒 } }", - "time-period": "时间段" - }, - "timezone": { - "no-timezones-matching": "No timezones matching '{{timezone}}' were found.", - "select-timezone": "选择时区", - "timezone": "时区", - "timezone-required": "时区必填。" - }, - "user": { - "activation-email-sent-message": "激活电子邮件已成功发送!", - "activation-link": "用户激活链接", - "activation-link-copied-message": "用户激活链接已经复制到粘贴板", - "activation-link-text": "使用该链接 激活 激活用户:", - "activation-method": "激活方式", - "add": "添加用户", - "add-user-text": "添加新用户", - "always-fullscreen": "始终全屏", - "anonymous": "匿名", - "copy-activation-link": "复制用户激活链接", - "customer": "客户", - "customer-users": "客户用户", - "default-dashboard": "默认面板", - "delete": "删除用户", - "delete-user-text": "请注意:确认后,用户和所有相关数据将不可恢复。", - "delete-user-title": "您确定要删除用户 '{{userEmail}}' 吗?", - "delete-users-action-title": "删除 { count, plural, 1 {# 个用户} other {# 个用户} }", - "delete-users-text": "请注意:确认后,所有选定的用户将被删除,所有相关数据将不可恢复。", - "delete-users-title": "确定要删除 { count, plural, 1 {# 个用户} other {# 个用户} } 吗?", - "description": "说明", - "details": "详情", - "disable-account": "禁用用户帐户", - "disable-account-message": "已成功禁用用户帐户!", - "display-activation-link": "显示激活链接", - "email": "电子邮件", - "email-required": "电子邮件必填。", - "enable-account": "启用用户帐户", - "enable-account-message": "已成功启用用户帐户!", - "first-name": "名字", - "invalid-email-format": "无效的邮件格式。", - "last-name": "姓", - "login-as-customer-user": "以客户用户身份登录", - "login-as-tenant-admin": "以租户管理员身份登录", - "no-users-matching": "没有找到符合 '{{entity}}' 的用户。", - "no-users-text": "找不到用户", - "resend-activation": "重新发送激活", - "search": "查找用户", - "select-user": "选择用户", - "selected-users": "已选择 { count, plural, 1 {# 个用户} other {# 个用户} }", - "send-activation-mail": "发送激活邮件", - "sys-admin": "系统管理员", - "tenant-admin": "租户管理员", - "tenant-admins": "租户管理员", - "user": "用户", - "user-details": "用户详细信息", - "user-required": "用户必填", - "users": "用户" - }, - "value": { - "boolean": "布尔值", - "boolean-value": "布尔值", - "double": "双精度小数", - "double-value": "双精度小数值", - "double-value-required": "需要双精度值", - "false": "假", - "integer": "数字", - "integer-value": "数字值", - "integer-value-required": "整数值必填", - "invalid-integer-value": "整数值无效", - "json": "JSON", - "json-value": "JSON值", - "json-value-invalid": "JSON值的格式无效", - "json-value-required": "JSON值必填。", - "long": "Long", - "string": "字符串", - "string-value": "字符串值", - "string-value-required": "字符串值必填", - "true": "真", - "type": "值类型" - }, - "widget-action": { - "custom": "自定义动作", - "custom-pretty": "自定义操作(使用HTML模板)", - "header-button": "部件顶部按钮", - "open-dashboard": "切换到另一个仪表板", - "open-dashboard-state": "切换到新仪表板状态", - "open-right-layout": "打开右侧布局 (移动端视图)", - "set-entity-from-widget": "从部件中设置实体", - "target-dashboard": "目标仪表板", - "target-dashboard-state": "目标仪表板状态", - "target-dashboard-state-required": "目标仪表板状态必填", - "update-dashboard-state": "更新当前仪表板状态" - }, - "widget-config": { - "action": "Action", - "action-icon": "图标", - "action-name": "名称", - "action-name-not-unique": "Action 名称已经存在。
              相同 Action Source 的 Action 名称必须唯一。", - "action-name-required": "Action 名称必填。", - "action-source": "Action Source", - "action-source-required": "Action Source 必填", - "action-type": "类型", - "action-type-required": "类型必填", - "actions": "Actions", - "add-action": "添加 Action", - "add-datasource": "添加数据源", - "advanced": "高级", - "alarm-source": "警告源", - "background-color": "背景颜色", - "data": "数据", - "datasource-parameters": "参数", - "datasource-type": "类型", - "datasources": "数据源", - "decimals": "浮点数后的位数", - "delete-action": "删除 Action", - "delete-action-text": "确定要删除部件动作 '{{actionName}}' 吗?", - "delete-action-title": "删除 Widget Action", - "display-icon": "显示标题图标", - "display-legend": "显示图例", - "display-timewindow": "显示时间窗口", - "display-title": "显示标题", - "drop-shadow": "阴影", - "edit-action": "编辑 Action", - "enable-fullscreen": "启用全屏", - "general-settings": "基本设置", - "height": "高度", - "icon-color": "图标颜色", - "icon-size": "图标大小", - "margin": "边缘", - "maximum-datasources": "最大允许 { count, plural, 1 {# 个数据源。} other {# 个数据源。} }", - "mobile-mode-settings": "移动端设置", - "no-actions-text": "找不到 Action", - "order": "顺序", - "padding": "填充", - "remove-datasource": "移除数据源", - "search-actions": "Action 检索", - "settings": "设置", - "target-device": "目标设备", - "text-color": "文字颜色", - "timewindow": "时间窗口", - "title": "标题", - "title-style": "标题风格", - "title-tooltip": "标题工具提示", - "units": "特殊符号展示值", - "use-dashboard-timewindow": "使用仪表板的时间窗口", - "widget-style": "部件风格" - }, - "widget-type": { - "create-new-widget-type": "创建新的部件类型", - "export": "导出部件类型", - "export-failed-error": "无法导出部件类型: {{error}}", - "import": "导入部件类型", - "invalid-widget-type-file-error": "无法导入部件类型:无效的部件类型数据结构。", - "widget-type-file": "部件类型文件" - }, - "widget": { - "add": "添加部件", - "add-resource": "添加资源", - "add-widget-type": "添加新的部件类型", - "alarm": "警告部件", - "alarm-data-overflow": "Widget displays alarms for {{allowedEntities}} (maximum allowed) entities out of {{totalEntities}} entities", - "css": "CSS", - "data-overflow": "Widget displays {{count}} out of {{total}} entities", - "datakey-settings-schema": "数据键设置模式", - "edit": "编辑部件", - "editor": "部件编辑器", - "export": "导出部件", - "html": "HTML", - "javascript": "Javascript", - "js": "JS", - "latest": "最新值", - "management": "管理部件", - "missing-widget-title-error": "部件标题必须指定!", - "no-data": "小部件上没有要显示的数据", - "no-data-found": "没有找到数据", - "remove": "删除部件", - "remove-resource": "删除资源", - "remove-widget-text": "确认后,控件和所有相关数据将变得不可恢复。", - "remove-widget-title": "确实要删除 '{{widgetTitle}}'部件吗?", - "remove-widget-type": "删除部件类型", - "remove-widget-type-text": "确认后,窗口部件类型和所有相关数据将不可恢复。", - "remove-widget-type-title": "您确定要删除部件类型 '{{widgetName}}'吗?", - "resource-is-module": "Is module", - "resource-url": "JavaScript/CSS URL", - "resources": "资源", - "rpc": "控件部件", - "run": "运行部件", - "save": "保存部件", - "save-widget-type-as": "部件类型另存为", - "save-widget-type-as-text": "请输入新的部件标题或选择目标部件包", - "saveAs": "部件另存为", - "search-data": "查找数据", - "select-widget-type": "选择窗口部件类型", - "select-widgets-bundle": "选择部件包", - "settings-schema": "设置模式", - "static": "静态部件", - "tidy": "Tidy", - "timeseries": "Timeseries", - "title": "部件标题", - "title-required": "部件标题必填。", - "toggle-fullscreen": "切换全屏", - "type": "部件类型", - "unable-to-save-widget-error": "无法保存部件!控件有错误!", - "undo": "撤消部件更改", - "widget-bundle": "部件包", - "widget-library": "部件库", - "widget-saved": "部件已保存", - "widget-template-load-failed-error": "无法加载部件模板!", - "widget-type-load-error": "由于以下错误未加载小部件:", - "widget-type-load-failed-error": "无法加载部件类型!", - "widget-type-not-found": "加载部件配置出错。
              可能关联的部件已经删除了。" - }, - "widgets-bundle": { - "add": "添加部件包", - "add-widgets-bundle-text": "添加新的部件包", - "create-new-widgets-bundle": "创建新的部件包", - "current": "当前组", - "delete": "删除部件包", - "delete-widgets-bundle-text": "请注意:确认后,部件包和所有相关数据将不可恢复。", - "delete-widgets-bundle-title": "您确定要删除部件包 '{{widgetsBundleTitle}}'吗?", - "delete-widgets-bundles-action-title": "删除 { count, plural, 1 {# 个部件包} other {# 个部件包} }", - "delete-widgets-bundles-text": "请注意:确认后,所有选定的部件包将被删除,所有相关数据将不可恢复。", - "delete-widgets-bundles-title": "确定要删除 { count, plural, 1 {# 个部件包} other {# 个部件包} } 吗?", - "description": "描述", - "details": "详情", - "empty": "部件包是空的", - "export": "导出部件包", - "export-failed-error": "无法导出部件包: {{error}}", - "image-preview": "图片预览", - "import": "导入部件包", - "invalid-widgets-bundle-file-error": "无法导入部件包:无效的部件包数据结构。", - "loading-widgets-bundles": "加载部件包...", - "no-widgets-bundles-matching": "没有找到与 '{{widgetsBundle}}' 匹配的部件包。", - "no-widgets-bundles-text": "找不到部件包", - "open-widgets-bundle": "打开部件包", - "search": "查找部件包", - "selected-widgets-bundles": "已选择 { count, plural, 1 {# 个部件包} other {# 个部件包} }", - "system": "系统", - "title": "标题", - "title-required": "标题必填。", - "widgets-bundle-details": "部件包详细信息", - "widgets-bundle-file": "部件包文件", - "widgets-bundle-required": "部件包必填。", - "widgets-bundles": "部件包" - }, - "widgets": { - "date-range-navigator": { - "localizationMap": { - "2 weeks": "2周", - "3 months": "3个月", - "6 months": "6个月", - "Apr": "4月", - "April": "四月", - "Aug": "8月", - "August": "八月", - "Custom Date Range": "自定义日期范围", - "Custom interval": "自定义间隔", - "Date Range Template": "日期范围模板", - "Date picker": "日期选择器", - "Day": "天", - "Dec": "12月", - "December": "十二月", - "Feb": "2月", - "February": "二月", - "Fri": "周五", - "Hour": "小时", - "Interval": "间隔", - "Jan": "1月", - "January": "一月", - "Jul": "7月", - "July": "七月", - "Jun": "6月", - "June": "六月", - "Last Month": "上个月", - "Last Week": "上个星期", - "Last Year": "去年", - "Mar": "3月", - "March": "三月", - "May": "5月", - "Mon": "周一", - "Month": "月", - "Nov": "11月", - "November": "十一月", - "Oct": "10月", - "October": "十月", - "Ok": "Ok", - "Sat": "周六", - "Sep": "9月", - "September": "九月", - "Step size": "步长", - "Sun": "周日", - "This Month": "这个月", - "This Week": "本星期", - "This Year": "今年", - "Thu": "周四", - "Today": "今天", - "Tue": "周二", - "Wed": "周三", - "Week": "周", - "Year": "年", - "Yesterday": "昨天" - } - }, - "input-widgets": { - "attribute-not-allowed": "属性参数不能在此小部件中使用", - "blocked-location": "在浏览器中阻止地理位置", - "claim-device": "声明设备", - "claim-failed": "声明设备失败!", - "claim-not-found": "找不到设备!", - "claim-successful": "设备已成功申领!", - "date": "日期", - "device-name": "设备名称", - "device-name-required": "设备名称必填", - "discard-changes": "放弃更改", - "enable-https-use-widget": "请启用HTTPS以使用此部件", - "entity-attribute-required": "实体属性必填", - "entity-coordinate-required": "纬度和经度两个字段都是必需的", - "entity-timeseries-required": "实体 Timeseries 必填", - "get-location": "获取当前位置", - "invalid-date": "无效日期", - "latitude": "纬度", - "longitude": "经度", - "max-value-error": "最大值是{{value}}", - "min-value-error": "最小值是{{value}}", - "no-attribute-selected": "未选择任何属性", - "no-coordinate-specified": "未指定纬度/经度的数据键", - "no-datakey-selected": "未选择数据键", - "no-entity-selected": "未选择实体", - "no-found-your-camera": "找不到摄像机", - "no-image": "没有图像", - "no-permission-camera": "权限被用户拒绝/此站点无权使用摄像机", - "no-support-geolocation": "您的浏览器不支持地理定位", - "no-support-web-camera": "您的浏览器不支持摄像头", - "no-timeseries-selected": "未选择 Timeseries", - "not-allowed-entity": "所选实体不能具有共享属性", - "secret-key": "密钥", - "secret-key-required": "密钥必填", - "switch-attribute-value": "切换实体属性值", - "switch-camera": "切换摄像机", - "switch-timeseries-value": "切换实体 Timeseries 值", - "take-photo": "拍照", - "time": "时间", - "timeseries-not-allowed": "Timeseries 参数不能用于此部件", - "update-attribute": "更新 attribute", - "update-failed": "更新失败", - "update-successful": "更新成功", - "update-timeseries": "更新 Timeseries", - "value": "价值" + "header-button": "顶部按钮clcik", + "open-dashboard-state": "切换到新仪表板状态", + "update-dashboard-state": "更新当前仪表板状态", + "open-dashboard": "切换到另一个仪表板", + "custom": "自定义动作", + "custom-pretty": "自定义操作(使用HTML模板)", + "mobile-action": "移动端动作", + "target-dashboard-state": "目标仪表板状态", + "target-dashboard-state-required": "目标仪表板状态必填", + "set-entity-from-widget": "从部件中设置实体", + "target-dashboard": "目标仪表板", + "open-right-layout": "打开右侧布局 (移动端视图)", + "state-display-type": "显示仪表板状态选项", + "open-normal": "普通", + "open-in-separate-dialog": "在单独的对话框中打开", + "open-in-popover": "在popover打开", + "dialog-title": "对话框标题", + "dialog-hide-dashboard-toolbar": "在对话框中隐藏仪表板工具栏", + "dialog-width": "对话框宽度相对视图宽度", + "dialog-height": "对话框高度相对视图高度", + "dialog-size-range-error": "对话框尺寸比值必须是1至100范围内。", + "popover-preferred-placement": "首选弹出位置", + "popover-placement-top": "上", + "popover-placement-topLeft": "左上", + "popover-placement-topRight": "右上", + "popover-placement-right": "右", + "popover-placement-rightTop": "右上", + "popover-placement-rightBottom": "右下", + "popover-placement-bottom": "下", + "popover-placement-bottomLeft": "左下", + "popover-placement-bottomRight": "右下", + "popover-placement-left": "左", + "popover-placement-leftTop": "左上", + "popover-placement-leftBottom": "左下", + "popover-hide-on-click-outside": "点击隐藏外面的弹出窗口", + "popover-hide-dashboard-toolbar": "隐藏仪表板工具栏", + "popover-width": "浏览器中的弹出宽度(例如100px, 25vw)单位", + "popover-height": "浏览器中的弹出高度(例如:100px,25vh)单位", + "popover-style": "弹出样式", + "open-new-browser-tab": "在新的浏览器选项卡中打开", + "mobile": { + "action-type": "手机端动作类型", + "action-type-required": "手机端动作类型必填。", + "take-picture-from-gallery": "画册拍照", + "take-photo": "拍照", + "map-direction": "打开地图说明", + "map-location": "打开地图位置", + "scan-qr-code": "扫描二维码", + "make-phone-call": "拨打电话", + "get-location": "获得位置", + "take-screenshot": "截图" + } + }, + "widgets-bundle": { + "current": "当前组", + "widgets-bundles": "部件包", + "add": "添加部件包", + "delete": "删除部件包", + "title": "标题", + "title-required": "标题必填。", + "title-max-length": "标题长度必须少于256个字符", + "description": "描述", + "image-preview": "图片预览", + "add-widgets-bundle-text": "添加新的部件包", + "no-widgets-bundles-text": "未找到部件包", + "empty": "部件包是空的", + "details": "详情", + "widgets-bundle-details": "部件包详细信息", + "delete-widgets-bundle-title": "确定要删除部件包 '{{widgetsBundleTitle}}'吗?", + "delete-widgets-bundle-text": "请注意:确认后,部件包和所有相关数据将不可恢复。", + "delete-widgets-bundles-title": "确定要删除 { count, plural, 1 {# 个部件包} other {# 个部件包} } 吗?", + "delete-widgets-bundles-action-title": "删除 { count, plural, 1 {# 个部件包} other {# 个部件包} }", + "delete-widgets-bundles-text": "请注意:确认后,所有选定的部件包将被删除,所有相关数据将不可恢复。", + "no-widgets-bundles-matching": "未找到与 '{{widgetsBundle}}' 匹配的部件包。", + "widgets-bundle-required": "部件包必填。", + "system": "系统", + "import": "导入部件包", + "export": "导出部件包", + "export-failed-error": "无法导出部件包: {{error}}", + "create-new-widgets-bundle": "创建新的部件包", + "widgets-bundle-file": "部件包文件", + "invalid-widgets-bundle-file-error": "无法导入部件包:无效的部件包数据结构。", + "search": "查找部件包", + "selected-widgets-bundles": "已选择 { count, plural, 1 {# 个部件包} other {# 个部件包} }", + "open-widgets-bundle": "打开部件包", + "loading-widgets-bundles": "加载部件包..." + }, + "widget-config": { + "data": "数据", + "settings": "设置", + "advanced": "高级", + "title": "标题", + "title-tooltip": "标题提示框", + "general-settings": "基础设置", + "display-title": "显示标题", + "drop-shadow": "阴影", + "enable-fullscreen": "启用全屏", + "background-color": "背景颜色", + "text-color": "文字颜色", + "padding": "内边距", + "margin": "外边距", + "widget-style": "部件风格", + "widget-css": "部件CSS", + "title-style": "标题风格", + "mobile-mode-settings": "移动端设置", + "order": "顺序", + "height": "高度", + "mobile-hide": "移动端隐藏部件", + "units": "特殊符号展示值", + "decimals": "浮点数后的位数", + "timewindow": "时间窗口", + "use-dashboard-timewindow": "使用仪表板的时间窗口", + "display-timewindow": "显示时间窗口", + "legend": "图例", + "display-legend": "显示图例", + "datasources": "数据源", + "maximum-datasources": "最大允许{ count, plural, 1 {1个数据源。} other {#个数据源。} }", + "timeseries-key-error": "应至少指定一个时间序列数据密钥", + "datasource-type": "类型", + "datasource-parameters": "参数", + "remove-datasource": "移除数据源", + "add-datasource": "添加数据源", + "target-device": "目标设备", + "alarm-source": "警报源", + "actions": "动作", + "action": "动作", + "add-action": "添加动作", + "search-actions": "搜索动作", + "no-actions-text": "找不到动作", + "action-source": "动作源", + "action-source-required": "动作源必填", + "action-name": "名称", + "action-name-required": "动作名称必填。", + "action-name-not-unique": "动作名称已经存在。
              相同动作源的动作名称必须唯一。", + "action-icon": "图标", + "show-hide-action-using-function": "使用函数显示/隐藏操作", + "action-type": "类型", + "action-type-required": "类型必填", + "edit-action": "编辑动作", + "delete-action": "删除删除", + "delete-action-title": "删除部件动作", + "delete-action-text": "确定要删除部件动作'{{actionName}}'吗?", + "title-icon": "标题图标", + "display-icon": "显示标题图标", + "icon-color": "图标颜色", + "icon-size": "图标大小", + "advanced-settings": "高级设置", + "data-settings": "数据设置", + "no-data-display-message": "\"无数据显示\" 替代消息", + "data-page-size": "每个数据源的最大实体数", + "settings-component-not-found": "找不到选择器'{{selector}}'的每个数据源设置窗体组件的最大实体数" + }, + "widget-type": { + "import": "导入部件类型", + "export": "导出部件类型", + "export-failed-error": "无法导出部件类型: {{error}}", + "create-new-widget-type": "创建新的部件类型", + "widget-type-file": "部件类型文件", + "invalid-widget-type-file-error": "无法导入部件类型:无效的部件类型数据结构。" + }, + "widgets": { + "chart": { + "common-settings": "通用设置", + "enable-stacking-mode": "启用堆叠模式", + "line-shadow-size": "线条阴影大小", + "display-smooth-lines": "显示光滑(弯曲)线条", + "default-bar-width": "默认条形宽度不聚合数据(毫秒)", + "bar-alignment": "条形对齐", + "bar-alignment-left": "左", + "bar-alignment-right": "右", + "bar-alignment-center": "中", + "default-font-size": "默认字体大小", + "default-font-color": "默认字体颜色", + "thresholds-line-width": "所有线条默认宽度", + "tooltip-settings": "提示栏设置", + "show-tooltip": "显示提示栏", + "hover-individual-points": "坐标悬停显示", + "show-cumulative-values": "在堆叠模式下显示累加数据", + "hide-zero-false-values": "隐藏提示栏中0或false值", + "tooltip-value-format-function": "提示栏格式化函数", + "grid-settings": "网格设置", + "show-vertical-lines": "显示垂直参考线", + "show-horizontal-lines": "显示水平参考线", + "grid-outline-border-width": "网格边框宽度(像系)", + "primary-color": "边框颜色", + "background-color": "背景颜色", + "ticks-color": "参考线颜色", + "xaxis-settings": "X轴设置", + "axis-title": "标题", + "xaxis-tick-labels-settings": "标签设置", + "show-tick-labels": "显示标签", + "yaxis-settings": "y轴设置", + "min-scale-value": "最小值", + "max-scale-value": "最大值", + "yaxis-tick-labels-settings": "标签设置", + "tick-step-size": "步长", + "number-of-decimals": "小数位数", + "ticks-formatter-function": "刻度格式化函数", + "comparison-settings": "比较设置", + "enable-comparison": "启用比较", + "time-for-comparison": "比较时期", + "time-for-comparison-previous-interval": "历史时间间隔(默认)", + "time-for-comparison-days": "一天前", + "time-for-comparison-weeks": "一周前", + "time-for-comparison-months": "一月前", + "time-for-comparison-years": "一年前", + "time-for-comparison-custom-interval": "自定义间隔", + "custom-interval-value": "自定义间隔值(毫秒)", + "comparison-x-axis-settings": "比较x轴设置", + "axis-position": "位置", + "axis-position-top": "上面(默认)", + "axis-position-bottom": "下面", + "custom-legend-settings": "自定义图例设置", + "enable-custom-legend": "启用自定义图例(你可以使用属性/时间序列标签)", + "key-name": "键名", + "key-name-required": "键名必填", + "key-type": "键类型", + "key-type-attribute": "属性", + "key-type-timeseries": "时间序列", + "label-keys-list": "在标签中使用键列表", + "no-label-keys": "没有配置键", + "add-label-key": "添加键", + "line-width": "线条宽度", + "color": "颜色", + "data-is-hidden-by-default": "默认隐藏数据", + "disable-data-hiding": "禁用用数据隐藏", + "remove-from-legend": "从图例中移除数据键", + "exclude-from-stacking": "从堆叠模式排除", + "line-settings": "线条设置", + "show-line": "显示线条", + "fill-line": "线条填充", + "points-settings": "点设置", + "show-points": "显示点", + "points-line-width": "宽度", + "points-radius": "圆角", + "point-shape": "形状", + "point-shape-circle": "圆形", + "point-shape-cross": "十字形", + "point-shape-diamond": "菱形", + "point-shape-square": "矩形", + "point-shape-triangle": "三角形", + "point-shape-custom": "自定义", + "point-shape-draw-function": "绘制函数", + "show-separate-axis": "显示独立轴", + "axis-position-left": "左", + "axis-position-right": "右", + "thresholds": "阈值", + "no-thresholds": "没有配置阈值", + "add-threshold": "添加阈值", + "show-values-for-comparison": "显示比较的历史值", + "comparison-values-label": "历史数什标签", + "threshold-settings": "阈值设置", + "use-as-threshold": "将值作为阈值", + "threshold-line-width": "阈值线条宽度", + "threshold-color": "阈值颜色", + "common-pie-settings": "饼图设置", + "radius": "圆角", + "inner-radius": "内圆角", + "tilt": "倾斜", + "stroke-settings": "斜线设置", + "width-pixels": "宽度(像素)", + "show-labels": "显示标签", + "animation-settings": "动画设置", + "animated-pie": "启用动画", + "border-settings": "边框设置", + "border-width": "边框宽度", + "border-color": "边框颜色", + "legend-settings": "图例设置", + "display-legend": "显示图例", + "labels-font-color": "标签字体颜色" + }, + "dashboard-state": { + "dashboard-state-settings": "仪表板状态设置", + "dashboard-state": "仪表板状态ID", + "autofill-state-layout": "自动填充状态布局高度", + "default-margin": "部件默认外边距", + "default-background-color": "默认背景色", + "sync-parent-state-params": "同步父仪表板状态参数" + }, + "date-range-navigator": { + "date-range-picker-settings": "日期范围选择设置", + "hide-date-range-picker": "隐藏日期范围选择", + "picker-one-panel": "日期范围选择板", + "picker-auto-confirm": "自动确认日期范围选择", + "picker-show-template": "日期范围选择显示模板", + "first-day-of-week": "一周的第一天", + "interval-settings": "间隔设置", + "hide-interval": "隐藏间隔", + "initial-interval": "初始间隔", + "interval-hour": "小时", + "interval-day": "天", + "interval-week": "周", + "interval-two-weeks": "2周", + "interval-month": "月", + "interval-three-months": "3个月", + "interval-six-months": "6个月", + "step-settings": "步长设置", + "hide-step-size": "步长设置", + "initial-step-size": "初始步长大小", + "hide-labels": "隐藏标签", + "use-session-storage": "使用会话存储", + "localizationMap": { + "Sun": "周日", + "Mon": "周一", + "Tue": "周二", + "Wed": "周三", + "Thu": "周四", + "Fri": "周五", + "Sat": "周六", + "Jan": "1月", + "Feb": "2月", + "Mar": "3月", + "Apr": "4月", + "May": "5月", + "Jun": "6月", + "Jul": "7月", + "Aug": "8月", + "Sep": "9月", + "Oct": "10月", + "Nov": "11月", + "Dec": "12月", + "January": "一月", + "February": "二月", + "March": "三月", + "April": "四月", + "June": "六月", + "July": "七月", + "August": "八月", + "September": "九月", + "October": "十月", + "November": "十一月", + "December": "十二月", + "Custom Date Range": "自定义日期范围", + "Date Range Template": "日期范围模板", + "Today": "今天", + "Yesterday": "昨天", + "This Week": "本星期", + "Last Week": "上星期", + "This Month": "本月", + "Last Month": "上月", + "Year": "年", + "This Year": "今年", + "Last Year": "去年", + "Date picker": "日期选择", + "Hour": "小时", + "Day": "天", + "Week": "周", + "2 weeks": "2周", + "Month": "月", + "3 months": "3个月", + "6 months": "6个月", + "Custom interval": "自定义间隔", + "Interval": "间隔", + "Step size": "步长", + "Ok": "确定" + } + }, + "entities-hierarchy": { + "hierarchy-data-settings": "层次数据设置", + "relations-query-function": "关系查询函数", + "has-children-function": "是否子级函数", + "node-state-settings": "状态设置", + "node-opened-function": "展开函数", + "node-disabled-function": "禁用函数", + "display-settings": "显示设置", + "node-icon-function": "icon函数", + "node-text-function": "文本函数", + "sort-settings": "排序设置", + "nodes-sort-function": "排序函数" + }, + "edge": { + "display-default-title": "显示默认标题" + }, + "gateway": { + "general-settings": "基础设置", + "widget-title": "部件村题", + "default-archive-file-name": "默认文件名称", + "device-type-for-new-gateway": "网关设备类型", + "messages-settings": "消息设置", + "save-config-success-message": "配置保存成功消息", + "device-name-exists-message": "设备名称已经存在消消息", + "gateway-title": "网关标题", + "read-only": "只读", + "events-title": "事件标题", + "events-filter": "事件过滤", + "event-key-contains": "包含事件key..." + }, + "gauge": { + "default-color": "默认颜色", + "radial-gauge-settings": "仪表盘设置", + "ticks-settings": "刻度设置", + "min-value": "最小值", + "max-value": "最大值", + "start-ticks-angle": "起始角度", + "ticks-angle": "结束角度", + "major-ticks-count": "主要刻度数量", + "major-ticks-color": "主要刻度颜色", + "minor-ticks-count": "次要刻度数量", + "minor-ticks-color": "次要刻度颜色", + "tick-numbers-font": "字体", + "unit-title-settings": "标题设置", + "show-unit-title": "显示标题", + "unit-title": "单位", + "title-font": "字体", + "units-settings": "单位设置", + "units-font": "字体", + "value-box-settings": "数值设置", + "show-value-box": "显示数值框", + "value-int": "长度", + "value-font": "字体", + "value-box-rect-stroke-color": "数值框矩形颜色", + "value-box-rect-stroke-color-end": "数值框矩形颜色渐变", + "value-box-background-color": "数值框背景色", + "value-box-shadow-color": "数值框阴影颜色", + "plate-settings": "表盘设置", + "show-plate-border": "显示边框", + "plate-color": "背景色", + "needle-settings": "指针设置", + "needle-circle-size": "针圈大小", + "needle-color": "颜色", + "needle-color-end": "渐变色", + "needle-color-shadow-up": "针头颜色", + "needle-color-shadow-down": "阴影颜色", + "highlights-settings": "色块设置", + "highlights-width": "色块宽度", + "highlights": "色块", + "highlight-from": "从", + "highlight-to": "到", + "highlight-color": "颜色", + "no-highlights": "没有配置色块", + "add-highlight": "添加色块", + "animation-settings": "动画设置", + "enable-animation": "启用动画", + "animation-duration": "动画时长", + "animation-rule": "动画类型", + "animation-linear": "线形", + "animation-quad": "方形", + "animation-quint": "五角形", + "animation-cycle": "环形", + "animation-bounce": "循环", + "animation-elastic": "弹跳", + "animation-dequad": "Dequad", + "animation-dequint": "Dequint", + "animation-decycle": "Decycle", + "animation-debounce": "Debounce", + "animation-delastic": "Delastic", + "linear-gauge-settings": "线型设置", + "bar-stroke-width": "量规宽度", + "bar-stroke-color": "量规颜色", + "bar-background-color": "量规背景色", + "bar-background-color-end": "量规背景渐变色", + "progress-bar-color": "进度条颜色", + "progress-bar-color-end": "进度条渐变色", + "major-ticks-names": "主要刻度名称", + "show-stroke-ticks": "显示主要刻度", + "major-ticks-font": "主要刻度字体", + "border-color": "边框颜色", + "border-width": "边框宽度", + "needle-circle-color": "指针颜色", + "animation-target": "动画触发", + "animation-target-needle": "指针", + "animation-target-plate": "表盘", + "common-settings": "通用设置", + "gauge-type": "仪表盘类型", + "gauge-type-arc": "弧形", + "gauge-type-donut": "环形", + "gauge-type-horizontal-bar": "水平", + "gauge-type-vertical-bar": "垂直", + "donut-start-angle": "角度从", + "bar-settings": "条形设置", + "relative-bar-width": "相对条宽", + "neon-glow-brightness": "霓虹灯效果亮度,(0-100),0-禁用效果", + "stripes-thickness": "条纹的厚度0是没有条纹", + "rounded-line-cap": "显示圆形线盖", + "bar-color-settings": "条颜色设置", + "use-precise-level-color-values": "使用精确的颜色值", + "bar-colors": "从下到上的条形颜色", + "color": "颜色", + "no-bar-colors": "没有配置条形颜色", + "add-bar-color": "添加条形颜色", + "from": "从", + "to": "到", + "fixed-level-colors": "连界值条形颜色", + "gauge-title-settings": "仪表盘标题设置", + "show-gauge-title": "显示仪表盘标题", + "gauge-title": "仪表盘标题", + "gauge-title-font": "仪表盘标题", + "unit-title-and-timestamp-settings": "单位标题和时间戳设置", + "show-timestamp": "显示值时间戳", + "timestamp-format": "时间戳格式化", + "label-font": "标签字体显示值", + "value-settings": "数值设置", + "show-value": "显示文本值", + "min-max-settings": "最小/最大标签设置", + "show-min-max": "显示最小值和最大值", + "min-max-font": "标签最大和最小字体", + "show-ticks": "显示刻度", + "tick-width": "刻度宽度", + "tick-color": "刻度颜色", + "tick-values": "刻度值", + "no-tick-values": "没有配置刻度值", + "add-tick-value": "添加刻度值" + }, + "gpio": { + "pin": "Pin", + "label": "标签", + "row": "行", + "column": "列", + "color": "颜色", + "panel-settings": "面板设置", + "background-color": "背景颜色", + "gpio-switches": "GPIO开关", + "no-gpio-switches": "没有配置GPIO开关", + "add-gpio-switch": "添加开关", + "gpio-status-request": "GPIO状态请求", + "method-name": "方法名", + "method-body": "方法体", + "gpio-status-change-request": "GPIO状态更改请求", + "parse-gpio-status-function": "GPIO状态解析函数", + "gpio-leds": "led", + "no-gpio-leds": "没有配置led", + "add-gpio-led": "添加LED" + }, + "html-card": { + "html": "HTML", + "css": "CSS" + }, + "input-widgets": { + "attribute-not-allowed": "属性参数不能在此小部件中使用", + "blocked-location": "在浏览器中阻止地理位置", + "claim-device": "声明设备", + "claim-failed": "声明设备失败!", + "claim-not-found": "找不到设备!", + "claim-successful": "设备已成功申领!", + "date": "日期", + "device-name": "设备名称", + "device-name-required": "设备名称必填", + "discard-changes": "放弃更改", + "entity-attribute-required": "实体属性必填", + "entity-coordinate-required": "纬度和经度两个字段都是必需的", + "entity-timeseries-required": "实体时间序列必填", + "get-location": "获取当前位置", + "invalid-date": "无效日期", + "latitude": "纬度", + "longitude": "经度", + "min-value-error": "最小值是{{value}}", + "max-value-error": "最大值是{{value}}", + "not-allowed-entity": "所选实体不能具有共享属性", + "no-attribute-selected": "未选择任何属性", + "no-datakey-selected": "未选择数据键", + "no-coordinate-specified": "未指定纬度/经度的数据键", + "no-entity-selected": "未选择实体", + "no-image": "没有图像", + "no-support-geolocation": "你的浏览器不支持地理定位", + "no-support-web-camera": "你的浏览器不支持摄像头", + "enable-https-use-widget": "请启用HTTPS以使用此部件", + "no-found-your-camera": "找不到摄像机", + "no-permission-camera": "权限被用户拒绝/此站点无权使用摄像机", + "no-timeseries-selected": "未选择时间序列", + "secret-key": "密钥", + "secret-key-required": "密钥必填", + "switch-attribute-value": "切换实体属性值", + "switch-camera": "切换摄像机", + "switch-timeseries-value": "切换实体时间序列值", + "take-photo": "拍照", + "time": "时间", + "timeseries-not-allowed": "时间序列参数不能用于此部件", + "update-failed": "更新失败", + "update-successful": "更新成功", + "update-attribute": "更新属性", + "update-timeseries": "更新时间序列", + "value": "数据值", + "general-settings": "基础设置", + "widget-title": "部件标题", + "claim-button-label": "声称按钮标签", + "show-secret-key-field": "显示“密钥”输入字段", + "labels-settings": "标签设置", + "show-labels": "显示标签", + "device-name-label": "设备名称设备名称输入字段的标签输入字段", + "secret-key-label": "设备名称设备密钥输入字段的标签输入字段", + "messages-settings": "信息设置", + "claim-device-success-message": "设备声明成功的文本信息", + "claim-device-not-found-message": "设备声明未找到信息", + "claim-device-failed-message": "设备声明失败的文本信息", + "claim-device-name-required-message": "设备声明“设备名称”必填的错误信息", + "claim-device-secret-key-required-message": "设备声明“设备密钥”必填的错误信息", + "show-label": "显示标签", + "label": "标签", + "required": "必填", + "required-error-message": "错误信息“必填”", + "show-result-message": "显示结果信息", + "integer-field-settings": "Integer字段设置", + "min-value": "最大值", + "max-value": "最小值", + "double-field-settings": "Double字段设置", + "text-field-settings": "Text字段设置", + "min-length": "最小长度", + "max-length": "最大长度", + "checkbox-settings": "Checkbox设置", + "true-label": "Checked标签", + "false-label": "Unchecked标签", + "image-input-settings": "Image字段设置", + "display-preview": "显示预览", + "display-clear-button": "显示清除按钮", + "display-apply-button": "显示应用按钮", + "display-discard-button": "显示弃用按钮", + "datetime-field-settings": "Date/time字段设置", + "display-time-input": "显示time输入", + "latitude-key-name": "Latitude键名", + "longitude-key-name": "Longitude键名", + "show-get-location-button": "显示“获取当前位置”按钮", + "use-high-accuracy": "使用高精度", + "location-fields-settings": "位置设置", + "latitude-label": "latitude标签", + "longitude-label": "longitude标签", + "input-fields-alignment": "对齐方式", + "input-fields-alignment-column": "列(默认)", + "input-fields-alignment-row": "行", + "latitude-field-required": "Latitude字段必填", + "longitude-field-required": "Longitude字段必填", + "attribute-settings": "属性设置", + "widget-mode": "部件模式", + "widget-mode-update-attribute": "更新属性", + "widget-mode-update-timeseries": "更新时间序列", + "attribute-scope": "属性范围", + "attribute-scope-server": "服务端属性", + "attribute-scope-shared": "共享属性", + "value-required": "启用数值必填", + "image-settings": "图片设置", + "image-format": "图片格式", + "image-format-jpeg": "JPEG", + "image-format-png": "PNG", + "image-format-webp": "WEBP", + "image-quality": "图片压缩", + "max-image-width": "最大宽度", + "max-image-height": "最大高度", + "action-buttons": "动作按钮", + "show-action-buttons": "显示动作按钮", + "update-all-values": "更新所有值", + "save-button-label": "“保存”按钮标签", + "reset-button-label": "“撤销”按钮标签", + "group-settings": "分组设置", + "show-group-title": "显示分组标题", + "group-title": "分组标题", + "fields-alignment": "对齐字段", + "fields-alignment-row": "行(默认)", + "fields-alignment-column": "列", + "fields-in-row": "行中的字段数", + "option-value": "值(为创建空选项编写“null”)", + "option-label": "标签", + "hide-input-field": "隐藏输入字段", + "datakey-type": "Datakey类型", + "datakey-type-server": "服务端属性(默认)", + "datakey-type-shared": "共享属性", + "datakey-type-timeseries": "时间序列", + "datakey-value-type": "Datakey值类型", + "datakey-value-type-string": "String", + "datakey-value-type-double": "Double", + "datakey-value-type-integer": "Integer", + "datakey-value-type-boolean-checkbox": "Boolean(多选)", + "datakey-value-type-boolean-switch": "Boolean(开关)", + "datakey-value-type-date-time": "Date & Time", + "datakey-value-type-date": "Date", + "datakey-value-type-time": "Time", + "datakey-value-type-select": "Select", + "value-is-required": "值是必填", + "ability-to-edit-attribute": "编辑属性的能力", + "ability-to-edit-attribute-editable": "可编辑(默认)", + "ability-to-edit-attribute-disabled": "禁用", + "ability-to-edit-attribute-readonly": "只读", + "disable-on-datakey-name": "禁用另一个datakey的错误值(指定datakey名称)", + "slide-toggle-settings": "滑块设置", + "slide-toggle-label-position": "滑动标签位置", + "slide-toggle-label-position-after": "后面", + "slide-toggle-label-position-before": "前面", + "select-options": "下拉选项", + "no-select-options": "没有配置下拉选项", + "add-select-option": "添加下接选项", + "numeric-field-settings": "数字字段设置", + "step-interval": "步长间隔", + "error-messages": "错误信息", + "min-value-error-message": "“最小值”错误信息", + "max-value-error-message": "“最大值”错误信息", + "invalid-date-error-message": "“无效日期”错误消息", + "icon-settings": "图标设置", + "use-custom-icon": "自定义图标", + "input-cell-icon": "输入单元格之前显示的图标", + "value-conversion-settings": "值转换设置", + "get-value-settings": "获取值设置", + "use-get-value-function": "启用获取值函数", + "get-value-function": "获取值函数", + "set-value-settings": "设置值设置", + "use-set-value-function": "启用值值函数", + "set-value-function": "启用函数" + }, + "invalid-qr-code-text": "无效的二维码文本。", + "qr-code": { + "use-qr-code-text-function": "启用二维码文本函数", + "qr-code-text-pattern": "二维码文本模式(例如:${entityName}|${keyName}一些文本。')", + "qr-code-text-pattern-hint": "二维码文本模式使用实体别名中第一个找到的键的值。", + "qr-code-text-pattern-required": "二维码文本必填。", + "qr-code-text-function": "二维码文本函数" + }, + "label-widget": { + "label-pattern": "模式", + "label-pattern-hint": "提示文本,如:'${keyName}单位。'或${#<key index>}单位'", + "label-pattern-required": "模式必填", + "label-position": "相对位置", + "x-pos": "X", + "y-pos": "Y", + "background-color": "背景色", + "font-settings": "字体设置", + "background-image": "背景图片", + "labels": "标签", + "no-labels": "没有配置标签", + "add-label": "添加标签" + }, + "navigation": { + "title": "标题", + "navigation-path": "导航路径", + "filter-type": "过滤类型", + "filter-type-all": "所有内容", + "filter-type-include": "包含内容", + "filter-type-exclude": "排除内容", + "items": "内容", + "enter-urls-to-filter": "输入URL进行过滤..." + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "消息类型", + "method": "方法", + "params": "参数", + "created-time": "创建时间", + "expiration-time": "到期时间", + "retries": "重试", + "status": "状态", + "filter": "过滤", + "refresh": "刷新", + "add": "添加RPC请求", + "details": "详情", + "delete": "删除", + "delete-request-title": "删除持续化RPC请求", + "delete-request-text": "您确定要删除请求吗?", + "details-title": "详情RPC ID: ", + "additional-info": "附加信息", + "response": "响应", + "any-status": "任何状态", + "rpc-status-list": "RPC状态列表", + "no-request-prompt": "无显示请求", + "send-request": "发送请求", + "add-title": "创建持续化RPC请求", + "method-error": "方法名必填。", + "timeout-error": "最小超时值为5000(5秒)。", + "white-space-error": "不允许使用空白。", + "rpc-status": { + "QUEUED": "QUEUED", + "SENT": "SENT", + "DELIVERED": "DELIVERED", + "SUCCESSFUL": "SUCCESSFUL", + "TIMEOUT": "TIMEOUT", + "EXPIRED": "EXPIRED", + "FAILED": "FAILED" + }, + "rpc-search-status-all": "所有", + "message-types": { + "false": "Two-way", + "true": "One-way" + }, + "general-settings": "基础设置", + "enable-filter": "启用过滤", + "enable-sticky-header": "滚动时显示标头", + "enable-sticky-action": "滚动时显示动作列", + "display-request-details": "显示请求详情", + "allow-send-request": "允许发送RPC请求", + "allow-delete-request": "允许删除请求", + "columns-settings": "设置列", + "display-columns": "显示列", + "column": "列", + "no-columns-found": "没有配置列", + "no-columns-matching": "'{{column}}'找不到。" + }, + "rpc": { + "value-settings": "设置值", + "initial-value": "初始值", + "retrieve-value-settings": "恢复开/关设置", + "retrieve-value-method": "恢复方法", + "retrieve-value-method-none": "无需恢复", + "retrieve-value-method-rpc": "RPC方法恢复", + "retrieve-value-method-attribute": "订阅属性", + "retrieve-value-method-timeseries": "订阅时间序列", + "attribute-value-key": "属性key", + "timeseries-value-key": "时序key", + "get-value-method": "RPC获取方法", + "parse-value-function": "解析函数", + "update-value-settings": "更新值设置", + "set-value-method": "RPC获取方法", + "convert-value-function": "转换函数", + "rpc-settings": "RPC设置", + "request-timeout": "RPC请求超(毫秒)", + "persistent-rpc-settings": "持久化RPC设置", + "request-persistent": "RPC请求持久化", + "persistent-polling-interval": " RPC持久化轮询间隔(毫秒)", + "common-settings": "通用设置", + "switch-title": "开关标题", + "show-on-off-labels": "显示开/关", + "slide-toggle-label": "滑块切换标签", + "label-position": "标签位置", + "label-position-before": "前面", + "label-position-after": "后面", + "slider-color": "滑块颜色", + "slider-color-primary": "Primary", + "slider-color-accent": "Accent", + "slider-color-warn": "Warn", + "button-style": "按钮样式", + "button-raised": "按钮凸起", + "button-primary": "原色", + "button-background-color": "背景色", + "button-text-color": "文字颜色", + "widget-title": "部件标题", + "button-label": "按钮标签", + "device-attribute-scope": "设备属性范围", + "server-attribute": "服务端属性", + "shared-attribute": "共享属性", + "device-attribute-parameters": "设备属性参数", + "is-one-way-command": "是否单向命令", + "rpc-method": "RPC方法", + "rpc-method-params": "RPC参数", + "show-rpc-error": "显示RPC命令执行错误", + "led-title": "LED标题", + "led-color": "LED颜色", + "check-status-settings": "检查状态设置", + "perform-rpc-status-check": "执行RPC设备状态检查", + "retrieve-led-status-value-method": "使用方法状态值恢复LED", + "led-status-value-attribute": "设备属性包含LED状态值", + "led-status-value-timeseries": "设备时间序列包含LED状态值", + "check-status-method": "RPC设备状态检查方法", + "parse-led-status-value-function": "解析函数", + "knob-title": "旋转按钮", + "min-value": "最小值", + "max-value": "最大值" + }, + "maps": { + "select-entity": "选择实体", + "select-entity-hint": "提示:选择后单击地图以设置位置", + "tooltips": { + "placeMarker": "单击放置'{{entityName}}'实体", + "firstVertex": "单击放置多边形'{{entityName}}'的第一个点", + "firstVertex-cut": "单击放置第一个点", + "continueLine": "单击继续绘制'{{entityName}}'多边形", + "continueLine-cut": "单击继续绘制", + "finishLine": "单击任何现有标记完成", + "finishPoly": "单击第一个标记完成'{{entityName}}'并保存", + "finishPoly-cut": "单击第一个标记完成并保存", + "finishRect": "单击'{{entityName}}'多边形完成并保存", + "startCircle": "单击'{{entityName}}'放置圆圈中心", + "finishCircle": "单击'{{entityName}}'完成圆圈", + "placeCircleMarker": "单击放置圆形标记" + }, + "actions": { + "finish": "完成", + "cancel": "取消", + "removeLastVertex": "删除最后一点" + }, + "buttonTitles": { + "drawMarkerButton": "放置实体", + "drawPolyButton": "创建多边形", + "drawLineButton": "创建多边形线条", + "drawCircleButton": "创建圆形", + "drawRectButton": "创建矩形", + "editButton": "编辑模式", + "dragButton": "拖放模式", + "cutButton": "剪切多边形区域", + "deleteButton": "移除", + "drawCircleMarkerButton": "创建圆形标志", + "rotateButton": "旋转多边形" + }, + "map-provider-settings": "地图设置", + "map-provider": "提供程序", + "map-provider-google": "Google地图", + "map-provider-openstreet": "OpenStreet地图", + "map-provider-here": "HERE地图", + "map-provider-image": "Image地图", + "map-provider-tencent": "Tencent地图", + "openstreet-provider": "OpenStreet地图提供程序", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik(默认)", + "openstreet-provider-hot": "OpenStreetMap.HOT", + "openstreet-provider-esri-street": "Esri.WorldStreetMap", + "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-esri-imagery": "Esri.WorldImagery", + "openstreet-provider-cartodb-positron": "CartoDB.Positron", + "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", + "use-custom-provider": "自定义提供程序", + "custom-provider-tile-url": "提供程序URL", + "google-maps-api-key": "Google地图Key", + "default-map-type": "默认地图类型", + "google-map-type-roadmap": "路线地图", + "google-map-type-satelite": "卫星", + "google-map-type-hybrid": "混合", + "google-map-type-terrain": "街道", + "map-layer": "地图", + "here-map-normal-day": "HERE.normalDay(默认)", + "here-map-normal-night": "HERE.normalNight", + "here-map-hybrid-day": "HERE.hybridDay", + "here-map-terrain-day": "HERE.terrainDay", + "credentials": "证书", + "here-app-id": "HERE地图id", + "here-app-code": "HERE地图code", + "tencent-maps-api-key": "Tencent地图Key", + "tencent-map-type-roadmap": "路线地图", + "tencent-map-type-satelite": "卫星", + "tencent-map-type-hybrid": "混合", + "image-map-background": "地图北景", + "image-map-background-from-entity-attribute": "从实体属性中获取背景图", + "image-url-source-entity-alias": "图像URL源实体别名", + "image-url-source-entity-attribute": "图像URL源实体属性", + "common-map-settings": "通用设置", + "x-pos-key-name": "X位置键名", + "y-pos-key-name": "Y位置键名", + "latitude-key-name": "Latitude键名", + "longitude-key-name": "Longitude键名", + "default-map-zoom-level": "地图缩放级别(1-20)", + "default-map-center-position": "地图中心位置(0,0)", + "disable-scroll-zooming": "地图中心位置", + "disable-double-click-zooming": "禁用双击缩放", + "disable-zoom-control-buttons": "禁用缩放按钮", + "fit-map-bounds": "拟合地图标记", + "use-default-map-center-position": "地图默认中心位置", + "entities-limit": "加载实体限制", + "markers-settings": "标记设置", + "marker-offset-x": "标记X宽度偏移量", + "marker-offset-y": "标记Y高度偏移量", + "position-function": "位置转换函数应返回x,y坐标", + "draggable-marker": "拖动标记", + "label": "标签设置", + "show-label": "显示标签", + "use-label-function": "标签函数", + "label-pattern": "标签模式(例如:'${entityName}', '${entityName}: (文本${keyName}单位)' )", + "label-function": "标签函数", + "tooltip": "提示栏设置", + "show-tooltip": "显示提示栏", + "show-tooltip-action": "提示拦动作", + "show-tooltip-action-click": "单击显示(默认)", + "show-tooltip-action-hover": "悬停显示", + "auto-close-tooltips": "自动关闭", + "use-tooltip-function": "启用函数", + "tooltip-pattern": "提示栏(例如:'文本${keyName}单位。'或 Link text')", + "tooltip-function": "提示栏函数", + "tooltip-offset-x": "提示栏x标记宽度偏移量", + "tooltip-offset-y": "提示栏y标记高度偏移量", + "color": "颜色设置", + "use-color-function": "启用函数", + "color-function": "颜色函数", + "marker-image": "图片标记设置", + "use-marker-image-function": "启用函数", + "custom-marker-image": "自定义图片标记", + "custom-marker-image-size": "自定义图片标记大小(像素)", + "marker-image-function": "自定义图片标记函数", + "marker-images": "图片标记", + "polygon-settings": "多边形设置", + "show-polygon": "启用多边形", + "polygon-key-name": "多边形键名", + "enable-polygon-edit": "启用编辑", + "polygon-label": "标签", + "show-polygon-label": "启用标签", + "use-polygon-label-function": "启用函数", + "polygon-label-pattern": "标签模式(例如: '${entityName}', '${entityName}:(文本${keyName}单位)' )", + "polygon-label-function": "标签函数", + "polygon-tooltip": "提示栏", + "show-polygon-tooltip": "启用提示栏", + "auto-close-polygon-tooltips": "自动关闭", + "use-polygon-tooltip-function": "启用函数", + "polygon-tooltip-pattern": "提示栏(例如:'文本${keyName}单位'或Link text')", + "polygon-tooltip-function": "提示栏函数", + "polygon-color": "颜色", + "polygon-opacity": "透明度”", + "use-polygon-color-function": "启用函数", + "polygon-color-function": "颜色函数", + "polygon-stroke": "斜线", + "stroke-color": "斜线颜色", + "stroke-opacity": "透明度", + "stroke-weight": "宽度", + "use-polygon-stroke-color-function": "启用函数", + "polygon-stroke-color-function": "颜色函数", + "circle-settings": "圆形设置", + "show-circle": "启用圆形", + "circle-key-name": "圆形键名", + "enable-circle-edit": "启用编辑", + "circle-label": "标签", + "show-circle-label": "启用标签", + "use-circle-label-function": "启用函数", + "circle-label-pattern": "标签模式(例如:'${entityName}', '${entityName}:(文本${keyName}单位)')", + "circle-label-function": "标签函数", + "circle-tooltip": "提示栏", + "show-circle-tooltip": "显示提示栏", + "auto-close-circle-tooltips": "自动关闭", + "use-circle-tooltip-function": "启用函数", + "circle-tooltip-pattern": "提示栏(例如:'文本${keyName}单位。'或Link text')", + "circle-tooltip-function": "提示栏函数", + "circle-fill-color": "填充色", + "circle-fill-color-opacity": "透明度", + "use-circle-fill-color-function": "启用函数", + "circle-fill-color-function": "填充颜色函数", + "circle-stroke": "斜线设置", + "use-circle-stroke-color-function": "启用函数", + "circle-stroke-color-function": "颜色函数", + "markers-clustering-settings": "标记集群设置", + "use-map-markers-clustering": "启用地图标记集群", + "zoom-on-cluster-click": "单击群集时变焦", + "max-cluster-zoom": "集群最大的缩放比例(0-18)", + "max-cluster-radius-pixels": "最大半径", + "cluster-zoom-animation": "放大动画", + "show-markers-bounds-on-cluster-mouse-over": "显示鼠标在群集上时显示标记的边界", + "spiderfy-max-zoom-level": "最大缩放比例(查看所有群集标记)", + "load-optimization": "负载优化", + "cluster-chunked-loading": "块加载集群标记", + "cluster-markers-lazy-load": "延迟加载集群标记", + "editor-settings": "编辑设置", + "enable-snapping": "启用顶点捕捉", + "init-draggable-mode": "启用拖动模式初始化地图", + "hide-all-edit-buttons": "隐藏所有按钮", + "hide-draw-buttons": "隐藏绘制按钮", + "hide-edit-buttons": "隐藏编辑按钮", + "hide-remove-button": "隐藏删除按钮", + "route-map-settings": "路由设置", + "trip-animation-settings": "旅行动画设置", + "normalization-step": "正常数据步长(ms)", + "tooltip-background-color": "工具提示背景颜色", + "tooltip-font-color": "工具提示字体颜色", + "tooltip-opacity": "工具提示不透明度(0-1)", + "auto-close-tooltip": "自动关闭工具提示", + "rotation-angle": "设置标记的附加旋转角度(度)", + "path-settings": "路径设置", + "path-color": "路径颜色", + "use-path-color-function": "使用路径颜色功能", + "path-color-function": "路径颜色功能", + "path-decorator": "路径装饰器", + "use-path-decorator": "使用路径装饰器", + "decorator-symbol": "装饰符号", + "decorator-symbol-arrow-head": "箭头", + "decorator-symbol-dash": "短跑", + "decorator-symbol-size": "装饰器符号尺寸(像素)", + "use-path-decorator-custom-color": "使用路径装饰器自定义颜色", + "decorator-custom-color": "装饰器定制颜色", + "decorator-offset": "装饰器偏移", + "end-decorator-offset": "结束装饰器偏移", + "decorator-repeat": "装饰器重复", + "points-settings": "点设置", + "show-points": "显示点", + "point-color": "点颜色", + "point-size": "点大小(像素)", + "use-point-color-function": "使用点颜色功能", + "point-color-function": "点颜色函数", + "use-point-as-anchor": "使用点作为锚", + "point-as-anchor-function": "点为锚函数", + "independent-point-tooltip": "独立点工具提示", + "clustering-markers": "集群标记", + "use-icon-create-function": "启用集群标记", + "marker-color-function": "标记颜色函数" + }, + "markdown": { + "use-markdown-text-function": "使用markdown/HTML函数", + "markdown-text-function": "Markdown/HTML函数", + "markdown-text-pattern": "Markdown/HTML模式(markdown或HTML变量, 例如:'${entityName}或${keyName}一些文本')", + "markdown-css": "Markdown/HTML CSS" + }, + "simple-card": { + "label-position": "标签位置", + "label-position-left": "左", + "label-position-top": "上" + }, + "table": { + "common-table-settings": "表格设置", + "enable-search": "启用搜索", + "enable-sticky-header": "始终显示标题", + "enable-sticky-action": "始终显示动作", + "hidden-cell-button-display-mode": "隐藏单元按钮操作显示模式", + "show-empty-space-hidden-action": "显示空空间而不是隐藏的单元按钮动作", + "dont-reserve-space-hidden-action": "不要为隐藏动作按钮保留空间", + "display-timestamp": "显示时间", + "display-milliseconds": "显示毫秒", + "display-pagination": "显示分页", + "default-page-size": "分页数量", + "use-entity-label-tab-name": "实体标签名称", + "hide-empty-lines": "隐藏空线", + "row-style": "行样式", + "use-row-style-function": "启用样式函数", + "row-style-function": "样式函数", + "cell-style": "列样式", + "use-cell-style-function": "启用样式函数", + "cell-style-function": "样式函数", + "cell-content": "内容", + "use-cell-content-function": "启用内容函数", + "cell-content-function": "内容函数", + "show-latest-data-column": "显示最新数据列", + "latest-data-column-order": "样式函数", + "entities-table-title": "实体表格标题", + "enable-select-column-display": "启用数据列", + "display-entity-name": "显示实体名称", + "entity-name-column-title": "实体名称列标题", + "display-entity-label": "显示实体标签", + "entity-label-column-title": "实体标签列标题", + "display-entity-type": "显示实体类型", + "default-sort-order": "默认排序", + "custom-title": "Custom header title", + "column-width": "列宽", + "default-column-visibility": "默认显示", + "column-visibility-visible": "显示", + "column-visibility-hidden": "隐藏", + "column-visibility-hidden-mobile": "Hidden in mobile mode", + "column-selection-to-display": "“要显示”列中的列选择", + "column-selection-to-display-enabled": "启用", + "column-selection-to-display-disabled": "禁用", + "alarms-table-title": "警报标题", + "enable-alarms-selection": "启用警报选择", + "enable-alarms-search": "启用警报搜索", + "enable-alarm-filter": "启用警报过滤器", + "display-alarm-details": "显示警报详细", + "allow-alarms-ack": "允许确认警报", + "allow-alarms-clear": "允许清除警报" + }, + "value-source": { + "value-source": "数值源", + "predefined-value": "预定义值", + "entity-attribute": "从实体属性中获取值", + "value": "数据值", + "source-entity-alias": "实体别", + "source-entity-attribute": "实体属性" + }, + "widget-font": { + "font-family": "字体", + "size": "大小", + "relative-font-size": "相对字体大小", + "font-style": "样式", + "font-style-normal": "常规", + "font-style-italic": "斜体", + "font-style-oblique": "倾斜", + "font-weight": "字形", + "font-weight-normal": "常规", + "font-weight-bold": "加粗", + "font-weight-bolder": "相对加粗", + "font-weight-lighter": "相对常规", + "color": "颜色", + "shadow-color": "阴影颜色" + } + }, + "icon": { + "icon": "图标", + "select-icon": "选择图标", + "material-icons": "素材图标", + "show-all": "显示所有图标" + }, + "phone-input": { + "phone-input-label": "手机号码", + "phone-input-required": "手机号码必填", + "phone-input-validation": "手机号码无效或不存在", + "phone-input-pattern": "无效的手机号码。应为E.164格式,例如:{{phoneNumber}}", + "phone-input-hint": "E.164格式手机号码,例如:{{phoneNumber}}" + }, + "custom": { + "widget-action": { + "action-cell-button": "单元格click", + "row-click": "数据行click", + "polygon-click": "多边形click", + "marker-click": "标记click", + "circle-click": "圆形click", + "tooltip-tag-action": "提示框click", + "node-selected": "节点选中click", + "element-click": "HTML元素click", + "pie-slice-click": " 饼状click", + "row-double-click": "双击clcik" + } + }, + "paginator": { + "items-per-page": "每页数量:", + "first-page-label": "第一页", + "last-page-label": "最后一页", + "next-page-label": "下一页", + "previous-page-label": "上一页", + "items-per-page-separator": "-" + }, + "language": { + "language": "语言", + "locales": { + "de_DE": "德语", + "fr_FR": "法语", + "zh_CN": "简体中文", + "zh_TW": "繁體中文", + "en_US": "英语", + "it_IT": "意大利语", + "ko_KR": "韩语", + "ru_RU": "俄罗斯语", + "es_ES": "西班牙语", + "es_CA": "Catalan", + "ja_JP": "日本語", + "tr_TR": "土耳其语", + "fa_IR": "波斯语", + "uk_UA": "乌克兰语", + "cs_CZ": "捷克语", + "el_GR": "希腊语", + "ro_RO": "罗马尼亚语", + "lv_LV": "拉脱维亚语", + "ka_GE": "格鲁吉亚语", + "pt_BR": "葡萄牙语", + "sl_SI": "斯洛文尼亚语" + } } - } } diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json index 6ddaedc120..e5a54a6198 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1,1607 +1,4618 @@ { - "access": { - "unauthorized": "未授權", - "unauthorized-access": "未授權存取", - "unauthorized-access-text": "您需要登入才能存取這個資源!", - "access-forbidden": "禁止存取", - "access-forbidden-text": "您沒有存取此位置的權限
              如果您仍希望存取此位置,請嘗試使用其他用戶登入。", - "refresh-token-expired": "Session 已過期", - "refresh-token-failed": "無法更新 Session" - }, - "action": { - "activate": "啟動", - "suspend": "暫停", - "save": "儲存", - "saveAs": "另存為", - "cancel": "取消", - "ok": "確定", - "delete": "刪除", - "add": "增加", - "yes": "是", - "no": "否", - "update": "更新", - "remove": "移除", - "search": "查詢", - "clear-search": "清除查詢", - "assign": "分配", - "unassign": "取消分配", - "share": "分享", - "make-private": "私有", - "apply": "應用", - "apply-changes": "應用更改", - "edit-mode": "編輯模式", - "enter-edit-mode": "進入編輯模式", - "decline-changes": "取消更改", - "close": "關閉", - "back": "返回", - "run": "執行", - "sign-in": "登入!", - "edit": "編輯", - "view": "查看", - "create": "建立", - "drag": "拖拉", - "refresh": "更新", - "undo": "取消", - "copy": "複製", - "paste": "貼上", - "copy-reference": "複製引用", - "paste-reference": "貼上引用", - "import": "匯入", - "export": "匯出", - "share-via": "通過 {{provider}}分享" - }, - "aggregation": { - "aggregation": "聚合", - "function": "資料聚合功能", - "limit": "最大值", - "group-interval": "分組間隔", - "min": "最少值", - "max": "最大值", - "avg": "平均值", - "sum": "總計", - "count": "Count", - "none": "空" - }, - "admin": { - "general": "一般", - "general-settings": "一般設定", - "outgoing-mail": "發送郵件", - "outgoing-mail-settings": "發送郵件設定", - "system-settings": "系統設定", - "test-mail-sent": "測試郵件發送成功!", - "base-url": "基本URL", - "base-url-required": "基本URL必填。", - "mail-from": "郵件來自", - "mail-from-required": "郵件發件人必填。", - "smtp-protocol": "SMTP協定", - "smtp-host": "SMTP主機", - "smtp-host-required": "SMTP主機必填。", - "smtp-port": "SMTP連接埠", - "smtp-port-required": "您必須提供一個smtp連接埠。", - "smtp-port-invalid": "這看起來不是有效的smtp連接埠。", - "timeout-msec": "超時(ms)", - "timeout-required": "超時必填。", - "timeout-invalid": "這看起來不像有效的超時值。", - "enable-tls": "啟用TLS", - "tls-version": "TLS版本", - "send-test-mail": "發送測試郵件" - }, - "alarm": { - "alarm": "警告", - "alarms": "警告", - "select-alarm": "選擇警告", - "no-alarms-matching": "沒有找到符合 '{{entity}}' 的警告", - "alarm-required": "警告必填", - "alarm-status": "警告狀態", - "search-status": { - "ANY": "所有", - "ACTIVE": "已啟動", - "CLEARED": "已清除", - "ACK": "已回覆", - "UNACK": "未回覆" - }, - "display-status": { - "ACTIVE_UNACK": "啟動未回覆", - "ACTIVE_ACK": "啟動已回覆", - "CLEARED_UNACK": "清除未回覆", - "CLEARED_ACK": "清除已回覆" - }, - "no-alarms-prompt": "未發現警告", - "created-time": "建立時間", - "type": "類型", - "severity": "嚴重程度", - "originator": "起因", - "originator-type": "起因類型", - "details": "詳細資訊", - "status": "狀態", - "alarm-details": "警告詳細資訊", - "start-time": "開始時間", - "end-time": "結束時間", - "ack-time": "回覆時間", - "clear-time": "建立時間", - "severity-critical": "危險", - "severity-major": "重要", - "severity-minor": "次要", - "severity-warning": "警告", - "severity-indeterminate": "不確定", - "acknowledge": "回覆", - "clear": "清除", - "search": "搜尋警告", - "selected-alarms": "已選擇 { count, plural, 1 {1 警告} other {# 警告} } ", - "no-data": "無資料顯示", - "polling-interval": "警告輪詢間隔(秒)", - "polling-interval-required": "警告輪詢間隔必填。", - "min-polling-interval-message": "輪詢間隔至少是1秒。", - "aknowledge-alarms-title": "回覆 { count, plural, 1 {1 警告} other {# 警告} }", - "aknowledge-alarms-text": "確定要回覆 { count, plural, 1 {1 警告} other {# 警告} }?", - "clear-alarms-title": "清除 { count, plural, 1 {1 警告} other {# 警告} }", - "clear-alarms-text": "確定要清除 { count, plural, 1 {1 警告} other {# 警告} }?" - }, - "alias": { - "add": "增加別名", - "edit": "編輯別名", - "name": "別名", - "name-required": "別名必填", - "duplicate-alias": "別名已經存在。", - "filter-type-single-entity": "單一實體", - "filter-type-entity-list": "實體列表", - "filter-type-entity-name": "實體名稱", - "filter-type-state-entity": "實體(儀表板狀態)", - "filter-type-state-entity-description": "實體令牌(儀表板狀態參數)", - "filter-type-asset-type": "資產類型", - "filter-type-asset-type-description": "類型為 '{{assetType}}' 的資產", - "filter-type-asset-type-and-name-description": "類型為 '{{assetType}}' 且以 '{{prefix}}' 開頭的資產", - "filter-type-device-type": "設備類型", - "filter-type-device-type-description": "類型為 '{{deviceType}}' 的設備", - "filter-type-device-type-and-name-description": "類型為 '{{deviceType}}' 且以 '{{prefix}}' 開頭的設備", - "filter-type-entity-view-type": "實體視圖類型", - "filter-type-entity-view-type-description": "類型為 '{{entityView}}' 的實體視圖", - "filter-type-entity-view-type-and-name-description": "類型為 {{entityView}}' 且以 '{{prefix}}' 開頭的實體視圖", - "filter-type-relations-query": "關係查詢", - "filter-type-relations-query-description": "具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的 {{entities}} ", - "filter-type-asset-search-query": "資產搜尋查詢", - "filter-type-asset-search-query-description": "類型為 {{assetTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的資產", - "filter-type-device-search-query": "設備搜尋查詢", - "filter-type-device-search-query-description": "類型為 {{deviceTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的設備", - "filter-type-entity-view-search-query": "實體視圖搜尋查詢", - "filter-type-entity-view-search-query-description": "類型為 {{entityViewTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的實體視圖", - "entity-filter": "實體過濾", - "resolve-multiple": "解決為多實體", - "filter-type": "過濾類型", - "filter-type-required": "過濾類型必填。", - "entity-filter-no-entity-matched": "未找到符合指定過濾條件的實體。", - "no-entity-filter-specified": "沒有指定實體過濾條件", - "root-state-entity": "使用儀表板狀態實體作為根實體", - "root-entity": "根實體", - "state-entity-parameter-name": "狀態實體參數名稱", - "default-state-entity": "預設狀態實體", - "default-entity-parameter-name": "預設", - "max-relation-level": "最大關係層級", - "unlimited-level": "不限層級", - "state-entity": "儀表板狀態實體", - "all-entities": "所有實體", - "any-relation": "不限" - }, - "asset": { - "asset": "資產", - "assets": "資產", - "management": "資產管理", - "view-assets": "查看資產", - "add": "增加資產", - "assign-to-customer": "分配給客戶", - "assign-asset-to-customer": "將資產分配給客戶", - "assign-asset-to-customer-text": "請選擇要分配給客戶的資產", - "no-assets-text": "未找到資產", - "assign-to-customer-text": "請選擇客戶以分配資產", - "public": "公開", - "assignedToCustomer": "分配客戶", - "make-public": "資產設為公開", - "make-private": "資產設為私有", - "unassign-from-customer": "取消分配客戶", - "delete": "刪除資產", - "asset-public": "資產公開", - "asset-type": "資產類型", - "asset-type-required": "資產類型必填。", - "select-asset-type": "選擇資產類型", - "enter-asset-type": "輸入資產類型", - "any-asset": "任何資產", - "no-asset-types-matching": "沒有找到符合 '{{entitySubtype}}' 的資產類型。", - "asset-type-list-empty": "資產類型未選擇。", - "asset-types": "資產類型", - "name": "名稱", - "name-required": "名稱必填。", - "description": "描述", - "type": "類型", - "type-required": "類型必填。", - "details": "詳細資訊", - "events": "事件", - "add-asset-text": "增加新資產", - "asset-details": "資產詳細資訊", - "assign-assets": "分配資產", - "assign-assets-text": "分配 { count, plural, 1 {1 資產} other {# 資產} } 給客戶", - "delete-assets": "刪除資產", - "unassign-assets": "取消分配資產", - "unassign-assets-action-title": "從客戶處取消分配 { count, plural, 1 {1 資產} other {# 資產} } ", - "assign-new-asset": "分配新資產", - "delete-asset-title": "確定要刪除資產 '{{assetName}}'?", - "delete-asset-text": "小心!確認後資產及其所有相關資料將無法恢復。", - "delete-assets-title": "確定要刪除 { count, plural, 1 {1 資產} other {# 資產} }?", - "delete-assets-action-title": "刪除 { count, plural, 1 {1 資產} other {# 資產} }", - "delete-assets-text": "小心,確認後,所有選擇的資產將被刪除,所有相關的資料將變得無法恢復。", - "make-public-asset-title": "你確定你想建立公開'{{assetName}}'資產?", - "make-public-asset-text": "確認後,資產及其所有資料將被公開並被他人存取。", - "make-private-asset-title": "你確定你想建立私有 '{{assetName}}' 資產?", - "make-private-asset-text": "確認後,資產及其所有資料將被私有化,無法被他人存取。", - "unassign-asset-title": "您確定要取消對'{{assetName}}'資產的分配嗎?", - "unassign-asset-text": "確認後,資產將未分配,客戶無法存取。", - "unassign-asset": "未分配資產", - "unassign-assets-title": "您確定要取消分配 { count, plural, 1 {1 資產} other {# 資產} }嗎?", - "unassign-assets-text": "確認後,所有選擇的資產將被分配,客戶無法存取。", - "copyId": "複製資產ID", - "idCopiedMessage": "資產ID已經複製到剪貼簿", - "select-asset": "選擇資產", - "no-assets-matching": "沒有找到符合 '{{entity}}' 的資產。", - "asset-required": "資產必填", - "name-starts-with": "資產名稱以此開頭", - "label": "標籤" - }, - "attribute": { - "attributes": "屬性", - "latest-telemetry": "最新遙測", - "attributes-scope": "設備屬性範圍", - "scope-latest-telemetry": "最新遙測", - "scope-client": "客戶端屬性", - "scope-server": "服務端屬性", - "scope-shared": "共享屬性", - "add": "增加屬性", - "key": "鍵", - "last-update-time": "最後更新時間", - "key-required": "屬性鍵必填。", - "value": "值", - "value-required": "屬性值必填。", - "delete-attributes-title": "您確定要刪除 { count, plural, 1 {1 屬性} other {# 屬性} }嗎?", - "delete-attributes-text": "注意,確認後所有選中的屬性都會被刪除。", - "delete-attributes": "刪除屬性", - "enter-attribute-value": "輸入屬性值", - "show-on-widget": "在部件上顯示", - "widget-mode": "部件模式", - "next-widget": "下一個部件", - "prev-widget": "上一個部件", - "add-to-dashboard": "增加到儀表板", - "add-widget-to-dashboard": "將部件增加到儀表板", - "selected-attributes": "{ count, plural, 1 {1 屬性} other {# 屬性} } 被選中", - "selected-telemetry": "{ count, plural, 1 {1 遙測} other {# 遙測} } 被選中" - }, - "audit-log": { - "audit": "審計", - "audit-logs": "審計日誌", - "timestamp": "時間戳", - "entity-type": "實體類型", - "entity-name": "實體名稱", - "user": "用戶", - "type": "類型", - "status": "狀態", - "details": "詳細資訊", - "type-added": "增加", - "type-deleted": "刪除", - "type-updated": "更新", - "type-attributes-updated": "更新屬性", - "type-attributes-deleted": "刪除屬性", - "type-rpc-call": "RPC調用", - "type-credentials-updated": "更新憑證", - "type-assigned-to-customer": "分配給客戶", - "type-unassigned-from-customer": "未分配給客戶", - "type-activated": "啟動", - "type-suspended": "暫停", - "type-credentials-read": "讀取憑證", - "type-attributes-read": "讀取屬性", - "status-success": "成功", - "status-failure": "失敗", - "audit-log-details": "審計日誌詳細資訊", - "no-audit-logs-prompt": "找不到日誌", - "action-data": "活動資料", - "failure-details": "失敗詳細資訊", - "search": "查找審計日誌", - "clear-search": "清空查找" - }, - "confirm-on-exit": { - "message": "您有未儲存的更改。確定要離開此頁嗎?", - "html-message": "您有未儲存的更改。
              確定要離開此頁面嗎?", - "title": "未儲存的更改" - }, - "contact": { - "country": "國家", - "city": "城市", - "state": "州", - "postal-code": "郵政編碼", - "postal-code-invalid": "只允許數字。", - "address": "地址", - "address2": "地址2", - "phone": "手機", - "email": "郵箱", - "no-address": "無地址" - }, - "common": { - "username": "用戶名", - "password": "密碼", - "enter-username": "輸入用戶名", - "enter-password": "輸入密碼", - "enter-search": "輸入檢索條件", - "created-time": "建立時間" - }, - "content-type": { - "json": "Json", - "text": "Text", - "binary": "Binary (Base64)" - }, - "customer": { - "customer": "客戶", - "customers": "客戶", - "management": "客戶管理", - "dashboard": "客戶儀表板", - "dashboards": "客戶儀表板", - "devices": "客戶設備", - "entity-views": "客戶實體視圖", - "assets": "客戶資產", - "public-dashboards": "公共儀表板", - "public-devices": "公共設備", - "public-assets": "公共資產", - "public-entity-views": "公共實體視圖", - "add": "增加客戶", - "delete": "刪除客戶", - "manage-customer-users": "管理客戶用戶", - "manage-customer-devices": "管理客戶設備", - "manage-customer-dashboards": "管理客戶儀表板", - "manage-public-devices": "管理公共設備", - "manage-public-dashboards": "管理公共儀表板", - "manage-customer-assets": "管理客戶資產", - "manage-public-assets": "管理公共資產", - "add-customer-text": "增加新客戶", - "no-customers-text": "沒有找到客戶", - "customer-details": "客戶詳細資訊", - "delete-customer-title": "您確定要刪除客戶'{{customerTitle}}'嗎?", - "delete-customer-text": "小心!確認後,客戶及其所有相關資料將無法恢復。", - "delete-customers-title": "您確定要刪除 { count, plural, 1 {1 客戶} other {# 客戶} }嗎?", - "delete-customers-action-title": "刪除 { count, plural, 1 {1 客戶} other {# 客戶} }", - "delete-customers-text": "小心!確認後,所有選擇的客戶將被刪除,所有相關資料將無法恢復。", - "manage-users": "管理用戶", - "manage-assets": "管理資產", - "manage-devices": "管理設備", - "manage-dashboards": "管理儀表板", - "title": "標題", - "title-required": "需要標題", - "description": "描述", - "details": "詳細資訊", - "events": "事件", - "copyId": "複製客戶ID", - "idCopiedMessage": "客戶ID已複製到剪貼板", - "select-customer": "選擇客戶", - "no-customers-matching": "沒有找到符合 '{{entity}}' 的客戶。", - "customer-required": "客戶是必選項", - "select-default-customer": "選擇預設的客戶", - "default-customer": "預設客戶", - "default-customer-required": "為了測試租戶級別上的儀表板,需要預設客戶。" - }, - "datetime": { - "date-from": "日期從", - "time-from": "時間從", - "date-to": "日期到", - "time-to": "時間到" - }, - "dashboard": { - "dashboard": "儀表板", - "dashboards": "儀表板庫", - "management": "儀表板管理", - "view-dashboards": "查看儀表板", - "add": "增加儀表板", - "assign-dashboard-to-customer": "將儀表板分配給客戶", - "assign-dashboard-to-customer-text": "請選擇要分配給客戶的儀表板", - "assign-to-customer-text": "請選擇客戶分配儀表板", - "assign-to-customer": "分配給客戶", - "unassign-from-customer": "取消分配客戶", - "make-public": "儀表板設為公開", - "make-private": "儀表板設為私有", - "manage-assigned-customers": "管理已分配的客戶", - "assigned-customers": "已分配的客戶", - "assign-to-customers": "將儀表板分配給客戶", - "assign-to-customers-text": "請選擇客戶指定儀表板", - "unassign-from-customers": "客戶未分配儀表板", - "unassign-from-customers-text": "請選擇從儀表板中取消分配的客戶", - "no-dashboards-text": "沒有找到儀表板", - "no-widgets": "沒有配置部件", - "add-widget": "增加新的部件", - "title": "標題", - "select-widget-title": "選擇部件", - "select-widget-subtitle": "可用的部件類型列表", - "delete": "刪除儀表板", - "title-required": "需要標題。", - "description": "描述", - "details": "詳細資訊", - "dashboard-details": "儀表板詳細資訊", - "add-dashboard-text": "增加新的儀表板", - "assign-dashboards": "分配儀表板", - "assign-new-dashboard": "分配新的儀表板", - "assign-dashboards-text": "分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", - "unassign-dashboards-action-text": "未分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", - "delete-dashboards": "刪除儀表板", - "unassign-dashboards": "取消分配儀表板", - "unassign-dashboards-action-title": "從客戶處取消分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } ", - "delete-dashboard-title": "您確定要刪除儀表板 '{{dashboardTitle}}'嗎?", - "delete-dashboard-text": "小心!確認後儀表板及其所有相關資料將無法恢復。", - "delete-dashboards-title": "你確定你要刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }嗎?", - "delete-dashboards-action-title": "刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }", - "delete-dashboards-text": "小心!確認後所有選擇的儀表板將被刪除,所有相關資料將無法恢復。", - "unassign-dashboard-title": "您確定要取消分配儀表板 '{{dashboardTitle}}'嗎?", - "unassign-dashboard-text": "確認後,面板將被取消分配,客戶將無法存取。", - "unassign-dashboard": "取消分配儀表板", - "unassign-dashboards-title": "您確定要取消分配儀表板 { count, plural, 1 {1 儀表板} other {# 儀表板} } 嗎?", - "unassign-dashboards-text": "確認後,所有選擇的儀表板將被取消分配,客戶將無法存取。", - "public-dashboard-title": "儀表板現已公佈", - "public-dashboard-text": "你的儀表板{{dashboardTitle}} 已被公開,可通過如下連結存取:", - "public-dashboard-notice": "提示: 不要忘記將相關設備公開以存取其資料。", - "make-private-dashboard-title": "您確定要將儀表板 '{{dashboardTitle}}' 設為私有嗎?", - "make-private-dashboard-text": "確認後,儀表板將被設為私有,不能被其他人存取。", - "make-private-dashboard": "儀表板設為私有", - "socialshare-text": "'{{dashboardTitle}}' 由Thingsboard提供支持", - "socialshare-title": "'{{dashboardTitle}}' 由Thingsboard提供支持", - "select-dashboard": "選擇儀表板", - "no-dashboards-matching": "找不到符合 '{{entity}}' 的儀表板。", - "dashboard-required": "儀表板必填。", - "select-existing": "選擇現有儀表板", - "create-new": "建立新的儀表板", - "new-dashboard-title": "新儀表板標題", - "open-dashboard": "打開儀表板", - "set-background": "設定背景", - "background-color": "背景顏色", - "background-image": "背景圖片", - "background-size-mode": "背景大小模式", - "no-image": "無圖像選擇", - "drop-image": "拖拉圖像或單擊以選擇要上傳的文件。", - "settings": "設定", - "columns-count": "列數", - "columns-count-required": "需要列數。", - "min-columns-count-message": "只允許最少10列", - "max-columns-count-message": "只允許最多1000列", - "widgets-margins": "部件間邊距", - "horizontal-margin": "水平邊距", - "horizontal-margin-required": "需要水平邊距值。", - "min-horizontal-margin-message": "只允許0作為最小水平邊距值。", - "max-horizontal-margin-message": "只允許50作為最大水平邊距值。", - "vertical-margin": "垂直邊距", - "vertical-margin-required": "需要垂直邊距值。", - "min-vertical-margin-message": "只允許0作為最小垂直邊距值。", - "max-vertical-margin-message": "只允許50作為最大垂直邊距值。", - "autofill-height": "自動填充佈局高度", - "mobile-layout": "移動端佈局設定", - "mobile-row-height": "移動端行高距(px)", - "mobile-row-height-required": "移動端行高距必填。", - "min-mobile-row-height-message": "移動端行高距至少5px。", - "max-mobile-row-height-message": "移動端行高距最多200px。", - "display-title": "顯示儀表板標題", - "toolbar-always-open": "工具欄常駐", - "title-color": "標題顏色", - "display-dashboards-selection": "顯示儀表板選項", - "display-entities-selection": "顯示實體選項", - "display-dashboard-timewindow": "顯示時間窗口", - "display-dashboard-export": "顯示匯出", - "import": "匯入儀表板", - "export": "匯出儀表板", - "export-failed-error": "無法匯出儀表板: {{error}}", - "create-new-dashboard": "建立新的儀表板", - "dashboard-file": "儀表板文件", - "invalid-dashboard-file-error": "無法匯入儀表板: 儀表板資料結構無效。", - "dashboard-import-missing-aliases-title": "配置匯入儀表板使用的別名", - "create-new-widget": "建立新部件", - "import-widget": "匯入部件", - "widget-file": "部件文件", - "invalid-widget-file-error": "無法匯入窗口部件: 窗口部件資料結構無效。", - "widget-import-missing-aliases-title": "配置匯入的窗口部件使用的別名", - "open-toolbar": "打開儀表板工具欄", - "close-toolbar": "關閉工具欄", - "configuration-error": "配置錯誤", - "alias-resolution-error-title": "儀表板別名配置錯誤", - "invalid-aliases-config": "無法找到與某些別名過濾器符合的任何設備。
              請聯繫您的管理員以解決此問題。", - "select-devices": "選擇設備", - "assignedToCustomer": "分配給客戶", - "public": "公共", - "public-link": "公共連結", - "copy-public-link": "複製公共連結", - "public-link-copied-message": "儀表板的公共連結已被複製到剪貼板", - "manage-states": "儀表板狀態管理", - "states": "儀表板狀態", - "search-states": "儀表板狀態檢索", - "selected-states": "{ count, plural, 1 {1 儀表板狀態} other {# 儀表板狀態} } 選中", - "edit-state": "儀表板狀態編輯", - "delete-state": "刪除儀表板狀態", - "add-state": "增加儀表板狀態", - "state": "儀表板狀態", - "state-name": "狀態名", - "state-name-required": "儀表板狀態名必填。", - "state-id": "狀態ID", - "state-id-required": "儀表板狀態ID必填。", - "state-id-exists": "儀表板狀態ID已經存在。", - "is-root-state": "根狀態", - "delete-state-title": "刪除儀表板狀態", - "delete-state-text": "確定要刪除儀表板狀態 '{{stateName}}' 嗎?", - "show-details": "顯示詳細資訊", - "hide-details": "隱藏詳細資訊", - "select-state": "選擇目標狀態", - "state-controller": "狀態控制" - }, - "datakey": { - "settings": "設定", - "advanced": "進階", - "label": "標籤", - "color": "顏色", - "units": "單位符號", - "decimals": "小數位數", - "data-generation-func": "資料生成功能", - "use-data-post-processing-func": "使用資料後處理功能", - "configuration": "資料鍵配置", - "timeseries": "時間序列", - "attributes": "屬性", - "alarm": "報警字段", - "timeseries-required": "需要設備時間序列。", - "timeseries-or-attributes-required": "設備時間/屬性必填。", - "maximum-timeseries-or-attributes": "最大允許 { count, plural, 1 {1 時間序列/屬性} other {# 時間序列/屬性} }", - "alarm-fields-required": "警告字段必填。", - "function-types": "函數類型", - "function-types-required": "需要函數類型。", - "maximum-function-types": "至少需要 { count, plural, 1 {1 函數類型} other {# 函數類型} }" - }, - "datasource": { - "type": "資料源類型", - "name": "資料源名稱", - "add-datasource-prompt": "請增加資料源" - }, - "details": { - "edit-mode": "編輯模式", - "toggle-edit-mode": "切換編輯模式" - }, - "device": { - "device": "設備", - "device-required": "設備必填", - "devices": "設備", - "management": "設備管理", - "view-devices": "查看設備", - "device-alias": "設備別名", - "aliases": "設備別名", - "no-alias-matching": "'{{alias}}' 沒有找到。", - "no-aliases-found": "找不到別名。", - "no-key-matching": "'{{key}}' 沒有找到。", - "no-keys-found": "找不到密鑰。", - "create-new-alias": "建立一個新的!", - "create-new-key": "建立一個新的!", - "duplicate-alias-error": "找到重複別名 '{{alias}}'。
              設備別名必須是唯一的。", - "configure-alias": "配置 '{{alias}}' 別名", - "no-devices-matching": "找不到與 '{{entity}}' 符合的設備。", - "alias": "別名", - "alias-required": "需要設備別名。", - "remove-alias": "刪除設備別名", - "add-alias": "增加設備別名", - "name-starts-with": "名稱前綴", - "device-list": "設備列表", - "use-device-name-filter": "使用過濾器", - "device-list-empty": "沒有被選中的設備", - "device-name-filter-required": "設備名稱過濾器必填。", - "device-name-filter-no-device-matched": "找不到以'{{device}}' 開頭的設備。", - "add": "增加設備", - "assign-to-customer": "分配給客戶", - "assign-device-to-customer": "將設備分配給客戶", - "assign-device-to-customer-text": "請選擇要分配給客戶的設備", - "make-public": "公開", - "make-private": "私有", - "no-devices-text": "找不到設備", - "assign-to-customer-text": "請選擇客戶分配設備", - "device-details": "設備詳細訊息", - "add-device-text": "增加新設備", - "credentials": "憑據", - "manage-credentials": "管理憑據", - "delete": "刪除設備", - "assign-devices": "分配設備", - "assign-devices-text": "將{count,plural,1 {1 設備} other {# 設備} }分配給客戶", - "delete-devices": "刪除設備", - "unassign-from-customer": "取消分配客戶", - "unassign-devices": "取消分配設備", - "unassign-devices-action-title": "從客戶處取消分配{count,plural,1 {1 設備} other {# 設備} }", - "assign-new-device": "分配新設備", - "make-public-device-title": "您確定要將設備 '{{deviceName}}' 設為公開嗎?", - "make-public-device-text": "確認後,設備及其所有資料將被設為公開並可被其他人存取。", - "make-private-device-title": "您確定要將設備 '{{deviceName}}' 設為私有嗎?", - "make-private-device-text": "確認後,設備及其所有資料將被設為私有,不被其他人存取。", - "view-credentials": "查看憑據", - "delete-device-title": "您確定要刪除設備的{{deviceName}}嗎?", - "delete-device-text": "小心!確認後設備及其所有相關資料將無法恢復。", - "delete-devices-title": "您確定要刪除{count,plural,1 {1 設備} other {# 設備} } 嗎?", - "delete-devices-action-title": "刪除 {count,plural,1 {1 設備} other {# 設備} }", - "delete-devices-text": "小心!確認後所有選擇的設備將被刪除,所有相關資料將無法恢復。", - "unassign-device-title": "您確定要取消分配設備 '{{deviceName}}'?", - "unassign-device-text": "確認後,設備將被取消分配,客戶將無法存取。", - "unassign-device": "取消分配設備", - "unassign-devices-title": "您確定要取消分配{count,plural,1 {1 設備} other {# 設備} } 嗎?", - "unassign-devices-text": "確認後,所有選擇的設備將被取消分配,並且客戶將無法存取。", - "device-credentials": "設備憑據", - "credentials-type": "憑據類型", - "access-token": "存取令牌", - "access-token-required": "需要存取令牌", - "access-token-invalid": "存取令牌長度必須為1到32個字符。", - "secret": "密鑰", - "secret-required": "密鑰必填", - "device-type": "設備類型", - "device-type-required": "設備類型必填。", - "select-device-type": "選擇設備類型", - "enter-device-type": "輸入設備類型", - "any-device": "任意設備", - "no-device-types-matching": "沒有找到符合 '{{entitySubtype}}' 的設備類型。", - "device-type-list-empty": "未選擇設備類型", - "device-types": "設備類型", - "name": "名稱", - "name-required": "名稱必填。", - "description": "說明", - "events": "事件", - "details": "詳細訊息", - "copyId": "複製設備ID", - "copyAccessToken": "複製存取令牌", - "idCopiedMessage": "設備ID已複製到剪貼板", - "accessTokenCopiedMessage": "設備存取令牌已複製到剪貼板", - "assignedToCustomer": "分配給客戶", - "unable-delete-device-alias-title": "無法刪除設備別名", - "unable-delete-device-alias-text": "設備別名 '{{deviceAlias}}' 不能夠被刪除,因為它被下列部件所使用:
              {{widgetsList}}", - "is-gateway": "是閘道", - "public": "公開", - "device-public": "設備公開", - "select-device": "選擇設備" - }, - "dialog": { - "close": "關閉對話框" - }, - "error": { - "unable-to-connect": "無法連接到伺服器!請檢查您的互聯網連接。", - "unhandled-error-code": "未處理的錯誤代碼: {{errorCode}}", - "unknown-error": "未知錯誤" - }, - "entity": { - "entity": "實體", - "entities": "實體", - "aliases": "實體別名", - "entity-alias": "實體別名", - "unable-delete-entity-alias-title": "無法刪除實體別名", - "unable-delete-entity-alias-text": "實體別名 '{{entityAlias}}' 被以下部件使用不能刪除:
              {{widgetsList}}", - "duplicate-alias-error": "別名 '{{alias}}' 重複。
              同一儀表板別名必須唯一。", - "missing-entity-filter-error": "別名 '{{alias}}' 缺少過濾器", - "configure-alias": "別名 '{{alias}}' 配置", - "alias": "別名", - "alias-required": "實體別名必填。", - "remove-alias": "移除實體別名", - "add-alias": "增加實體別名", - "entity-list": "實體列表", - "entity-type": "實體類型", - "entity-types": "實體類型", - "entity-type-list": "實體類型列表", - "any-entity": "任意實體", - "enter-entity-type": "輸入實體類型", - "no-entities-matching": "沒有找到符合 '{{entity}}' 的實體。", - "no-entity-types-matching": "沒有找到符合 '{{entityType}}' 類型的實體。", - "name-starts-with": "名稱開始於", - "use-entity-name-filter": "用戶過濾", - "entity-list-empty": "沒有選擇實體。", - "entity-type-list-empty": "沒有選擇實體類型。", - "entity-name-filter-required": "實體名過濾器必填。", - "entity-name-filter-no-entity-matched": "沒有找到以 '{{entity}}' 開頭的實體", - "all-subtypes": "所有", - "select-entities": "選擇實體", - "no-aliases-found": "沒有找到別名", - "no-alias-matching": "沒有找到 '{{alias}}'", - "create-new-alias": "建立新別名", - "key": "鍵", - "key-name": "鍵名", - "no-keys-found": "沒有找到鍵", - "no-key-matching": "沒有找到鍵 '{{key}}'", - "create-new-key": "建立新鍵", - "type": "類型", - "type-required": "實體類型必填。", - "type-device": "設備", - "type-devices": "設備", - "list-of-devices": "{ count, plural, 1 {設備} other {# 設備列表} }", - "device-name-starts-with": "以 '{{prefix}}' 開頭的設備", - "type-asset": "資產", - "type-assets": "資產", - "list-of-assets": "{ count, plural, 1 {資產} other {# 資產列表} }", - "asset-name-starts-with": "以 '{{prefix}}' 開頭的資產", - "type-entity-view": "實體視圖", - "type-entity-views": "實體視圖", - "list-of-entity-views": "{ count, plural, 1 {實體視圖} other {# 實體視圖列表} }", - "entity-view-name-starts-with": "以 '{{prefix}}' 開頭的實體視圖", - "type-rule": "規則", - "type-rules": "規則", - "list-of-rules": "{ count, plural, 1 {規則} other {# 規則列表} }", - "rule-name-starts-with": "以 '{{prefix}}' 開頭的規則", - "type-plugin": "插件", - "type-plugins": "插件", - "list-of-plugins": "{ count, plural, 1 {插件} other {# 插件列表} }", - "plugin-name-starts-with": "以 '{{prefix}}' 開頭的插件", - "type-tenant": "租戶", - "type-tenants": "租戶", - "list-of-tenants": "{ count, plural, 1 {租戶} other {# 租戶列表} }", - "tenant-name-starts-with": "以 '{{prefix}}' 開頭的租戶", - "type-customer": "客戶", - "type-customers": "客戶", - "list-of-customers": "{ count, plural, 1 {客戶} other {# 客戶列表} }", - "customer-name-starts-with": "以 '{{prefix}}' 開頭的客戶", - "type-user": "用戶", - "type-users": "用戶", - "list-of-users": "{ count, plural, 1 {用戶} other {# 用戶列表} }", - "user-name-starts-with": "以 '{{prefix}}' 開頭的用戶", - "type-dashboard": "儀表板", - "type-dashboards": "儀表板", - "list-of-dashboards": "{ count, plural, 1 {儀表板} other {# 儀表板列表} }", - "dashboard-name-starts-with": "以 '{{prefix}}' 開頭的儀表板", - "type-alarm": "警告", - "type-alarms": "警告", - "list-of-alarms": "{ count, plural, 1 {警告} other {# 警告列表} }", - "alarm-name-starts-with": "以 '{{prefix}}' 開頭的警告", - "type-rulechain": "規則鏈", - "type-rulechains": "規則鏈庫", - "list-of-rulechains": "{ count, plural, 1 {一個規則鏈} other {# 規則鏈列表} }", - "rulechain-name-starts-with": "規則鏈前綴名稱 '{{prefix}}'", - "type-current-customer": "當前客戶", - "search": "實體檢索", - "selected-entities": "{ count, plural, 1 {1 實體} other {# 實體} } 被選中", - "entity-name": "實體名", - "details": "實體詳細資訊", - "no-entities-prompt": "沒有找到實體", - "no-data": "無資料" - }, - "entity-view": { - "entity-view": "實體視圖", - "entity-view-required": "實體視圖必填。", - "entity-views": "實體視圖", - "management": "實體視圖管理", - "view-entity-views": "查看實體視圖", - "entity-view-alias": "實體視圖別名", - "aliases": "實體視圖別名", - "no-alias-matching": "'{{alias}}' 沒有找到。", - "no-aliases-found": "找不到別名。", - "no-key-matching": "'{{key}}' 沒有找到。", - "no-keys-found": "找不到密鑰。", - "create-new-alias": "建立一個新的!", - "create-new-key": "建立一個新的!", - "duplicate-alias-error": "找到重複別名 '{{alias}}'。
              實體視圖別名必須是唯一的。", - "configure-alias": "配置 '{{alias}}' 別名", - "no-devices-matching": "找不到與 '{{entity}}' 符合的實體視圖。", - "alias": "別名", - "alias-required": "需要實體視圖別名。", - "remove-alias": "刪除實體視圖別名", - "add-alias": "增加實體視圖別名", - "name-starts-with": "名稱前綴", - "entity-view-list": "實體視圖列表", - "use-entity-view-name-filter": "使用過濾器", - "entity-view-list-empty": "沒有被選中的實體視圖", - "entity-view-name-filter-required": "實體視圖名稱過濾器必填。", - "entity-view-name-filter-no-entity-view-matched": "找不到以'{{entityView}}' 開頭的實體視圖。", - "add": "增加實體視圖", - "assign-to-customer": "分配給客戶", - "assign-entity-view-to-customer": "將實體視圖分配給客戶", - "assign-entity-view-to-customer-text": "請選擇要分配給客戶的實體視圖", - "no-entity-views-text": "找不到實體視圖", - "assign-to-customer-text": "請選擇客戶分配實體視圖", - "entity-view-details": "實體視圖詳細訊息", - "add-entity-view-text": "增加新實體視圖", - "delete": "刪除實體視圖", - "assign-entity-views": "分配實體視圖", - "assign-entity-views-text": "分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} } 給客戶", - "delete-entity-views": "刪除實體視圖", - "unassign-from-customer": "取消分配客戶", - "unassign-entity-views": "取消分配實體視圖", - "unassign-entity-views-action-title": "從客戶處取消分配{count,plural,1 {1 實體視圖} other {# 實體視圖} }", - "assign-new-entity-view": "分配新實體視圖", - "delete-entity-view-title": "確定要刪除實體視圖 '{{entityViewName}}'?", - "delete-entity-view-text": "小心!確認後實體視圖及其所有相關資料將無法恢復。", - "delete-entity-views-title": "確定要刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }?", - "delete-entity-views-action-title": "刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }", - "delete-entity-views-text": "B小心,確認後,所有選擇的實體視圖將被刪除,所有相關的資料將變得無法恢復。", - "unassign-entity-view-title": "您確定要取消對 '{{entityViewName}}'實體視圖的分配嗎?", - "unassign-entity-view-text": "確認後,實體視圖將未分配,客戶無法存取。", - "unassign-entity-view": "未分配實體視圖", - "unassign-entity-views-title": "您確定要取消分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }嗎?", - "unassign-entity-views-text": "確認後,所有選擇的實體視圖將被分配,客戶無法存取。", - "entity-view-type": "實體視圖類型", - "entity-view-type-required": "實體視圖類型必填。", - "select-entity-view-type": "選擇實體視圖類型", - "enter-entity-view-type": "輸入實體視圖類型", - "any-entity-view": "任何實體視圖", - "no-entity-view-types-matching": "沒有找到符合 '{{entitySubtype}}' 的實體視圖類型。", - "entity-view-type-list-empty": "實體視圖類型未選擇。", - "entity-view-types": "實體視圖類型", - "name": "名稱", - "name-required": "名稱必填。", - "description": "描述", - "events": "事件", - "details": "詳細資訊", - "copyId": "複製實體視圖ID", - "assignedToCustomer": "分配給客戶", - "unable-entity-view-device-alias-title": "無法刪除實體視圖別名", - "unable-entity-view-device-alias-text": "實體視圖別名 '{{entityViewAlias}}' 不能夠被刪除,因為它被下列部件所使用:
              {{widgetsList}}", - "select-entity-view": "選擇實體視圖", - "make-public": "實體視圖設為公開", - "make-private": "實體視圖設為私有", - "start-date": "開始日期", - "start-ts": "開始時間", - "end-date": "結束日期", - "end-ts": "結束時間", - "date-limits": "日期限製", - "client-attributes": "客戶端屬性", - "shared-attributes": "共享屬性", - "server-attributes": "服務端屬性", - "timeseries": "時間序列", - "client-attributes-placeholder": "客戶端屬性", - "shared-attributes-placeholder": "共享屬性", - "server-attributes-placeholder": "服務端屬性", - "timeseries-placeholder": "時間序列", - "target-entity": "目標實體", - "attributes-propagation": "屬性傳播", - "attributes-propagation-hint": "每次儲存或更新這個實體視圖時,實體視圖將自動從目標實體複製指定的屬性。由於性能原因,目標實體屬性不會在每次屬性更改時傳播到實體視圖。您可以通過配置\"copy to view\"規則鏈中的規則節點,並將\"Post attributes\"和\"attributes Updated\"消息連結到新規則節點,從而啟用自動傳播。", - "timeseries-data": "時間序列資料", - "timeseries-data-hint": "配置目標實體的時間序列資料鍵,以便實體視圖可以存取這些鍵。這個時間序列資料是只讀的。", - "make-public-entity-view-title": "你確定你想建立公開 '{{entityViewName}}' 實體視圖?", - "make-public-entity-view-text": "確認後,實體視圖 及其所有資料將被公開並被他人存取。", - "make-private-entity-view-title": "你確定你想建立私有 '{{entityViewName}}' 實體視圖?", - "make-private-entity-view-text": "確認後,實體視圖及其所有資料將被私有化,無法被他人存取。" - }, - "event": { - "event-type": "事件類型", - "type-error": "錯誤", - "type-lc-event": "生命週期事件", - "type-stats": "類型統計", - "type-debug-rule-node": "測試", - "type-debug-rule-chain": "測試", - "no-events-prompt": "找不到事件", - "error": "錯誤", - "alarm": "報警", - "event-time": "事件時間", - "server": "伺服器", - "body": "整體", - "method": "方法", - "type": "類型", - "message-id": "消息ID", - "message-type": "消息類型", - "data-type": "資料類型", - "relation-type": "關係類型", - "metadata": "元資料", - "data": "資料", - "event": "事件", - "status": "狀態", - "success": "成功", - "failed": "失敗", - "messages-processed": "消息處理", - "errors-occurred": "錯誤發生", - "all-events": "所有", - "entity-type": "實體類型" - }, - "extension": { - "extensions": "擴展", - "selected-extensions": "{ count, plural, 1 {1 擴展} other {# 擴展} } 被選擇", - "type": "類型", - "key": "鍵名", - "value": "值", - "id": "ID", - "extension-id": "擴展ID", - "extension-type": "擴展類型", - "transformer-json": "JSON *", - "unique-id-required": "當前擴展ID已經存在。", - "delete": "刪除擴展", - "add": "增加擴展", - "edit": "編輯擴展", - "delete-extension-title": "確實要刪除擴展名'{{extensionId}}'嗎?", - "delete-extension-text": "小心,確認後,擴展和所有相關資料將變得無法恢復。", - "delete-extensions-title": "您確定要刪除 { count, plural, 1 {1 表達式} other {# 表達式} }嗎?", - "delete-extensions-text": "小心,確認後,所有選擇的擴展將被刪除。", - "converters": "轉換器", - "converter-id": "轉換器序號", - "configuration": "配置", - "converter-configurations": "轉換器的配置", - "token": "安全令牌", - "add-converter": "增加轉換器", - "add-config": "增加轉換器配置", - "device-name-expression": "設備名稱表達式", - "device-type-expression": "設備類型表達式", - "custom": "顧客", - "to-double": "加倍", - "transformer": "轉換器", - "json-required": "轉換器JSON必填。", - "json-parse": "無法解析轉換器JSON。", - "attributes": "屬性", - "add-attribute": "增加屬性", - "add-map": "增加映射元素", - "timeseries": "時間序列", - "add-timeseries": "增加時間序列", - "field-required": "必填字段", - "brokers": "代理伺服器組", - "add-broker": "增加代理伺服器", - "host": "主機", - "port": "連接埠", - "port-range": "連接埠應該在1到65535的範圍內。", - "ssl": "Ssl", - "credentials": "證書", - "username": "用戶名", - "password": "密碼", - "retry-interval": "以毫秒為單位的重試間隔", - "anonymous": "匿名", - "basic": "Basic", - "pem": "PEM", - "ca-cert": "CA證書文件 *", - "private-key": "私鑰文件 *", - "cert": "證書文件 *", - "no-file": "沒有選擇文件。", - "drop-file": "刪除文件或單擊以選擇要上載的文件。", - "mapping": "映射", - "topic-filter": "主題濾波", - "converter-type": "轉換類型", - "converter-json": "Json", - "json-name-expression": "設備名稱JSON表達式", - "topic-name-expression": "設備名稱主題表達式", - "json-type-expression": "設備類型JSON表達式", - "topic-type-expression": "設備類型主題表達式", - "attribute-key-expression": "屬性關鍵字表達式", - "attr-json-key-expression": "屬性鍵JSON表達式", - "attr-topic-key-expression": "屬性關鍵字主題表達式", - "request-id-expression": "請求ID表達式", - "request-id-json-expression": "請求ID JSON表達式", - "request-id-topic-expression": "請求ID主題表達式", - "response-topic-expression": "響應主題表達式", - "value-expression": "值表達式", - "topic": "主題", - "timeout": "毫秒超時", - "converter-json-required": "轉換JSON是必需的。", - "converter-json-parse": "無法解析轉換JSON。", - "filter-expression": "過濾表達式", - "connect-requests": "連接請求", - "add-connect-request": "增加連接請求", - "disconnect-requests": "斷開請求", - "add-disconnect-request": "增加斷開請求", - "attribute-requests": "屬性請求", - "add-attribute-request": "增加屬性請求", - "attribute-updates": "屬性更新", - "add-attribute-update": "增加屬性更新", - "server-side-rpc": "服務端RPC", - "add-server-side-rpc-request": "增加服務端RPC請求", - "device-name-filter": "設備名稱濾波", - "attribute-filter": "屬性濾波", - "method-filter": "方法濾波", - "request-topic-expression": "請求主題表達式", - "response-timeout": "毫秒內響應超時", - "topic-expression": "主題表達", - "client-scope": "客戶範圍", - "add-device": "增加伺服器", - "opc-server": "伺服器組", - "opc-add-server": "增加伺服器", - "opc-add-server-prompt": "請增加伺服器", - "opc-application-name": "應用名稱", - "opc-application-uri": "應用URI", - "opc-scan-period-in-seconds": "秒級掃描週期", - "opc-security": "安全性", - "opc-identity": "身份", - "opc-keystore": "密鑰庫", - "opc-type": "類型", - "opc-keystore-type": "類型", - "opc-keystore-location": "位置 *", - "opc-keystore-password": "密碼", - "opc-keystore-alias": "別名", - "opc-keystore-key-password": "密鑰密碼", - "opc-device-node-pattern": "設備節點模式", - "opc-device-name-pattern": "設備名稱模式", - "modbus-server": "Servers/slaves", - "modbus-add-server": "增加 server/slave", - "modbus-add-server-prompt": "請增加 server/slave", - "modbus-transport": "傳輸", - "modbus-port-name": "串口名稱", - "modbus-encoding": "編碼", - "modbus-parity": "奇偶性", - "modbus-baudrate": "鮑率", - "modbus-databits": "資料位", - "modbus-stopbits": "停止位", - "modbus-databits-range": "資料位應該在7到8的範圍內。", - "modbus-stopbits-range": "停止位應該在1到2的範圍內。", - "modbus-unit-id": "單位編號", - "modbus-unit-id-range": "單位ID應該在1到247的範圍內", - "modbus-device-name": "設備名稱", - "modbus-poll-period": "輪詢週期 (ms)", - "modbus-attributes-poll-period": "輪詢屬性週期 (ms)", - "modbus-timeseries-poll-period": "時間序列輪詢週期 (ms)", - "modbus-poll-period-range": "輪詢週期應為正值。", - "modbus-tag": "標籤", - "modbus-function": "函數", - "modbus-register-address": "寄存器地址", - "modbus-register-address-range": "寄存器地址應該在0到65535的範圍內。", - "modbus-register-bit-index": "位索引", - "modbus-register-bit-index-range": "位索引應該在0到15的範圍內。", - "modbus-register-count": "寄存器計數", - "modbus-register-count-range": "寄存器計數應該是一個正值。", - "modbus-byte-order": "字節順序", - "sync": { - "status": "狀態", - "sync": "同步", - "not-sync": "不同步", - "last-sync-time": "最後同步時間", - "not-available": "無法使用" - }, - "export-extensions-configuration": "匯出擴展配置", - "import-extensions-configuration": "匯入擴展配置", - "import-extensions": "匯入擴展", - "import-extension": "匯入擴展", - "export-extension": "匯出擴展", - "file": "擴展文件", - "invalid-file-error": "無效的擴展文件" - }, - "fullscreen": { - "expand": "展開到全螢幕", - "exit": "退出全螢幕", - "toggle": "切換全螢幕模式", - "fullscreen": "全螢幕" - }, - "function": { - "function": "函數" - }, - "grid": { - "delete-item-title": "您確定要刪除此項嗎?", - "delete-item-text": "注意,確認後此項及其所有相關資料將變得無法恢復。", - "delete-items-title": "你確定你要刪除 { count, plural, 1 {1 項} other {# 項} }嗎?", - "delete-items-action-title": "刪除 { count, plural, 1 {1 項} other {# 項} }", - "delete-items-text": "注意,確認後所有選擇的項目將被刪除,所有相關資料將無法恢復。", - "add-item-text": "增加新項目", - "no-items-text": "沒有找到項目", - "item-details": "項目詳細訊息", - "delete-item": "刪除項目", - "delete-items": "刪除項目", - "scroll-to-top": "滾動到頂部" - }, - "help": { - "goto-help-page": "轉到幫助頁面" - }, - "home": { - "home": "首頁", - "profile": "屬性", - "logout": "註銷", - "menu": "菜單", - "avatar": "頭像", - "open-user-menu": "打開用戶菜單" - }, - "import": { - "no-file": "沒有選擇文件", - "drop-file": "拖動一個JSON文件或者單擊以選擇要上傳的文件。" - }, - "item": { - "selected": "選擇" - }, - "js-func": { - "no-return-error": "函數必須返回值!", - "return-type-mismatch": "函數必須返回 '{{type}}' 類型的值!", - "tidy": "整理" - }, - "key-val": { - "key": "鍵名", - "value": "值", - "remove-entry": "刪除條目", - "add-entry": "增加條目", - "no-data": "沒有條目" - }, - "layout": { - "layout": "佈局", - "manage": "佈局管理", - "settings": "佈局設定", - "color": "顏色", - "main": "主體", - "right": "右側", - "select": "選擇目標佈局" - }, - "legend": { - "position": "圖例位置", - "show-max": "顯示最大值", - "show-min": "顯示最小值", - "show-avg": "顯示平均值", - "show-total": "顯示總數", - "settings": "圖例設定", - "min": "最小值", - "max": "最大值", - "avg": "平均值", - "total": "總數" - }, - "login": { - "login": "登入", - "request-password-reset": "請求密碼重置", - "reset-password": "重置密碼", - "create-password": "建立密碼", - "passwords-mismatch-error": "輸入的密碼必須相同!", - "password-again": "再次輸入密碼", - "sign-in": "登入 ", - "username": "用戶名(電子郵件)", - "remember-me": "記住我", - "forgot-password": "忘記密碼?", - "password-reset": "密碼重置", - "new-password": "新密碼", - "new-password-again": "再次輸入新密碼", - "password-link-sent-message": "密碼重置連結已成功發送!", - "email": "電子郵件" - }, - "position": { - "top": "頂部", - "bottom": "底部", - "left": "左側", - "right": "右側" - }, - "profile": { - "profile": "屬性", - "change-password": "更改密碼", - "current-password": "當前密碼" - }, - "relation": { - "relations": "關聯", - "direction": "方向", - "search-direction": { - "FROM": "從", - "TO": "到" - }, - "direction-type": { - "FROM": "從", - "TO": "到" - }, - "from-relations": "向外的關聯", - "to-relations": "向內的關聯", - "selected-relations": "{ count, plural, 1 {1 關聯} other {# 關聯} } 被選中", - "type": "類型", - "to-entity-type": "到實體類型", - "to-entity-name": "到實體名稱", - "from-entity-type": "從實體類型", - "from-entity-name": "從實體類型", - "to-entity": "到實體", - "from-entity": "從實體", - "delete": "刪除關聯", - "relation-type": "關聯類型", - "relation-type-required": "關聯類型必填", - "any-relation-type": "任意類型", - "add": "增加關聯", - "edit": "編輯關聯", - "delete-to-relation-title": "確定要刪除實體 '{{entityName}}' 的關聯嗎?", - "delete-to-relation-text": "確定刪除後實體 '{{entityName}}' 將取消與當前實體的關聯關係。", - "delete-to-relations-title": "確定要刪除 { count, plural, 1 {1 關聯} other {# 關聯} }?", - "delete-to-relations-text": "確定刪除所有選擇的關聯關係後,與當前實體對應的所有關聯關係將被移除。", - "delete-from-relation-title": "確定要從實體 '{{entityName}}' 刪除關聯嗎?", - "delete-from-relation-text": "確定刪除後,當前實體將與實體 '{{entityName}}' 取消關聯", - "delete-from-relations-title": "確定刪除 { count, plural, 1 {1 關聯} other {# 關聯} } 嗎?", - "delete-from-relations-text": "確定刪除所有選擇的關聯關係後,當前實體將與對應的實體取消關聯", - "remove-relation-filter": "移除關聯過濾器", - "add-relation-filter": "增加關聯過濾器", - "any-relation": "任意關聯", - "relation-filters": "關聯過濾器", - "additional-info": "附加訊息 (JSON)", - "invalid-additional-info": "無法解析附加訊息json。" - }, - "rulechain": { - "rulechain": "規則鏈", - "rulechains": "規則鏈庫", - "root": "根實體", - "delete": "刪除規則", - "activate": "啟動規則", - "suspend": "暫停規則", - "active": "啟動", - "suspended": "暫停", - "name": "名稱", - "name-required": "名稱必填。", - "description": "描述", - "add": "增加規則", - "set-root": "建立規則鏈根", - "set-root-rulechain-title": "您確定要生成規則鏈'{{RuleChainName}}'根嗎?", - "set-root-rulechain-text": "確認之後,規則鏈將變為根規格鏈,並將處理所有傳入的傳輸消息。", - "delete-rulechain-title": " 確實要刪除規則鏈'{{ruleChainName}}'嗎?", - "delete-rulechain-text": "小心,在確認規則鏈和所有相關資料將變得無法恢復。", - "delete-rulechains-title": "確實要刪除{count, plural, 1 { 1 規則鏈} other {# 規則鏈庫} }嗎?", - "delete-rulechains-action-title": "刪除 { count, plural, 1 {1 規則鏈} other {# 規則鏈庫} }", - "delete-rulechains-text": "小心,確認後,所有選擇的規則鏈將被刪除,所有相關的資料將變得無法恢復。", - "add-rulechain-text": "增加新的規則鏈", - "no-rulechains-text": "規則鏈沒有發現", - "rulechain-details": "規則鏈詳細資訊", - "details": "詳細資訊", - "events": "事件", - "system": "系統", - "import": "匯入規則", - "export": "匯出規則", - "export-failed-error": "無法匯出規則:{{error}}", - "create-new-rulechain": "建立新的規則鏈", - "rulechain-file": "規則鏈文件", - "invalid-rulechain-file-error": "不能匯入規則鏈:無效的規則鏈資料格式。", - "copyId": "複製規則鏈ID", - "idCopiedMessage": "規則ID已經複製到剪貼板", - "select-rulechain": "選擇規則鏈", - "no-rulechains-matching": "沒有發現符合'{{entity}}'的規則鏈。", - "rulechain-required": "規則鏈必填", - "management": "規則集管理", - "debug-mode": "測試模式" - }, - "rulenode": { - "details": "詳細資訊", - "events": "事件", - "search": "搜尋節點", - "open-node-library": "打開節點庫", - "add": "增加規則節點", - "name": "名稱", - "name-required": "名稱必填。", - "type": "類型", - "description": "描述", - "delete": "刪除規則節點", - "select-all-objects": "選擇所有節點和連接", - "deselect-all-objects": "取消選擇所有節點和連接", - "delete-selected-objects": "刪除選擇的節點和連接", - "delete-selected": "刪除選擇", - "select-all": "選擇全部", - "copy-selected": "選擇副本", - "deselect-all": "取消選擇", - "rulenode-details": "規則節點詳細資訊", - "debug-mode": "測試模式", - "configuration": "配置", - "link": "連結", - "link-details": "規則節點連結詳細資訊", - "add-link": "增加連結", - "link-label": "連結標籤", - "link-label-required": "連結標籤必填", - "custom-link-label": "自定義連結標籤", - "custom-link-label-required": "自定義連結標籤必填", - "type-filter": "濾波器", - "type-filter-details": "使用配置條件過濾傳入消息", - "type-enrichment": "屬性集", - "type-enrichment-details": "向消息元資料中增加附加訊息", - "type-transformation": "變換", - "type-transformation-details": "更改消息有效載荷和元資料", - "type-action": "動作", - "type-action-details": "執行特別動作", - "type-external": "外部的", - "type-external-details": "與外部系統交互", - "type-rule-chain": "規則鏈", - "type-rule-chain-details": "將傳入消息轉發到指定的規則鏈", - "type-in​​put": "輸入", - "type-in​​put-details": "規則鏈的邏輯輸入,將傳入消息轉發到下一個相關規則節點", - "directive-is-not-loaded": "定義的配置指令 '{{directiveName}}' 不可用。", - "ui-resources-load-error": "加載配置UI資源失敗。", - "invalid-target-rulechain": "無法解析目標規則鏈!", - "test-script-function": "測試腳本功能", - "message": "消息", - "message-type": "消息類型", - "message-type-required": "消息類型必填", - "metadata": "元資料", - "metadata-required": "元資料項不能為空。", - "output": "輸出", - "test": "測試", - "help": "幫助" - }, - "tenant": { - "tenant": "租戶", - "tenants": "租戶", - "management": "租戶管理", - "add": "增加租戶", - "admins": "管理員", - "manage-tenant-admins": "管理租戶管理員", - "delete": "刪除租戶", - "add-tenant-text": "增加新租戶", - "no-tenants-text": "沒有找到租戶", - "tenant-details": "租客詳細資訊", - "delete-tenant-title": "您確定要刪除租戶'{{tenantTitle}}'嗎?", - "delete-tenant-text": "小心!確認後,租戶和所有相關資料將無法恢復。", - "delete-tenants-title": "您確定要刪除 {count,plural,1 {1 租戶} other {# 租戶} } 嗎?", - "delete-tenants-action-title": "刪除 { count, plural, 1 {1 租戶} other {# 租戶} }", - "delete-tenants-text": "小心!確認後,所有選擇的租戶將被刪除,所有相關資料將無法恢復。", - "title": "標題", - "title-required": "標題必填。", - "description": "描述", - "details": "詳細資訊", - "events": "事件", - "copyId": "複製租戶ID", - "idCopiedMessage": "租戶ID已經複製到剪貼板", - "select-tenant": "選擇租戶", - "no-tenants-matching": "沒有找到符合 '{{entity}}' 的租戶", - "tenant-required": "租戶必填" - }, - "timeinterval": { - "seconds-interval": "{ seconds, plural, 1 {1 秒} other {# 秒} }", - "minutes-interval": "{ minutes, plural, 1 {1 分} other {# 分} }", - "hours-interval": "{ hours, plural, 1 {1 小時} other {# 小時} }", - "days-interval": "{ days, plural, 1 {1 天} other {# 天} }", - "days": "天", - "hours": "時", - "minutes": "分", - "seconds": "秒", - "advanced": "高級" - }, - "timewindow": { - "days": "{ days, plural, 1 { 天 } other {# 天 } }", - "hours": "{ hours, plural, 0 { 小時 } 1 {1 小時 } other {# 小時 } }", - "minutes": "{ minutes, plural, 0 { 分 } 1 {1 分 } other {# 分 } }", - "seconds": "{ seconds, plural, 0 { 秒 } 1 {1 秒 } other {# 秒 } }", - "realtime": "實時", - "history": "歷史", - "last-prefix": "最後", - "period": "從 {{ startTime }} 到 {{ endTime }}", - "edit": "編輯時間窗口", - "date-range": "日期範圍", - "last": "最後", - "time-period": "時間段" - }, - "user": { - "user": "用戶", - "users": "用戶", - "customer-users": "客戶用戶", - "tenant-admins": "租戶管理員", - "sys-admin": "系統管理員", - "tenant-admin": "租戶管理員", - "customer": "客戶", - "anonymous": "匿名", - "add": "增加用戶", - "delete": "刪除用戶", - "add-user-text": "增加新用戶", - "no-users-text": "找不到用戶", - "user-details": "用戶詳細訊息", - "delete-user-title": "您確定要刪除用戶 '{{userEmail}}' 嗎?", - "delete-user-text": "小心!確認後,用戶和所有相關資料將無法恢復。", - "delete-users-title": "你確定你要刪除 { count, plural, 1 {1 用戶} other {# 用戶} } 嗎?", - "delete-users-action-title": "刪除 { count, plural, 1 {1 用戶} other {# 用戶} }", - "delete-users-text": "小心!確認後,所有選擇的用戶將被刪除,所有相關資料將無法恢復。", - "activation-email-sent-message": "啟動電子郵件已成功發送!", - "resend-activation": "重新發送啟動", - "email": "電子郵件", - "email-required": "電子郵件必填。", - "invalid-email-format": "無效的郵件格式。", - "first-name": "名字", - "last-name": "姓", - "description": "描述", - "default-dashboard": "預設面板", - "always-fullscreen": "始終全螢幕", - "select-user": "選擇用戶", - "no-users-matching": "沒有找到符合 '{{entity}}' 的用戶。", - "user-required": "用戶必填", - "activation-method": "啟動方式", - "display-activation-link": "顯示啟動連結", - "send-activation-mail": "發送啟動郵件", - "activation-link": "用戶啟動連結", - "activation-link-text": "使用該連結 啟動 啟動用戶:", - "copy-activation-link": "複製用戶啟動連結", - "activation-link-copied-message": "用戶啟動連結已經複製到剪貼板", - "details": "詳細訊息" - }, - "value": { - "type": "值類型", - "string": "字符串", - "string-value": "字符串值", - "integer": "數字", - "integer-value": "數字值", - "invalid-integer-value": "整數值無效", - "double": "雙精度浮點數", - "double-value": "雙精度浮點數值", - "boolean": "布林", - "boolean-value": "布林值", - "false": "假", - "true": "真", - "long": "Long" - }, - "widget": { - "widget-library": "部件庫", - "widget-bundle": "部件包", - "select-widgets-bundle": "選擇部件包", - "management": "管理部件", - "editor": "部件編輯器", - "widget-type-not-found": "加載部件配置出錯。
              可能關聯的\n 部件已經刪除了。", - "widget-type-load-error": "由於以下錯誤未加載小部件:", - "remove": "刪除部件", - "edit": "編輯部件", - "remove-widget-title": "確實要刪除 '{{widgetTitle}}'部件嗎?", - "remove-widget-text": "確認後,控件和所有相關資料將變得無法恢復。", - "timeseries": "時間序列", - "search-data": "搜尋資料", - "no-data-found": "沒有找到資料", - "latest": "最新值", - "rpc": "控件部件", - "alarm": "警告部件", - "static": "靜態部件", - "select-widget-type": "選擇窗口部件類型", - "missing-widget-title-error": "部件標題必須指定!", - "widget-saved": "部件已儲存", - "unable-to-save-widget-error": "無法儲存部件!控件有錯誤!", - "save": "儲存部件", - "saveAs": "部件另存為", - "save-widget-type-as": "部件類型另存為", - "save-widget-type-as-text": "請輸入新的部件標題或選擇目標部件包", - "toggle-fullscreen": "切換全螢幕", - "run": "執行部件", - "title": "部件標題", - "title-required": "需要部件標題。", - "type": "部件類型", - "resources": "資源", - "resource-url": "JavaScript/CSS URL", - "remove-resource": "刪除資源", - "add-resource": "增加資源", - "html": "HTML", - "tidy": "整理", - "css": "CSS", - "settings-schema": "設定模式", - "datakey-settings-schema": "資料鍵設定模式", - "javascript": "Javascript", - "remove-widget-type-title": "您確定要刪除部件類型 '{{widgetName}}'嗎?", - "remove-widget-type-text": "確認後,窗口部件類型和所有相關資料將無法恢復。", - "remove-widget-type": "刪除部件類型", - "add-widget-type": "增加新的部件類型", - "widget-type-load-failed-error": "無法加載部件類型!", - "widget-template-load-failed-error": "無法加載部件模板!", - "add": "增加部件", - "undo": "復原部件更改", - "export": "匯出部件" - }, - "widget-action": { - "header-button": "部件頂部按鈕", - "open-dashboard-state": "切換到新儀表板狀態", - "update-dashboard-state": "更新當前儀表板狀態", - "open-dashboard": "切換到另一個儀表板", - "custom": "自定義動作", - "target-dashboard-state": "目標儀表板狀態", - "target-dashboard-state-required": "目標儀表板狀態必填", - "set-entity-from-widget": "從部件中設定實體", - "target-dashboard": "目標儀表板", - "open-right-layout": "打開右側佈局 (移動端視圖)" - }, - "widgets-bundle": { - "current": "當前包", - "widgets-bundles": "部件包", - "add": "增加部件包", - "delete": "刪除部件包", - "title": "標題", - "title-required": "標題必填。", - "add-widgets-bundle-text": "增加新的部件包", - "no-widgets-bundles-text": "找不到部件包", - "empty": "部件包是空的", - "details": "詳細資訊", - "widgets-bundle-details": "部件包詳細訊息", - "delete-widgets-bundle-title": "您確定要刪除部件包 '{{widgetsBundleTitle}}'嗎?", - "delete-widgets-bundle-text": "小心!確認後,部件包和所有相關資料將無法恢復。", - "delete-widgets-bundles-title": "你確定你要刪除 { count, plural, 1 {1 部件包} other {# 部件包} } 嗎?", - "delete-widgets-bundles-action-title": "刪除 { count, plural, 1 {1 部件包} other {# 部件包} }", - "delete-widgets-bundles-text": "小心!確認後,所有選擇的部件包將被刪除,所有相關資料將無法恢復。", - "no-widgets-bundles-matching": "沒有找到與 '{{widgetsBundle}}' 符合的部件包。", - "widgets-bundle-required": "需要部件包。", - "system": "系統", - "import": "匯入部件包", - "export": "匯出部件包", - "export-failed-error": "無法匯出部件包: {{error}}", - "create-new-widgets-bundle": "建立新的部件包", - "widgets-bundle-file": "部件包文件", - "invalid-widgets-bundle-file-error": "無法匯入部件包:無效的部件包資料結構。" - }, - "widget-config": { - "data": "資料", - "settings": "設定", - "advanced": "高級", - "title": "標題", - "general-settings": "一般設定", - "display-title": "顯示標題", - "drop-shadow": "陰影", - "enable-fullscreen": "啟用全螢幕", - "background-color": "背景顏色", - "text-color": "文字顏色", - "padding": "填充", - "margin": "邊緣", - "widget-style": "部件風格", - "title-style": "標題風格", - "mobile-mode-settings": "移動端設定", - "order": "順序", - "height": "高度", - "units": "特殊符號展示值", - "decimals": "浮點數後的位數", - "timewindow": "時間窗口", - "use-dashboard-timewindow": "使用儀表板的時間窗口", - "display-legend": "顯示圖例", - "datasources": "資料源", - "maximum-datasources": "最大允許 { count, plural, 1 {1 資料} other {# 資料} }", - "datasource-type": "類型", - "datasource-parameters": "參數", - "remove-datasource": "移除資料源", - "add-datasource": "增加資料源", - "target-device": "目標設備", - "alarm-source": "警告源", - "actions": "動作", - "action": "動作", - "add-action": "增加動作", - "search-actions": "動作檢索", - "action-source": "動作源", - "action-source-required": "動作源必填", - "action-name": "動作名稱", - "action-name-required": "動作名稱必填。", - "action-name-not-unique": "動作名稱已經存在。
              統一動作源的動作名稱必須唯一。", - "action-icon": "圖示", - "action-type": "類型", - "action-type-required": "類型必填", - "edit-action": "編輯動作", - "delete-action": "刪除動作", - "delete-action-title": "刪除部件動作", - "delete-action-text": "確定要刪除部件動作 '{{actionName}}' 嗎?" - }, - "widget-type": { - "import": "匯入部件類型", - "export": "匯出部件類型", - "export-failed-error": "無法匯出部件類型: {{error}}", - "create-new-widget-type": "建立新的部件類型", - "widget-type-file": "部件類型文件", - "invalid-widget-type-file-error": "無法匯入部件類型:無效的部件類型資料結構。" - }, - "widgets": { - "date-range-navigator": { - "localizationMap": { - "Sun": "週日", - "Mon": "週一", - "Tue": "週二", - "Wed": "週三", - "Thu": "週四", - "Fri": "週五", - "Sat": "週六", - "Jan": "1月", - "Feb": "2月", - "Mar": "3月", - "Apr": "4月", - "May": "5月", - "Jun": "6月", - "Jul": "7月", - "Aug": "8月", - "Sep": "9月", - "Oct": "10月", - "Nov": "11月", - "Dec": "12月", - "January": "一月", - "February": "二月", - "March": "三月", - "April": "四月", - "June": "六月", - "July": "七月", - "August": "八月", - "September": "九月", - "October": "十月", - "November": "十一月", - "December": "十二月", - "Custom Date Range": "自定義日期範圍", - "Date Range Template": "日期範圍模板", - "Today": "今天", - "Yesterday": "昨天", - "This Week": "本星期", - "Last Week": "上個星期", - "This Month": "這個月", - "Last Month": "上個月", - "Year": "年", - "This Year": "今年", - "Last Year": "去年", - "Date picker": "日期選擇器", - "Hour": "小時", - "Day": "天", - "Week": "週", - "2 weeks": "2週", - "Month": "月", - "3 months": "3個月", - "6 months": "6個月", - "Custom interval": "自定義間隔", - "Interval": "間隔", - "Step size": "步長", - "Ok": "Ok" - } - } - }, - "icon": { - "icon": "圖示", - "select-icon": "選擇圖示", - "material-icons": "素材圖示", - "show-all": "顯示所有圖示" - }, - "custom": { + "access": { + "unauthorized": "未授權", + "unauthorized-access": "未授權存取", + "unauthorized-access-text": "您需要登入才能存取這個資源!", + "access-forbidden": "禁止存取", + "access-forbidden-text": "您沒有存取此位置的權限
              如果您仍希望存取此位置,請嘗試使用其他用戶登入。", + "refresh-token-expired": "Session 已過期", + "refresh-token-failed": "無法更新 Session", + "permission-denied": "許可權被拒絕", + "permission-denied-text": "您沒有執行此操作的許可權!" + }, + "action": { + "activate": "啟動", + "suspend": "暫停", + "save": "儲存", + "saveAs": "另存為", + "cancel": "取消", + "ok": "確定", + "delete": "刪除", + "add": "增加", + "yes": "是", + "no": "否", + "update": "更新", + "remove": "移除", + "select": "選擇", + "search": "查詢", + "clear-search": "清除查詢", + "assign": "分配", + "unassign": "取消分配", + "share": "分享", + "make-private": "私有", + "apply": "應用", + "apply-changes": "應用更改", + "edit-mode": "編輯模式", + "enter-edit-mode": "進入編輯模式", + "decline-changes": "取消更改", + "close": "關閉", + "back": "返回", + "run": "執行", + "sign-in": "登入!", + "edit": "編輯", + "view": "查看", + "create": "建立", + "drag": "拖拉", + "refresh": "更新", + "undo": "取消", + "copy": "複製", + "paste": "貼上", + "copy-reference": "複製引用", + "paste-reference": "貼上引用", + "import": "匯入", + "export": "匯出", + "share-via": "通過 {{provider}}分享", + "continue": "繼續", + "discard-changes": "放棄更改", + "download": "下載", + "next-with-label": "下一步: {{label}}", + "read-more": "讀更多", + "hide": "隱藏", + "done": "完成", + "print": "列印", + "restore": "恢復", + "confirm": "確認" + }, + "aggregation": { + "aggregation": "聚合", + "function": "資料聚合功能", + "limit": "最大值", + "group-interval": "分組間隔", + "min": "最少值", + "max": "最大值", + "avg": "平均值", + "sum": "總計", + "count": "計數", + "none": "空" + }, + "admin": { + "general": "一般", + "general-settings": "一般設定", + "home-settings": "主頁設訂", + "outgoing-mail": "發送郵件", + "outgoing-mail-settings": "發送郵件設定", + "system-settings": "系統設定", + "test-mail-sent": "測試郵件發送成功!", + "base-url": "基本URL", + "base-url-required": "基本URL必填。", + "prohibit-different-url": "禁止使用用戶端請求標頭中的主機名", + "prohibit-different-url-hint": "應為生產環境啟用此設定。禁用時可能會導致安全問題", + "mail-from": "郵件來自", + "mail-from-required": "郵件發件人必填。", + "smtp-protocol": "SMTP協定", + "smtp-host": "SMTP主機", + "smtp-host-required": "SMTP主機必填。", + "smtp-port": "SMTP連接埠", + "smtp-port-required": "您必須提供一個smtp連接埠。", + "smtp-port-invalid": "這看起來不是有效的smtp連接埠。", + "timeout-msec": "超時(ms)", + "timeout-required": "超時必填。", + "timeout-invalid": "這看起來不像有效的超時值。", + "enable-tls": "啟用TLS", + "tls-version": "TLS版本", + "enable-proxy": "啟用proxy", + "proxy-host": "Proxy主機", + "proxy-host-required": "需要Proxy主機。", + "proxy-port": "Proxy通訊埠", + "proxy-port-required": "需要Proxy通訊埠。", + "proxy-port-range": "Proxy通訊埠應在1到65535的範圍內。", + "proxy-user": "Proxy用戶", + "proxy-password": "Proxy密碼d", + "change-password": "修改密碼", + "send-test-mail": "發送測試郵件", + "sms-provider": "SMS提供者", + "sms-provider-settings": "SMS提供者設定", + "sms-provider-type": "SMS提供者類型", + "sms-provider-type-required": "SMS提供者形態為必填", + "sms-provider-type-aws-sns": "Amazon SNS", + "sms-provider-type-twilio": "Twilio", + "sms-provider-type-smpp": "SMPP", + "aws-access-key-id": "AWS存取金鑰ID", + "aws-access-key-id-required": "AWS存取金鑰ID為必填", + "aws-secret-access-key": "AWS私密存取金鑰ID", + "aws-secret-access-key-required": "AWS私密存取金鑰ID為必填", + "aws-region": "AWS地區", + "aws-region-required": "AWS地區為必填", + "number-from": "電話號碼來自", + "number-from-required": "電話號碼來自為必填", + "number-to": "電話號碼發送至", + "number-to-required": "電話號碼發送至為必填", + "phone-number-hint": "E.164格式的電話號碼,例如+19995550123", + "phone-number-hint-twilio": "E.164格式的電話號碼/電話號碼的SID/訊息服務SID,例如+19995550123/PNXXX/MGXXX", + "phone-number-pattern": "電話號碼無效。應採用E.164格式,例如+19995550123。", + "phone-number-pattern-twilio": "電話號碼無效。應採用E.164格式/電話號碼的SID/訊息服務SID,例如+19995550123/PNXXX/MGXXX。", + "sms-message": "SMS簡訊", + "sms-message-required": "SMS簡訊為必填", + "sms-message-max-length": "SMS簡訊不能超過1600個字元", + "twilio-account-sid": "Twilio Account SID", + "twilio-account-sid-required": "Twilio Account SID為必填", + "twilio-account-token": "Twilio Account token", + "twilio-account-token-required": "Twilio Account token為必填", + "send-test-sms": "發送測試SMS", + "test-sms-sent": "測試SMS已成功發送!", + "security-settings": "安全設定", + "password-policy": "密碼政策", + "minimum-password-length": "密碼長度下限", + "minimum-password-length-required": "密碼長度下限為必填", + "minimum-password-length-range": "密碼長度下限範圍值為5-50", + "minimum-uppercase-letters": "大寫字母數下限", + "minimum-uppercase-letters-range": "大寫字母數下限不可為否", + "minimum-lowercase-letters": "小寫字母數下限", + "minimum-lowercase-letters-range": "小寫字母數下限,不可為否", + "minimum-digits": "數字數下限", + "minimum-digits-range": "數字數下限不能為否", + "minimum-special-characters": "特殊字元數下限", + "minimum-special-characters-range": "特殊字元數下限,不可為否", + "password-expiration-period-days": "密碼失效期限,以天為單位", + "password-expiration-period-days-range": "密碼失效期限,以天為單位,不可為否", + "password-reuse-frequency-days": "密碼重用頻率天數", + "password-reuse-frequency-days-range": "密碼重用頻率天數,不可為否", + "allow-whitespace": "允許空白字元", + "general-policy": "通用政策", + "max-failed-login-attempts": "帳號上鎖前的最多嘗試登入錯誤次數", + "minimum-max-failed-login-attempts-range": "最多嘗試登入錯誤次數,不可為否", + "user-lockout-notification-email": "避免帳號被鎖,寄送email通知", + "domain-name": "網域名稱", + "domain-name-unique": "網域名稱與通訊協定需是唯一值", + "domain-name-max-length": "網域名稱需少於256字元", + "error-verification-url": "網域名稱不可包含符號 '/' 及 ':' 例如:thingsboard.io", + "oauth2": { + "access-token-uri": "訪問token URI", + "access-token-uri-required": "訪問token為必填", + "activate-user": "啓動用戶", + "add-domain": "增加網域", + "delete-domain": "刪除網域", + "add-provider": "增加提供者", + "delete-provider": "刪除提供者", + "allow-user-creation": "允許用戶建立", + "always-fullscreen": "始終以全螢幕顯示", + "authorization-uri": "授權URI", + "authorization-uri-required": "授權URI為必填", + "client-authentication-method": "客戶端驗證方法", + "client-id": "客戶ID", + "client-id-required": "客戶ID為必填", + "client-id-max-length": "客戶ID長度需小於256", + "client-secret": "客戶密鑰", + "client-secret-required": "客戶密鑰為必填", + "client-secret-max-length": "客戶密鑰長度需小於2049", + "custom-setting": "客製化設定", + "customer-name-pattern": "顧客名稱模式", + "customer-name-pattern-max-length": "顧客名稱模式長度需小於256", + "default-dashboard-name": "預設儀表板名稱", + "default-dashboard-name-max-length": "預設儀表板名稱長度需小於256", + "delete-domain-text": "小心!確認後,此網域及所有提供者資料將被刪除,將無法恢復。", + "delete-domain-title": "您確定要刪除網域設定 '{{domainName}}'嗎?", + "delete-registration-text": "小心!確認後,提供者資料將被刪除,將無法恢復。", + "delete-registration-title": "您確定要刪除提供者 '{{name}}'?", + "email-attribute-key": "Email屬性key", + "email-attribute-key-required": "Email屬性key為必填", + "email-attribute-key-max-length": "Email屬性key長度需小於32", + "first-name-attribute-key": "名字屬性key", + "first-name-attribute-key-max-length": "名字屬性key長度需小於32", + "general": "General", + "jwk-set-uri": "JSON Web Key URI", + "last-name-attribute-key": "姓氏屬性key", + "last-name-attribute-key-max-length": "姓氏屬性key長度需小於32", + "login-button-icon": "登入鍵圖示", + "login-button-label": "提供者標籤", + "login-button-label-placeholder": "使用$(Provider label)登入", + "login-button-label-required": "標籤為必填", + "login-provider": "登入提供者", + "mapper": "匹配器", + "new-domain": "新網域", + "oauth2": "OAuth2", + "password-max-length": "密碼需小於256", + "redirect-uri-template": "轉址URI格式", + "copy-redirect-uri": "複製轉址URI", + "registration-id": "註冊 ID", + "registration-id-required": "註冊ID為必填", + "registration-id-unique": "註冊ID需為系統中唯一值。", + "scope": "Scope", + "scope-required": "Scope為必填", + "tenant-name-pattern": "租戶名稱格式", + "tenant-name-pattern-required": "租戶名稱格式為必填", + "tenant-name-pattern-max-length": "租戶名稱格式長度需小於256", + "tenant-name-strategy": "租戶命名規則", + "type": "匹配器類型", + "uri-pattern-error": "無效URI格式", + "url": "URL", + "url-pattern": "無效URI格式", + "url-required": "URI為必填", + "url-max-length": "URI長度需小於256", + "user-info-uri": "用戶訊息URI", + "user-info-uri-required": "用戶訊息URI為必填", + "username-max-length": "用戶名稱長度需小於256", + "user-name-attribute-name": "用戶名稱屬性key", + "user-name-attribute-name-required": "用戶名稱屬性key為必填", + "protocol": "協定", + "domain-schema-http": "HTTP", + "domain-schema-https": "HTTPS", + "domain-schema-mixed": "HTTP+HTTPS", + "enable": "啟用OAuth2設定", + "domains": "網域", + "mobile-apps": "手機應用程式", + "no-mobile-apps": "無應用程式設定", + "mobile-package": "應用套裝軟體", + "mobile-package-placeholder": "例如my.example.app", + "mobile-package-hint": "對於Android:您自己的唯一應用程序ID。對於iOS:產品Bundle ID", + "mobile-package-unique": "應用程式套件需為唯一值", + "mobile-app-secret": "應用程式密鑰", + "invalid-mobile-app-secret": "應用程式密鑰需包含字母數字字元,長度需介於16到2048之間。", + "copy-mobile-app-secret": "複製應用程式密鑰", + "add-mobile-app": "增加應用程式", + "delete-mobile-app": "刪除應用程式資訊", + "providers": "提供者", + "platform-web": "Web", + "platform-android": "Android", + "platform-ios": "iOS", + "all-platforms": "所有平台", + "allowed-platforms": "允許平台" + }, + "smpp-provider": { + "smpp-version": "SMPP版本", + "smpp-host": "SMPP主機t", + "smpp-host-required": "需要SMPP主機", + "smpp-port": "SMPP通訊埠", + "smpp-port-required": "需要SMPP通訊埠", + "system-id": "系統ID", + "system-id-required": "需要系統ID", + "password": "密碼", + "password-required": "需要密碼", + "type-settings": "類型設定", + "source-settings": "來源設定", + "destination-settings": "目的地設定", + "additional-settings": "額外設定", + "system-type": "系統類型", + "bind-type": "綁定類型", + "service-type": "服務類型", + "source-address": "來源地址", + "source-ton": "來源 TON", + "source-npi": "來源NPI", + "destination-ton": "目的地TON (號碼類型)", + "destination-npi": "目的地NPI (編號計畫標識)", + "address-range": "地址範圍", + "coding-scheme": "編碼方案", + "bind-type-tx": "傳輸者", + "bind-type-rx": "接收者", + "bind-type-trx": "收發者", + "ton-unknown": "不明", + "ton-international": "國際的", + "ton-national": "國家的", + "ton-network-specific": "網路專用的", + "ton-subscriber-number": "訂閱者數量", + "ton-alphanumeric": "字母數字的", + "ton-abbreviated": "簡稱", + "npi-unknown": "0 - 未知", + "npi-isdn": "1 - ISDN/電話編號計畫 (E163/E164)", + "npi-data-numbering-plan": "3 - 數據編號計畫 (X.121)", + "npi-telex-numbering-plan": "4 - 電傳編號計畫 (F.69)", + "npi-land-mobile": "6 - 陸地移動 (E.212)", + "npi-national-numbering-plan": "8 - 國家編號計畫", + "npi-private-numbering-plan": "9 - 專用編號計畫", + "npi-ermes-numbering-plan": "10 - ERMES編號計畫 (ETSI DE/PS 3 01-3)", + "npi-internet": "13 - 網際網路 (IP)", + "npi-wap-client-id": "18 - WAP客戶端ID (由WAP論壇定義)", + "scheme-smsc": "0 - SMSC預設字母 (ASCII表示短程式碼和長程式碼,GSM表示免費)", + "scheme-ia5": "1 - IA5 (ASCII表示短程式碼和長程式碼,拉丁語9表示免費(ISO-8859-9))", + "scheme-octet-unspecified-2": "2 - 八位元組未指定 (8位元二進制)", + "scheme-latin-1": "3 - 拉丁語1 (ISO-8859-1)", + "scheme-octet-unspecified-4": "4 - 八位元組未指定 (8位元二進制)", + "scheme-jis": "5 - JIS (X 0208-1990)", + "scheme-cyrillic": "6 - Cyrillic (ISO-8859-5)", + "scheme-latin-hebrew": "7 - 拉丁語/希伯來語 (ISO-8859-8)", + "scheme-ucs-utf": "8 - UCS2/UTF-16 (ISO/IEC-10646)", + "scheme-pictogram-encoding": "9 - 編碼圖標", + "scheme-music-codes": "10 - 音樂程式碼(ISO-2022-JP)", + "scheme-extended-kanji-jis": "13 - 擴展漢字JIS (X 0212-1990)", + "scheme-korean-graphic-character-set": "14 - 韓文圖形字元集 (KS C 5601/KS X 1001)" + }, + "queue-select-name": "選擇佇列名稱", + "queue-name": "佇列名稱", + "queue-name-required": "佇列名稱為必填!", + "queues": "佇列", + "queue-partitions": "分割", + "queue-submit-strategy": "提交策略", + "queue-processing-strategy": "程序策略", + "queue-configuration": "佇列設定", + "repository-settings": "儲存設定", + "repository-url": "儲存URL", + "repository-url-required": "儲存URL為必填。", + "default-branch": "預設分支名稱", + "authentication-settings": "驗證設定", + "auth-method": "驗證方法", + "auth-method-username-password": "密碼/訪問token", + "auth-method-private-key": "私鑰", + "password-access-token": "密碼/訪問token", + "change-password-access-token": "更改密碼/訪問token", + "private-key": "私鑰", + "drop-private-key-file-or": "拖拉私鑰檔案或", + "passphrase": "密語", + "enter-passphrase": "輸入密語", + "change-passphrase": "更改密語", + "check-access": "檢查訪問", + "check-repository-access-success": "儲存訪問驗證成功", + "delete-repository-settings-title": "您確定要刪除儲存設定嗎?", + "delete-repository-settings-text": "小心!確認後,儲存設定及其版本控制資料將被刪除,所有相關資料將無法恢復", + "auto-commit-settings": "自動提交設定", + "auto-commit-entities": "自動提交實體", + "no-auto-commit-entities-prompt": "沒有配置自動提交的實體", + "delete-auto-commit-settings-title": "您確定要刪除自動提交設定嗎?", + "delete-auto-commit-settings-text": "小心!確認後,自動提交設定將被刪除,實體配置自動提交功能也將被停用", + "2fa": { + "2fa": "雙重驗證", + "available-providers": "可用的供應商", + "issuer-name": "發行者名稱", + "issuer-name-required": "發行者名稱為必填。", + "max-verification-failures-before-user-lockout": "用戶被鎖定前的最多驗證錯誤次數", + "max-verification-failures-before-user-lockout-pattern": "用戶驗證錯誤次數必須為正整數", + "number-of-checking-attempts": "用戶驗證嘗試次數", + "number-of-checking-attempts-pattern": "用戶驗證嘗試次數必須為正整數", + "number-of-checking-attempts-required": "用戶驗證嘗試次數為必填", + "number-of-codes": "程式數量", + "number-of-codes-pattern": "程式數量必須為正整數", + "number-of-codes-required": "程式數量為必填", + "provider": "提供者", + "retry-verification-code-period": "輸入重試驗證碼時間(秒)", + "retry-verification-code-period-pattern": "輸入重試驗證碼時間最少5秒", + "retry-verification-code-period-required": "輸入重試驗證碼時間為必填", + "total-allowed-time-for-verification": "允許重試驗證碼時間總和(秒)", + "total-allowed-time-for-verification-pattern": "允許重試驗證碼時間總和最少60秒", + "total-allowed-time-for-verification-required": "允許重試驗證碼時間總和為必填", + "use-system-two-factor-auth-settings": "使用系統雙重驗證設定", + "verification-code-check-rate-limit": "驗證碼檢查率限制", + "verification-code-lifetime": "驗證碼使用期限(秒)", + "verification-code-lifetime-pattern": "驗證碼使用期限必須為正整數", + "verification-code-lifetime-required": "驗證碼使用期限為必填。", + "verification-message-template": "驗證訊息模板", + "verification-limitations": "驗證條件", + "verification-message-template-pattern": "驗證條件必要模式: ${code}", + "verification-message-template-required": "驗證條件必要模式為必填", + "within-time": "時間內 (秒)", + "within-time-pattern": "時間必須為正整數", + "within-time-required": "時間為必填" + } + }, + "alias": { + "add": "增加別名", + "edit": "編輯別名", + "name": "別名", + "name-required": "別名必填", + "duplicate-alias": "別名已經存在。", + "filter-type-single-entity": "單一實體", + "filter-type-entity-list": "實體列表", + "filter-type-entity-name": "實體名稱", + "filter-type-entity-type": "實體類型", + "filter-type-state-entity": "實體(儀表板狀態)", + "filter-type-state-entity-description": "實體taken(儀表板狀態參數)", + "filter-type-asset-type": "資產類型", + "filter-type-asset-type-description": "類型為 '{{assetType}}' 的資產", + "filter-type-asset-type-and-name-description": "類型為 '{{assetType}}' 且以 '{{prefix}}' 開頭的資產", + "filter-type-device-type": "設備類型", + "filter-type-device-type-description": "類型為 '{{deviceType}}' 的設備", + "filter-type-device-type-and-name-description": "類型為 '{{deviceType}}' 且以 '{{prefix}}' 開頭的設備", + "filter-type-entity-view-type": "實體視圖類型", + "filter-type-entity-view-type-description": "類型為 '{{entityView}}' 的實體視圖", + "filter-type-entity-view-type-and-name-description": "類型為 {{entityView}}' 且以 '{{prefix}}' 開頭的實體視圖", + "filter-type-edge-type": "邊緣類型", + "filter-type-edge-type-description": " '類型為{{edgeType}}'的邊緣", + "filter-type-edge-type-and-name-description": "類型為 '{{edgeType}}' 且名稱以 '{{prefix}}'開頭的邊緣", + "filter-type-relations-query": "關聯查詢", + "filter-type-relations-query-description": "具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的 {{entities}} ", + "filter-type-asset-search-query": "資產搜尋查詢", + "filter-type-asset-search-query-description": "類型為 {{assetTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的資產", + "filter-type-device-search-query": "設備搜尋查詢", + "filter-type-device-search-query-description": "類型為 {{deviceTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的設備", + "filter-type-entity-view-search-query": "實體視圖搜尋查詢", + "filter-type-entity-view-search-query-description": "類型為 {{entityViewTypes}} 且具有 {{relationType}} 關聯 {{direction}} {{rootEntity}} 的實體視圖", + "filter-type-apiUsageState": "api使用狀態", + "filter-type-edge-search-query": "邊緣搜尋查詢", + "filter-type-edge-search-query-description": "具有{{relationType}}關聯{{direction}} {{rootEntity}}類型為{{edgeTypes}}的邊緣", + "entity-filter": "實體過濾", + "resolve-multiple": "解決為多實體", + "filter-type": "過濾類型", + "filter-type-required": "過濾類型必填。", + "entity-filter-no-entity-matched": "未找到符合指定過濾條件的實體。", + "no-entity-filter-specified": "沒有指定實體過濾條件", + "root-state-entity": "使用儀表板狀態實體作為根實體", + "last-level-relation": "僅獲取最後一級關聯", + "root-entity": "根實體", + "state-entity-parameter-name": "狀態實體參數名稱", + "default-state-entity": "預設狀態實體", + "default-entity-parameter-name": "預設", + "max-relation-level": "最大關聯層級", + "unlimited-level": "不限層級", + "state-entity": "儀表板狀態實體", + "all-entities": "所有實體", + "any-relation": "不限" + }, + "asset": { + "asset": "資產", + "assets": "資產", + "management": "資產管理", + "view-assets": "查看資產", + "add": "增加資產", + "asset-type-max-length": "資產類型應小於256", + "assign-to-customer": "分配給客戶", + "assign-asset-to-customer": "將資產分配給客戶", + "assign-asset-to-customer-text": "請選擇要分配給客戶的資產", + "no-assets-text": "未找到資產", + "assign-to-customer-text": "請選擇客戶以分配資產", + "public": "公開", + "assignedToCustomer": "分配客戶", + "make-public": "資產設為公開", + "make-private": "資產設為私有", + "unassign-from-customer": "取消分配客戶", + "delete": "刪除資產", + "asset-public": "資產公開", + "asset-type": "資產類型", + "asset-type-required": "資產類型必填。", + "select-asset-type": "選擇資產類型", + "enter-asset-type": "輸入資產類型", + "any-asset": "任何資產", + "no-asset-types-matching": "沒有找到符合 '{{entitySubtype}}' 的資產類型。", + "asset-type-list-empty": "資產類型未選擇。", + "asset-types": "資產類型", + "name": "名稱", + "name-required": "名稱必填。", + "name-max-length": "名稱應小於256", + "label-max-length": "標籤應小於256", + "description": "描述", + "type": "類型", + "type-required": "類型必填。", + "details": "詳細資訊", + "events": "事件", + "add-asset-text": "增加新資產", + "asset-details": "資產詳細資訊", + "assign-assets": "分配資產", + "assign-assets-text": "分配 { count, plural, 1 {1 資產} other {# 資產} } 給客戶", + "assign-asset-to-edge-title": "將資產分配給邊緣", + "assign-asset-to-edge-text": "請選擇要分配給邊緣的資產", + "delete-assets": "刪除資產", + "unassign-assets": "取消分配資產", + "unassign-assets-action-title": "從客戶處取消分配 { count, plural, 1 {1 資產} other {# 資產} } ", + "assign-new-asset": "分配新資產", + "delete-asset-title": "確定要刪除資產 '{{assetName}}'?", + "delete-asset-text": "小心!確認後資產及其所有相關資料將無法恢復。", + "delete-assets-title": "確定要刪除 { count, plural, 1 {1 資產} other {# 資產} }?", + "delete-assets-action-title": "刪除 { count, plural, 1 {1 資產} other {# 資產} }", + "delete-assets-text": "小心,確認後,所有選擇的資產將被刪除,所有相關的資料將變得無法恢復。", + "make-public-asset-title": "你確定你想建立公開'{{assetName}}'資產?", + "make-public-asset-text": "確認後,資產及其所有資料將被公開並被他人存取。", + "make-private-asset-title": "你確定你想建立私有 '{{assetName}}' 資產?", + "make-private-asset-text": "確認後,資產及其所有資料將被私有化,無法被他人存取。", + "unassign-asset-title": "您確定要取消對'{{assetName}}'資產的分配嗎?", + "unassign-asset-text": "確認後,資產將未分配,客戶無法存取。", + "unassign-asset": "未分配資產", + "unassign-assets-title": "您確定要取消分配 { count, plural, 1 {1 資產} other {# 資產} }嗎?", + "unassign-assets-text": "確認後,所有選擇的資產將被分配,客戶無法存取。", + "unassign-assets-from-edge": "從邊緣取消分配資產", + "copyId": "複製資產ID", + "idCopiedMessage": "資產ID已經複製到剪貼簿", + "select-asset": "選擇資產", + "no-assets-matching": "沒有找到符合 '{{entity}}' 的資產。", + "asset-required": "資產必填", + "name-starts-with": "資產名稱以此開頭", + "help-text": "根據需要使用 '%':'%asset_name_contains%'、 '%asset_name_ends'、 'asset_starts_with'。", + "import": "匯入資產", + "asset-file": "資產文件", + "label": "標籤", + "search": "搜尋資產", + "assign-asset-to-edge": "將資產分配給邊緣", + "unassign-asset-from-edge": "取消分配資產", + "unassign-asset-from-edge-title": "您確定要取消分配資產'{{assetName}}'嗎?", + "unassign-asset-from-edge-text": "確認後,資產將被取消分配,邊緣將無法訪問。", + "unassign-assets-from-edge-title": "您確定要取消分配 { count, plural, 1 {1 資產} other {# 資產} }?", + "unassign-assets-from-edge-text": "確認後,所有選定的資產都將被取消分配,邊緣將無法訪問。.", + "selected-assets": "{ count, plural, 1 {1 資產} other {# 資產} }被選中" + }, + "attribute": { + "attributes": "屬性", + "latest-telemetry": "最新遙測", + "attributes-scope": "設備屬性範圍", + "scope-latest-telemetry": "最新遙測", + "scope-client": "客戶端屬性", + "scope-server": "服務端屬性", + "scope-shared": "共享屬性", + "add": "增加屬性", + "key": "鍵", + "key-max-length": "金鑰應小於256", + "last-update-time": "最後更新時間", + "key-required": "屬性鍵必填。", + "value": "值", + "value-required": "屬性值必填。", + "delete-attributes-title": "您確定要刪除 { count, plural, 1 {1 屬性} other {# 屬性} }嗎?", + "delete-attributes-text": "注意,確認後所有選中的屬性都會被刪除。", + "delete-attributes": "刪除屬性", + "enter-attribute-value": "輸入屬性值", + "show-on-widget": "在部件上顯示", + "widget-mode": "部件模式", + "next-widget": "下一個部件", + "prev-widget": "上一個部件", + "add-to-dashboard": "增加到儀表板", + "add-widget-to-dashboard": "將部件增加到儀表板", + "selected-attributes": "{ count, plural, 1 {1 屬性} other {# 屬性} } 被選中", + "selected-telemetry": "{ count, plural, 1 {1 遙測} other {# 遙測} }被選中", + "no-attributes-text": "找不到屬性", + "no-telemetry-text": "找不到遙測" + }, + "api-usage": { + "api-usage": "api使用狀態", + "alarm": "警告", + "alarms-created": "警告建立", + "alarms-created-daily-activity": "警告建立每日活動", + "alarms-created-hourly-activity": "警告建立每小時活動", + "alarms-created-monthly-activity": "警告建立每月活動", + "data-points": "數據端", + "data-points-storage-days": "數據端儲存天數", + "email": "Email", + "email-messages": "Email訊息", + "email-messages-daily-activity": "Email訊息每日活動", + "email-messages-monthly-activity": "Email訊息每月活動", + "exceptions": "例外", + "executions": "執行", + "javascript": "JavaScript", + "javascript-executions": "JavaScript執行", + "javascript-functions": "JavaScript功能", + "javascript-functions-daily-activity": "JavaScript功能每日活動", + "javascript-functions-hourly-activity": "JavaScript功能每小時活動", + "javascript-functions-monthly-activity": "JavaScript功能每月活動", + "latest-error": "最新錯誤", + "messages": "訊息", + "notifications": "通知", + "notifications-email-sms": "(Email/SMS)通知", + "notifications-hourly-activity": "通知每小時活動", + "permanent-failures": "${entityName}永久失敗", + "permanent-timeouts": "${entityName}永久超時", + "processing-failures": "${entityName} 處理失敗", + "processing-failures-and-timeouts": "處理失敗與超時", + "processing-timeouts": "${entityName} 處理超時", + "queue-stats": "佇列統計", + "rule-chain": "規則鏈", + "rule-engine": "規則引擎", + "rule-engine-daily-activity": "規則引擎每日活動", + "rule-engine-executions": "規則引擎執行", + "rule-engine-hourly-activity": "規則引擎每小時活動", + "rule-engine-monthly-activity": "規則引擎每月活動", + "rule-engine-statistics": "規則引擎統計", + "rule-node": "規則節點", + "sms": "SMS", + "sms-messages": "SMS訊息", + "sms-messages-daily-activity": "SMS訊息每日活動", + "sms-messages-monthly-activity": "SMS訊息每月活動", + "successful": "${entityName} 成功", + "telemetry": "遙測", + "telemetry-persistence": "遙測持久性", + "telemetry-persistence-daily-activity": "遙測持久性每日活動", + "telemetry-persistence-hourly-activity": "遙測持久性每小時活動", + "telemetry-persistence-monthly-activity": "遙測持久性每月活動", + "transport": "傳輸", + "transport-daily-activity": "傳輸每日活動", + "transport-data-points": "傳輸資料端", + "transport-hourly-activity": "傳輸每小時活動", + "transport-messages": "傳輸訊息", + "transport-monthly-activity": "傳輸每月活動", + "view-details": "檢視詳細資料", + "view-statistics": "檢視統計數據" + }, + "audit-log": { + "audit": "審計", + "audit-logs": "審計日誌", + "timestamp": "時間戳", + "entity-type": "實體類型", + "entity-name": "實體名稱", + "user": "用戶", + "type": "類型", + "status": "狀態", + "details": "詳細資訊", + "type-added": "增加", + "type-deleted": "刪除", + "type-updated": "更新", + "type-attributes-updated": "更新屬性", + "type-attributes-deleted": "刪除屬性", + "type-rpc-call": "RPC調用", + "type-credentials-updated": "更新憑據", + "type-assigned-to-customer": "分配給客戶", + "type-unassigned-from-customer": "未分配給客戶", + "type-assigned-to-edge": "分配給邊緣", + "type-unassigned-from-edge": "從邊緣取消分配", + "type-activated": "啟動", + "type-suspended": "暫停", + "type-credentials-read": "讀取憑據", + "type-attributes-read": "讀取屬性", + "type-relation-add-or-update": "關聯已更新", + "type-relation-delete": "關聯已刪除", + "type-relations-delete": "所有關聯已刪除", + "type-alarm-ack": "已確認", + "type-alarm-clear": "清除", + "type-login": "登入", + "type-logout": "登出", + "type-lockout": "登出", + "status-success": "成功", + "status-failure": "失敗", + "audit-log-details": "審計日誌詳細資訊", + "no-audit-logs-prompt": "找不到日誌", + "action-data": "活動資料", + "failure-details": "失敗詳細資訊", + "search": "查找審計日誌", + "clear-search": "清空查找", + "type-assigned-from-tenant": "從租戶分配", + "type-assigned-to-tenant": "分配給租戶", + "type-provision-success": "設備已配置", + "type-provision-failure": "設備配置失敗", + "type-timeseries-updated": "遙測已更新", + "type-timeseries-deleted": "遙測已刪除" + }, + "confirm-on-exit": { + "message": "您有未儲存的更改。確定要離開此頁嗎?", + "html-message": "您有未儲存的更改。
              確定要離開此頁面嗎?", + "title": "未儲存的更改" + }, + "contact": { + "country": "國家", + "city": "城市", + "state": "州", + "postal-code": "郵政編碼", + "postal-code-invalid": "只允許數字。", + "address": "地址", + "address2": "地址2", + "phone": "手機", + "email": "郵箱", + "no-address": "無地址", + "state-max-length": "狀態長度應小於256", + "phone-max-length": "電話號碼應小於256", + "city-max-length": "指定城市應小於256" + }, + "common": { + "username": "用戶名", + "password": "密碼", + "enter-username": "輸入用戶名", + "enter-password": "輸入密碼", + "enter-search": "輸入檢索條件", + "created-time": "建立時間", + "loading": "正在加載...", + "proceed": "繼續", + "open-details-page": "打開詳細資訊頁" + }, + "content-type": { + "json": "Json", + "text": "文字", + "binary": "二進制 (Base64)" + }, + "customer": { + "customer": "客戶", + "customers": "客戶", + "management": "客戶管理", + "dashboard": "客戶儀表板", + "dashboards": "客戶儀表板", + "devices": "客戶設備", + "entity-views": "客戶實體視圖", + "assets": "客戶資產", + "public-dashboards": "公共儀表板", + "public-devices": "公共設備", + "public-assets": "公共資產", + "public-entity-views": "公共實體視圖", + "add": "增加客戶", + "delete": "刪除客戶", + "manage-customer-users": "管理客戶用戶", + "manage-customer-devices": "管理客戶設備", + "manage-customer-dashboards": "管理客戶儀表板", + "manage-public-devices": "管理公共設備", + "manage-public-dashboards": "管理公共儀表板", + "manage-customer-assets": "管理客戶資產", + "manage-public-assets": "管理公共資產", + "manage-customer-edges": "管理客戶優勢", + "manage-public-edges": "管理客戶優勢", + "add-customer-text": "增加新客戶", + "no-customers-text": "沒有找到客戶", + "customer-details": "客戶詳細資訊", + "delete-customer-title": "您確定要刪除客戶'{{customerTitle}}'嗎?", + "delete-customer-text": "小心!確認後,客戶及其所有相關資料將無法恢復。", + "delete-customers-title": "您確定要刪除 { count, plural, 1 {1 客戶} other {# 客戶} }嗎?", + "delete-customers-action-title": "刪除 { count, plural, 1 {1 客戶} other {# 客戶} }", + "delete-customers-text": "小心!確認後,所有選擇的客戶將被刪除,所有相關資料將無法恢復。", + "manage-users": "管理用戶", + "manage-assets": "管理資產", + "manage-devices": "管理設備", + "manage-dashboards": "管理儀表板", + "title": "標題", + "title-required": "需要標題", + "title-max-length": "標題應小於256", + "description": "描述", + "details": "詳細資訊", + "events": "事件", + "copyId": "複製客戶ID", + "idCopiedMessage": "客戶ID已複製到剪貼板", + "select-customer": "選擇客戶", + "no-customers-matching": "沒有找到符合 '{{entity}}' 的客戶。", + "customer-required": "客戶是必選項", + "select-default-customer": "選擇預設的客戶", + "default-customer": "預設客戶", + "default-customer-required": "為了測試租戶級別上的儀表板,需要預設客戶。", + "search": "搜尋客戶", + "selected-customers": "{ count, plural, 1 {1 客戶} other {# 客戶} }被選中", + "edges": "客戶邊緣實體物件", + "manage-edges": "管理邊緣" + }, + "datetime": { + "date-from": "日期從", + "time-from": "時間從", + "date-to": "日期到", + "time-to": "時間到" + }, + "dashboard": { + "dashboard": "儀表板", + "dashboards": "儀表板庫", + "management": "儀表板管理", + "view-dashboards": "查看儀表板", + "add": "增加儀表板", + "assign-dashboard-to-customer": "將儀表板分配給客戶", + "assign-dashboard-to-customer-text": "請選擇要分配給客戶的儀表板", + "assign-dashboard-to-edge-title": "將儀表板分配給邊緣", + "assign-to-customer-text": "請選擇客戶分配儀表板", + "assign-to-customer": "分配給客戶", + "unassign-from-customer": "取消分配客戶", + "make-public": "儀表板設為公開", + "make-private": "儀表板設為私有", + "manage-assigned-customers": "管理已分配的客戶", + "assigned-customers": "已分配的客戶", + "assign-to-customers": "將儀表板分配給客戶", + "assign-to-customers-text": "請選擇客戶指定儀表板", + "unassign-from-customers": "客戶未分配儀表板", + "unassign-from-customers-text": "請選擇從儀表板中取消分配的客戶", + "no-dashboards-text": "沒有找到儀表板", + "no-widgets": "沒有配置部件", + "add-widget": "增加新的部件", + "title": "標題", + "image": "儀表板圖像", + "mobile-app-settings": "移動應用程序設定", + "mobile-order": "移動應用程序中的儀表板順序", + "mobile-hide": "在移動應用程序中隱藏儀表板", + "update-image": "更新儀表板圖像", + "take-screenshot": "截圖", + "select-widget-title": "選擇部件", + "select-widget-value": "{{title}}: 選擇小部件", + "select-widget-subtitle": "可用的部件類型列表", + "delete": "刪除儀表板", + "title-required": "需要標題。", + "title-max-length": "標題應小於256", + "description": "描述", + "details": "詳細資訊", + "dashboard-details": "儀表板詳細資訊", + "add-dashboard-text": "增加新的儀表板", + "assign-dashboards": "分配儀表板", + "assign-new-dashboard": "分配新的儀表板", + "assign-dashboards-text": "分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", + "unassign-dashboards-action-text": "未分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } 給客戶", + "delete-dashboards": "刪除儀表板", + "unassign-dashboards": "取消分配儀表板", + "unassign-dashboards-action-title": "從客戶處取消分配 { count, plural, 1 {1 儀表板} other {# 儀表板} } ", + "delete-dashboard-title": "您確定要刪除儀表板 '{{dashboardTitle}}'嗎?", + "delete-dashboard-text": "小心!確認後儀表板及其所有相關資料將無法恢復。", + "delete-dashboards-title": "你確定你要刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }嗎?", + "delete-dashboards-action-title": "刪除 { count, plural, 1 {1 儀表板} other {# 儀表板} }", + "delete-dashboards-text": "小心!確認後所有選擇的儀表板將被刪除,所有相關資料將無法恢復。", + "unassign-dashboard-title": "您確定要取消分配儀表板 '{{dashboardTitle}}'嗎?", + "unassign-dashboard-text": "確認後,面板將被取消分配,客戶將無法存取。", + "unassign-dashboard": "取消分配儀表板", + "unassign-dashboards-title": "您確定要取消分配儀表板 { count, plural, 1 {1 儀表板} other {# 儀表板} } 嗎?", + "unassign-dashboards-text": "確認後,所有選擇的儀表板將被取消分配,客戶將無法存取。", + "public-dashboard-title": "儀表板現已公佈", + "public-dashboard-text": "你的儀表板{{dashboardTitle}} 已被公開,可通過如下連結存取:", + "public-dashboard-notice": "提示: 不要忘記將相關設備公開以存取其資料。", + "make-private-dashboard-title": "您確定要將儀表板 '{{dashboardTitle}}' 設為私有嗎?", + "make-private-dashboard-text": "確認後,儀表板將被設為私有,不能被其他人存取。", + "make-private-dashboard": "儀表板設為私有", + "socialshare-text": "'{{dashboardTitle}}' 由Thingsboard提供支持", + "socialshare-title": "'{{dashboardTitle}}' 由Thingsboard提供支持", + "select-dashboard": "選擇儀表板", + "no-dashboards-matching": "找不到符合 '{{entity}}' 的儀表板。", + "dashboard-required": "儀表板必填。", + "select-existing": "選擇現有儀表板", + "create-new": "建立新的儀表板", + "new-dashboard-title": "新儀表板標題", + "open-dashboard": "打開儀表板", + "set-background": "設定背景", + "background-color": "背景顏色", + "background-image": "背景圖片", + "background-size-mode": "背景大小模式", + "no-image": "無圖像選擇", + "empty-image": "沒有圖像", + "drop-image": "拖拉圖像或單擊以選擇要上傳的文件。", + "maximum-upload-file-size": "最大上傳文件大小: {{ size }}", + "cannot-upload-file": "無法上傳文件", + "settings": "設定", + "layout-settings": "佈局設定", + "columns-count": "列數", + "columns-count-required": "需要列數。", + "min-columns-count-message": "只允許最少10列", + "max-columns-count-message": "只允許最多1000列", + "widgets-margins": "部件間邊距", + "margin-required": "需要邊距值", + "min-margin-message": "只允許0作為最小邊距值0。", + "max-margin-message": "只允許50作為最大邊距值。", + "horizontal-margin": "水平邊距", + "horizontal-margin-required": "需要水平邊距值。", + "min-horizontal-margin-message": "只允許0作為最小水平邊距值。", + "max-horizontal-margin-message": "只允許50作為最大水平邊距值。", + "vertical-margin": "垂直邊距", + "vertical-margin-required": "需要垂直邊距值。", + "min-vertical-margin-message": "只允許0作為最小垂直邊距值。", + "max-vertical-margin-message": "只允許50作為最大垂直邊距值。", + "autofill-height": "自動填充佈局高度", + "mobile-layout": "移動端佈局設定", + "mobile-row-height": "移動端行高距(px)", + "mobile-row-height-required": "移動端行高距必填。", + "min-mobile-row-height-message": "移動端行高距至少5px。", + "max-mobile-row-height-message": "移動端行高距最多200px。", + "title-settings": "標題設定", + "display-title": "顯示儀表板標題", + "toolbar-always-open": "工具欄常駐", + "title-color": "標題顏色", + "toolbar-settings": "工具欄設定", + "hide-toolbar": "隱藏工具欄", + "display-dashboards-selection": "顯示儀表板選項", + "display-entities-selection": "顯示實體選項", + "display-filters": "顯示過濾器", + "display-dashboard-timewindow": "顯示時間窗口", + "display-dashboard-export": "顯示匯出", + "display-update-dashboard-image": "顯示更新儀表板圖像", + "dashboard-logo-settings": "儀表板logo設定", + "display-dashboard-logo": "在儀表板全螢幕模式下顯示logo", + "dashboard-logo-image": "儀表板logo圖像", + "advanced-settings": "進階設定", + "dashboard-css": "儀表板CSS", + "import": "匯入儀表板", + "export": "匯出儀表板", + "export-failed-error": "無法匯出儀表板: {{error}}", + "create-new-dashboard": "建立新的儀表板", + "dashboard-file": "儀表板文件", + "invalid-dashboard-file-error": "無法匯入儀表板: 儀表板資料結構無效。", + "dashboard-import-missing-aliases-title": "配置匯入儀表板使用的別名", + "create-new-widget": "建立新部件", + "import-widget": "匯入部件", + "widget-file": "部件文件", + "invalid-widget-file-error": "無法匯入窗口部件: 窗口部件資料結構無效。", + "widget-import-missing-aliases-title": "配置匯入的窗口部件使用的別名", + "open-toolbar": "打開儀表板工具欄", + "close-toolbar": "關閉工具欄", + "configuration-error": "配置錯誤", + "alias-resolution-error-title": "儀表板別名配置錯誤", + "invalid-aliases-config": "無法找到與某些別名過濾器符合的任何設備。
              請聯繫您的管理員以解決此問題。", + "select-devices": "選擇設備", + "assignedToCustomer": "分配給客戶", + "assignedToCustomers": "分配給客戶們", + "public": "公共", + "copyId": "複製儀表板id", + "idCopiedMessage": "儀表板Id已被複製到剪貼板", + "public-link": "公共連結", + "copy-public-link": "複製公共連結", + "public-link-copied-message": "儀表板的公共連結已被複製到剪貼板", + "manage-states": "儀表板狀態管理", + "states": "儀表板狀態", + "search-states": "儀表板狀態檢索", + "selected-states": "{ count, plural, 1 {1 儀表板狀態} other {# 儀表板狀態} } 選中", + "edit-state": "儀表板狀態編輯", + "delete-state": "刪除儀表板狀態", + "add-state": "增加儀表板狀態", + "no-states-text": "未找到任何狀態", + "state": "儀表板狀態", + "state-name": "狀態名", + "state-name-required": "儀表板狀態名必填。", + "state-id": "狀態ID", + "state-id-required": "儀表板狀態ID必填。", + "state-id-exists": "儀表板狀態ID已經存在。", + "is-root-state": "根狀態", + "delete-state-title": "刪除儀表板狀態", + "delete-state-text": "確定要刪除儀表板狀態 '{{stateName}}' 嗎?", + "show-details": "顯示詳細資訊", + "hide-details": "隱藏詳細資訊", + "select-state": "選擇目標狀態", + "state-controller": "狀態控制", + "search": "搜尋儀表板", + "selected-dashboards": "{ count, plural, 1 {1 儀表板} other {# 儀表板} }被選中", + "home-dashboard": "主儀表板", + "home-dashboard-hide-toolbar": "隱藏主儀表板工具欄", + "unassign-dashboard-from-edge-text": "確認後,儀表板將被取消分配,邊緣將無法訪問。", + "unassign-dashboards-from-edge-title": "您確定要取消分配 { count, plural, 1 {1 儀表板} other {# 儀表板} }嗎?", + "unassign-dashboards-from-edge-text": "確認後,所有選定的儀表板都將被取消分配,且邊緣將無法訪問。", + "assign-dashboard-to-edge": "將儀表板分配給邊緣", + "assign-dashboard-to-edge-text": "請選擇要分配給邊緣的儀表板", + "non-existent-dashboard-state-error": "未找到id為 \"{{ stateId }}\" 的儀表板狀態" + }, + "datakey": { + "settings": "設定", + "advanced": "進階", + "label": "標籤", + "color": "顏色", + "units": "單位符號", + "decimals": "小數位數", + "data-generation-func": "資料生成功能", + "use-data-post-processing-func": "使用資料後處理功能", + "configuration": "資料鍵配置", + "timeseries": "時間序列", + "attributes": "屬性", + "entity-field": "實體字段", + "alarm": "警告字段", + "timeseries-required": "需要設備時間序列。", + "timeseries-or-attributes-required": "設備時間/屬性必填。", + "alarm-fields-timeseries-or-attributes-required": "需要警告字段或實體時間序列/屬性。", + "maximum-timeseries-or-attributes": "最大允許 { count, plural, 1 {1 時間序列/屬性} other {# 時間序列/屬性} }", + "alarm-fields-required": "警告字段必填。", + "function-types": "函數類型", + "function-type": "函數類型", + "function-types-required": "需要函數類型。", + "maximum-function-types": "至少需要 { count, plural, 1 {1 函數類型} other {# 函數類型} }", + "alarm-keys": "警告資料鍵", + "alarm-key": "警告資料鍵", + "alarm-key-functions": "警告鍵功能", + "alarm-key-function": "警告鍵功能", + "latest-keys": "最新資料鍵", + "latest-key": "最新資料鍵", + "latest-key-functions": "最新按鍵功能", + "latest-key-function": "最新按鍵功能", + "timeseries-keys": "時間序列資料鍵", + "timeseries-key": "時間序列資料鍵", + "timeseries-key-functions": "時間序列鍵功能", + "timeseries-key-function": "時間序列鍵功能", + "time-description": "當前值的時間戳;", + "value-description": "當前值;", + "prev-value-description": "上一個函數調用的結果;", + "time-prev-description": "上一個值的時間戳;", + "prev-orig-value-description": "原始先前值;" + }, + "datasource": { + "type": "資料源類型", + "name": "資料源名稱", + "label": "標籤", + "add-datasource-prompt": "請增加資料源" + }, + "details": { + "details": "詳細資訊", + "edit-mode": "編輯模式", + "edit-json": "編輯JSON", + "toggle-edit-mode": "切換編輯模式" + }, + "device": { + "device": "設備", + "device-required": "設備必填", + "devices": "設備", + "management": "設備管理", + "view-devices": "查看設備", + "device-alias": "設備別名", + "device-type-max-length": "設備類型應小於256", + "aliases": "設備別名", + "no-alias-matching": "'{{alias}}' 沒有找到。", + "no-aliases-found": "找不到別名。", + "no-key-matching": "'{{key}}' 沒有找到。", + "no-keys-found": "找不到密鑰。", + "create-new-alias": "建立一個新的!", + "create-new-key": "建立一個新的!", + "duplicate-alias-error": "找到重複別名 '{{alias}}'。
              設備別名必須是唯一的。", + "configure-alias": "配置 '{{alias}}' 別名", + "no-devices-matching": "找不到與 '{{entity}}' 符合的設備。", + "alias": "別名", + "alias-required": "需要設備別名。", + "remove-alias": "刪除設備別名", + "add-alias": "增加設備別名", + "name-starts-with": "名稱前綴", + "help-text": "根據需要使用'%': '%device_name_contains%', '%device_name_ends', 'device_starts_with'。", + "device-list": "設備列表", + "use-device-name-filter": "使用過濾器", + "device-list-empty": "沒有被選中的設備", + "device-name-filter-required": "設備名稱過濾器必填。", + "device-name-filter-no-device-matched": "找不到以'{{device}}' 開頭的設備。", + "add": "增加設備", + "assign-to-customer": "分配給客戶", + "assign-device-to-customer": "將設備分配給客戶", + "assign-device-to-customer-text": "請選擇要分配給客戶的設備", + "assign-device-to-edge-title": "將設備分配給邊緣", + "assign-device-to-edge-text": "請選擇要分配給邊緣的設備", + "make-public": "公開", + "make-private": "私有", + "no-devices-text": "找不到設備", + "assign-to-customer-text": "請選擇客戶分配設備", + "device-details": "設備詳細訊息", + "add-device-text": "增加新設備", + "credentials": "憑據", + "manage-credentials": "管理憑據", + "delete": "刪除設備", + "assign-devices": "分配設備", + "assign-devices-text": "將{count,plural,1 {1 設備} other {# 設備} }分配給客戶", + "delete-devices": "刪除設備", + "unassign-from-customer": "取消分配客戶", + "unassign-devices": "取消分配設備", + "unassign-devices-action-title": "從客戶處取消分配{count,plural,1 {1 設備} other {# 設備} }", + "unassign-device-from-edge-title": "您確定要取消分配設備'{{deviceName}}'嗎?", + "unassign-device-from-edge-text": "確認後,設備將被取消分配,邊緣將無法訪問。", + "unassign-devices-from-edge": "從邊緣取消分配設備", + "assign-new-device": "分配新設備", + "make-public-device-title": "您確定要將設備 '{{deviceName}}' 設為公開嗎?", + "make-public-device-text": "確認後,設備及其所有資料將被設為公開並可被其他人存取。", + "make-private-device-title": "您確定要將設備 '{{deviceName}}' 設為私有嗎?", + "make-private-device-text": "確認後,設備及其所有資料將被設為私有,不被其他人存取。", + "view-credentials": "查看憑據", + "delete-device-title": "您確定要刪除設備的{{deviceName}}嗎?", + "delete-device-text": "小心!確認後設備及其所有相關資料將無法恢復。", + "delete-devices-title": "您確定要刪除{count,plural,1 {1 設備} other {# 設備} } 嗎?", + "delete-devices-action-title": "刪除 {count,plural,1 {1 設備} other {# 設備} }", + "delete-devices-text": "小心!確認後所有選擇的設備將被刪除,所有相關資料將無法恢復。", + "unassign-device-title": "您確定要取消分配設備 '{{deviceName}}'?", + "unassign-device-text": "確認後,設備將被取消分配,客戶將無法存取。", + "unassign-device": "取消分配設備", + "unassign-devices-title": "您確定要取消分配{count,plural,1 {1 設備} other {# 設備} } 嗎?", + "unassign-devices-text": "確認後,所有選擇的設備將被取消分配,並且客戶將無法存取。", + "device-credentials": "設備憑據", + "loading-device-credentials": "正在加載設備憑據...", + "credentials-type": "憑據類型", + "access-token": "存取", + "access-token-required": "需要存取token", + "access-token-invalid": "存取token長度必須為1到32個字符。", + "certificate-pem-format": "PEM格式的憑據", + "certificate-pem-format-required": "需要憑據", + "lwm2m-security-config": { + "identity": "客戶端身份", + "identity-required": "需要客戶端身份", + "identity-tooltip": "如標準[RFC7925]中所述,PSK識別字是任意的PSK識別字,最多128位元組。.\n PSK識別字必須首先轉換成字串,然後使用UTF-8編碼為八位位元組。", + "client-key": "客戶端金鑰", + "client-key-required": "需要客戶端金鑰。", + "client-key-tooltip-prk": "PRK公鑰或id必須採用標準[RFC7250]並編碼為Base64格式!", + "client-key-tooltip-psk": "PSK密鑰必須採用標準[RFC4279]和HexDec格式:32、64、128個字元!", + "endpoint": "端點客戶端名稱", + "endpoint-required": "需要端點客戶端名稱", + "client-public-key": "客戶端公鑰", + "client-public-key-hint": "如果客戶端公鑰為空,則使用可信憑據", + "client-public-key-tooltip": "X509公鑰必須是DER編碼的X509v3格式,並且只支持EC算法,然後編碼成Base64格式!", + "mode": "安全配置模式", + "client-tab": "客戶端安全配置", + "client-certificate": "客戶端憑據", + "bootstrap-tab": "Bootstrap客戶端", + "bootstrap-server": "Bootstrap伺服器", + "lwm2m-server": "LwM2M伺服器", + "client-publicKey-or-id": "客戶端公鑰或Id", + "client-publicKey-or-id-required": "需要客戶端公鑰或Id", + "client-publicKey-or-id-tooltip-psk": "如標準[RFC7925]中所述,PSK識別字是最多128位元組的任意PSK識別字。\n PSK識別字首先必須先轉換為字串,然後使用UTF-8編碼為八位位元組。", + "client-publicKey-or-id-tooltip-rpk": "RPK公鑰或id必須採用標準[RFC7250]並編碼為Base64格式!", + "client-publicKey-or-id-tooltip-x509": "X509公鑰必須是DER編碼的X509v3格式,並且只支持EC算法,然後編碼為Base64格式", + "client-secret-key": "客戶端密鑰", + "client-secret-key-required": "需要客戶端密鑰", + "client-secret-key-tooltip-psk": "PSK密鑰必須採用標準[RFC4279]和HexDec格式: 32、64、128個字元!", + "client-secret-key-tooltip-prk": "RPK密鑰必須是PKCS_8格式 (DER 編碼,標準[RFC5958]) ,然後編碼為Base64格式!", + "client-secret-key-tooltip-x509": "X509密鑰必須是PKCS_8格式(DER編碼,標準[RFC5958]),然後編碼為Base64格式!" + }, + "client-id": "客戶ID", + "client-id-pattern": "包含無效字元。", + "user-name": "用戶名稱", + "user-name-required": "需要用戶名稱。", + "client-id-or-user-name-necessary": "客戶ID和/或用戶名是必須的", + "password": "密碼", + "secret": "密鑰", + "secret-required": "密鑰必填", + "device-type": "設備類型", + "device-type-required": "設備類型必填。", + "select-device-type": "選擇設備類型", + "enter-device-type": "輸入設備類型", + "any-device": "任意設備", + "no-device-types-matching": "沒有找到符合 '{{entitySubtype}}' 的設備類型。", + "device-type-list-empty": "未選擇設備類型", + "device-types": "設備類型", + "name": "名稱", + "name-required": "名稱必填。", + "name-max-length": "名稱應小於256", + "label-max-length": "標籤應小於256", + "description": "說明", + "label": "標籤", + "events": "事件", + "details": "詳細訊息", + "copyId": "複製設備ID", + "copyAccessToken": "複製存取token", + "copy-mqtt-authentication": "複製MQTT憑據", + "idCopiedMessage": "設備ID已複製到剪貼板", + "accessTokenCopiedMessage": "設備存取token已複製到剪貼板", + "mqtt-authentication-copied-message": "設備MQTT身份驗證已複製到剪貼板", + "assignedToCustomer": "分配給客戶", + "unable-delete-device-alias-title": "無法刪除設備別名", + "unable-delete-device-alias-text": "設備別名 '{{deviceAlias}}' 不能夠被刪除,因為它被下列部件所使用:
              {{widgetsList}}", + "is-gateway": "是閘道", + "overwrite-activity-time": "覆蓋已連接設備的活動時間", + "public": "公開", + "device-public": "設備公開", + "select-device": "選擇設備", + "import": "匯入設備", + "device-file": "設備文件", + "search": "搜尋設備", + "selected-devices": "{ count, plural, 1 {1 設備} other {# 設備} }被選中", + "device-configuration": "設備配置", + "transport-configuration": "傳輸配置", + "wizard": { + "device-wizard": "設備嚮導", + "device-details": "設備詳情", + "new-device-profile": "建立設備協議", + "existing-device-profile": "選擇現有的設備協議", + "specific-configuration": "具體配置", + "customer-to-assign-device": "客戶指定設備", + "add-credentials": "新增驗證資訊" + }, + "unassign-devices-from-edge-title": "您確定要解除邊緣設備 { count, plural, 1 {1 device} other {# devices} }的指定嗎?", + "unassign-devices-from-edge-text": "確認後邊緣指定設備將解除指定及其所有相關資料將無法恢復。" + }, + "asset-profile": { + "asset-profile": "Asset profile", + "asset-profiles": "Asset profiles", + "all-asset-profiles": "All", + "add": "Add asset profile", + "edit": "Edit asset profile", + "asset-profile-details": "Asset profile details", + "no-asset-profiles-text": "No asset profiles found", + "search": "Search asset profiles", + "selected-asset-profiles": "{ count, plural, 1 {1 asset profile} other {# asset profiles} } selected", + "no-asset-profiles-matching": "No asset profile matching '{{entity}}' were found.", + "asset-profile-required": "Asset profile is required", + "idCopiedMessage": "Asset profile Id has been copied to clipboard", + "set-default": "Make asset profile default", + "delete": "Delete asset profile", + "copyId": "Copy asset profile Id", + "name-max-length": "Name should be less than 256", + "new-device-profile-name": "Asset profile name", + "new-device-profile-name-required": "Asset profile name is required.", + "name": "Name", + "name-required": "Name is required.", + "image": "Asset profile image", + "description": "Description", + "default": "Default", + "default-rule-chain": "Default rule chain", + "mobile-dashboard": "Mobile dashboard", + "mobile-dashboard-hint": "Used by mobile application as a asset details dashboard", + "select-queue-hint": "Select from a drop-down list.", + "delete-asset-profile-title": "Are you sure you want to delete the asset profile '{{assetProfileName}}'?", + "delete-asset-profile-text": "Be careful, after the confirmation the asset profile and all related data will become unrecoverable.", + "delete-asset-profiles-title": "Are you sure you want to delete { count, plural, 1 {1 asset profile} other {# asset profiles} }?", + "delete-asset-profiles-text": "Be careful, after the confirmation all selected asset profiles will be removed and all related data will become unrecoverable.", + "set-default-asset-profile-title": "Are you sure you want to make the asset profile '{{assetProfileName}}' default?", + "set-default-asset-profile-text": "After the confirmation the asset profile will be marked as default and will be used for new assets with no profile specified.", + "no-asset-profiles-found": "No asset profiles found.", + "create-new-asset-profile": "Create a new one!", + "create-asset-profile": "Create new asset profile", + "import": "Import asset profile", + "export": "Export asset profile", + "export-failed-error": "Unable to export asset profile: {{error}}", + "asset-profile-file": "Asset profile file", + "invalid-asset-profile-file-error": "Unable to import asset profile: Invalid asset profile data structure." + }, + "device-profile": { + "device-profile": "設備協議", + "device-profiles": "設備協議", + "all-device-profiles": "全部", + "add": "增加設備協議", + "edit": "編輯設備協議", + "device-profile-details": "設備協議詳情", + "no-device-profiles-text": "未找到設備協議文件", + "search": "搜尋設備協議", + "selected-device-profiles": "{ count, plural, 1 {1 設備協議} other {# 設備協議} }被選中", + "no-device-profiles-matching": "未找到與 '{{entity}}'匹配的設備協議。", + "device-profile-required": "需要設備協議", + "idCopiedMessage": "設備協議Id已複製到剪貼板", + "set-default": "將設備協議設為預設", + "delete": "刪除設備協議", + "copyId": "複製設備協議Id", + "name-max-length": "名稱應小於256", + "new-device-profile-name": "設備協議名稱", + "new-device-profile-name-required": "需要設備協議名稱。", + "name": "名稱", + "name-required": "需要名稱", + "type": "協議類型", + "type-required": "需要協議類型。", + "type-default": "預設", + "image": "設備協議圖像", + "transport-type": "傳輸類型", + "transport-type-required": "需要傳輸類型。", + "transport-type-default": "預設", + "transport-type-default-hint": "支持基本的MQTT、HTTP和CoAP 傳輸", + "transport-type-mqtt": "MQTT", + "transport-type-mqtt-hint": "啟用進階MQTT傳輸設定", + "transport-type-coap": "CoAP", + "transport-type-coap-hint": "啟用進階CoAP傳輸設定", + "transport-type-lwm2m": "LWM2M", + "transport-type-lwm2m-hint": "LWM2M傳輸類型", + "transport-type-snmp": "SNMP", + "transport-type-snmp-hint": "指定SNMP傳輸配置", + "description": "描述", + "default": "預設", + "profile-configuration": "屬性配置", + "transport-configuration": "傳輸配置", + "default-rule-chain": "預設規則鏈", + "mobile-dashboard": "移動儀表板", + "mobile-dashboard-hint": "由移動應用程序用作設備詳情儀表板", + "select-queue-hint": "從下拉列表中選擇。", + "delete-device-profile-title": "您確定要刪除 '{{deviceProfileName}}' 設備協議嗎?", + "delete-device-profile-text": "小心!確認後此設備協議及其OTA更新的相關資料將無法恢復。", + "delete-device-profiles-title": "您確定要刪除設備協議標題嗎{ count, plural, 1 {1 設備協議} other {# 設備協議} }?", + "delete-device-profiles-text": "小心!確認後所有選擇的設備協議及其OTA更新的相關資料將無法恢復。", + "set-default-device-profile-title": "您確定要將 '{{deviceProfileName}}' 設為設備協議預設值嗎?", + "set-default-device-profile-text": "確認後此預設值將將做爲未指定的新設備協議。", + "no-device-profiles-found": "未找到設備協議文件", + "create-new-device-profile": "建立一個新的!", + "mqtt-device-topic-filters": "MQTT設備主題過濾", + "mqtt-device-topic-filters-unique": "MQTT設備主題過濾必須為唯一值", + "mqtt-device-payload-type": "MQTT設備内容", + "mqtt-device-payload-type-json": "JSON", + "mqtt-device-payload-type-proto": "Protobuf", + "mqtt-enable-compatibility-with-json-payload-format": "啟用與其他内容格式的相容性", + "mqtt-enable-compatibility-with-json-payload-format-hint": "啟用後,平台將預設使用Protobuf内容。如果解析失敗,平台將嘗試使用JSON内容格式。在靭體更新期間對向後相容很有用。例如,初始版本的靭體使用Json,而新版本則使用Protobuf。在設備群的靭體新過程中,需要同時支援Protobuf和JSON。相容性模式會帶來輕微的性能下降,因此建議在所有設備都更新後禁用該模式。", + "mqtt-use-json-format-for-default-downlink-topics": "使用Json格式做爲預設的下行主題", + "mqtt-use-json-format-for-default-downlink-topics-hint": "啟用後,平台將使用Json有效負載格式通過以下主題推送屬性和RPC:v1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id。此設置不會影響使用新(v2)主題發送的屬性和rpc訂閱: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id。其中 $request_id是一個整數請求識別字。", + "mqtt-send-ack-on-validation-exception": "在PUBLISH消息驗證失敗時發送PUBACK", + "mqtt-send-ack-on-validation-exception-hint": "預設情況下,平台將在消息驗證失敗時關閉MQTT會談。當啟用時,平台將發送發佈確認,而非關閉會談。", + "snmp-add-mapping": "增加SNMP映射", + "snmp-mapping-not-configured": "未配置OID到時間序列/遙測的映射", + "snmp-timseries-or-attribute-name": "映射的時間序列/屬性名稱", + "snmp-timseries-or-attribute-type": "映射的時間序列/屬性類型", + "snmp-method-pdu-type-get-request": "GetRequest", + "snmp-method-pdu-type-get-next-request": "GetNextRequest", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", + "mqtt-payload-type-required": "需要負載類型", + "coap-device-type": "CoAP設備類型", + "coap-device-payload-type": "CoAP設備有效負載", + "coap-device-type-required": "需要CoAP設備類型。", + "coap-device-type-default": "預設", + "coap-device-type-efento": "Efento NB-IoT", + "support-level-wildcards": "支持單[+] 和多級[#]萬用字元。", + "telemetry-topic-filter": "遙測主題過濾器", + "telemetry-topic-filter-required": "需要遙測主題過濾器。", + "attributes-topic-filter": "屬性主題過濾器", + "attributes-topic-filter-required": "需要屬性主題過濾器。", + "telemetry-proto-schema": "遙測原型模式", + "telemetry-proto-schema-required": "需要遙測原型模式。", + "attributes-proto-schema": "屬性原型模式", + "attributes-proto-schema-required": "需要屬性原型模式。", + "rpc-response-proto-schema": "RPC響應原型模式", + "rpc-response-proto-schema-required": "需要RPC響應原型模式。", + "rpc-response-topic-filter": "RPC響應主題過濾器", + "rpc-response-topic-filter-required": "需要RPC響應主題過濾器。", + "rpc-request-proto-schema": "RPC請求原型模式", + "rpc-request-proto-schema-required": "需要RPC請求原型模式。", + "rpc-request-proto-schema-hint": "RPC請求訊息應該總是有字段:string method = 1; int32 requestId = 2; 和params = 3的任何資料類型。", + "not-valid-pattern-topic-filter": "無效的模式主題過濾器", + "not-valid-single-character": "單級萬用字元的使用無效", + "not-valid-multi-character": "多級萬用字元的使用無效", + "single-level-wildcards-hint": "[+]適用於任何主題過濾級別。例如 v1/devices/+/telemetry 或 +/devices/+/attributes。", + "multi-level-wildcards-hint": "[#]可以替換主題過濾器本身,並且必須是主題的最後一個符號。 例如: #或v1/devices/me/#。", + "alarm-rules": "警告規則", + "alarm-rules-with-count": "警告規則 ({{count}})", + "no-alarm-rules": "未配置警告規則", + "add-alarm-rule": "增加警告規則", + "edit-alarm-rule": "編輯警告規則", + "alarm-type": "警告類型", + "alarm-type-required": "需要警告類型。", + "alarm-type-unique": "警告類型必須為符合設備協議警告規則的唯一值", + "alarm-type-max-length": "警告類型應小於256。", + "create-alarm-pattern": "建立{{alarmType}}警告", + "create-alarm-rules": "建立警告規則", + "no-create-alarm-rules": "未配置創建條件", + "add-create-alarm-rule-prompt": "請添加建立警告規則", + "clear-alarm-rule": "清除警告規則", + "no-clear-alarm-rule": "未配置清除條件", + "add-create-alarm-rule": "增加建立條件", + "add-clear-alarm-rule": "增加清除條件", + "select-alarm-severity": "選擇警告嚴重性", + "alarm-severity-required": "需要警告嚴重性。", + "condition-duration": "條件持續時間", + "condition-duration-value": "持續時間值", + "condition-duration-time-unit": "時間單位", + "condition-duration-value-range": "持續時間值應在1到2147483647的範圍內。", + "condition-duration-value-pattern": "持續時間值應該是整數。", + "condition-duration-value-required": "需要持續時間值。", + "condition-duration-time-unit-required": "需要時間單位。", + "advanced-settings": "進階設定", + "alarm-rule-details": "詳細資訊", + "alarm-rule-details-hint": "提示:使用${keyName}替換警告規則條件中使用的屬性或遙測鍵的值。", + "add-alarm-rule-details": "增加詳細資訊", + "alarm-rule-mobile-dashboard": "移動儀表板", + "alarm-rule-mobile-dashboard-hint": "由移動應用程序用作警告詳情儀表板", + "alarm-rule-no-mobile-dashboard": "未選擇儀表板", + "propagate-alarm": "傳播警告給相關實體", + "alarm-rule-relation-types-list": "要傳播的關聯類型", + "alarm-rule-relation-types-list-hint": "如果未選擇傳播關聯類型,則將在不按關聯類型過濾的情況下傳播警告。", + "propagate-alarm-to-owner": "傳播警告給相關實體擁有者", + "propagate-alarm-to-tenant": "傳播警告給租戶", + "alarm-details": "警告詳細資料", + "alarm-rule-condition": "警告規則條件", + "enter-alarm-rule-condition-prompt": "請新增警告規則條件", + "edit-alarm-rule-condition": "編輯警告規則條件", + "device-provisioning": "設備佈建", + "provision-strategy": "設備佈建策略", + "provision-strategy-required": "設備佈建策略必填", + "provision-strategy-disabled": "關閉", + "provision-strategy-created-new": "允許建立新設備", + "provision-strategy-check-pre-provisioned": "檢視預先佈建設備", + "provision-device-key": "佈建設備金鑰", + "provision-device-key-required": "佈建設備金鑰必填", + "copy-provision-key": "複製佈建金鑰", + "provision-key-copied-message": "佈建金鑰已複製到剪貼板", + "provision-device-secret": "佈建設備密鑰", + "provision-device-secret-required": "佈建設備金鑰必填", + "copy-provision-secret": "複製佈建密鑰", + "provision-secret-copied-message": "佈建密鑰已複製到剪貼板", + "condition": "條件", + "condition-type": "條件類型", + "condition-type-simple": "條件類型-簡易", + "condition-type-duration": "條件類型-期間", + "condition-during": "{{during}}期間", + "condition-during-dynamic": "在\"{{ attribute }}\" ({{during}})期間", + "condition-type-repeating": "條件類型-重複", + "condition-type-required": "條件類型必填", + "condition-repeating-value": "事件計數", + "condition-repeating-value-range": "事件計數應在1到2147483647的範圍內。", + "condition-repeating-value-pattern": "事件計數應該是整數", + "condition-repeating-value-required": "需要事件計數。", + "condition-repeat-times": "重複 { count, plural, 1 {1 次} other {# 次 }", + "condition-repeat-times-dynamic": "重複 \"{ attribute }\" ({ count, plural, 1 {1 次} other {# 次} })", + "schedule-type": "排程類型", + "schedule-type-required": "排程類型必填", + "schedule": "排程", + "edit-schedule": "編輯警告排程", + "schedule-any-time": "永久啟動", + "schedule-specific-time": "某時間啟動", + "schedule-custom": "客製排程", + "schedule-day": { + "monday": "星期一", + "tuesday": "星期二", + "wednesday": "星期三", + "thursday": "星期四", + "friday": "星期五", + "saturday": "星期六", + "sunday": "星期天" + }, + "schedule-days": "天", + "schedule-time": "次", + "schedule-time-from": "從", + "schedule-time-to": "到", + "schedule-days-of-week-required": "排程每周至少要選擇一天", + "create-device-profile": "建立新設備協議", + "import": "匯入新設備協議", + "export": "匯出新設備協議", + "export-failed-error": "無法匯出設備協議:{{error}}", + "device-profile-file": "設備協議文件", + "invalid-device-profile-file-error": "無法匯入新設備協議:無效的設備協議資料結構。", + "power-saving-mode": "節能模式", + "power-saving-mode-type": { + "default": "使用設備協議的節能模式", + "psm": "節能模式 (PSM)", + "drx": "不間斷接收 (DRX)", + "edrx": "延伸不間斷接收 (eDRX)" + }, + "edrx-cycle": "eDRX週期", + "edrx-cycle-required": "延伸不間斷接收必填", + "edrx-cycle-pattern": "延伸不間斷接收樣式", + "edrx-cycle-min": "eDRX週期的最小數量為{{ min }}秒。", + "paging-transmission-window": "呼叫傳輸窗口", + "paging-transmission-window-required": "呼叫傳輸窗口必填", + "paging-transmission-window-pattern": "呼叫傳輸窗口值需為正整數", + "paging-transmission-window-min": "pPaging傳輸窗口的最小數量是{{ min }}秒。", + "psm-activity-timer": "節能模式活動計時器", + "psm-activity-timer-required": "節能模式活動計時器必填", + "psm-activity-timer-pattern": "節能模式活動計時器值需為正整數", + "psm-activity-timer-min": "節能模式活動計時器最小值為 {{ min }} 秒", + "lwm2m": { + "object-list": "物件列表", + "object-list-empty": "無選擇物件", + "no-objects-found": "找不到物件", + "no-objects-matching": "找不到匹配物件 '{{object}}' ", + "model-tab": "LWM2M模型", + "add-new-instances": "新增執行個體", + "instances-list": "執行個體列表", + "instances-list-required": "執行個體列表為必填", + "instance-id-pattern": "執行個體id值需為正整數", + "instance-id-max": "執行個體id最大值{{max}}", + "instance": "執行個體", + "resource-label": "資源名稱", + "observe-label": "觀測標籤", + "attribute-label": "屬性", + "telemetry-label": "遙測", + "edit-observe-select": "編輯觀測請選擇遙測或屬性", + "edit-attributes-select": "編輯屬性觀測請選擇遙測或屬性", + "no-attributes-set": "未設定屬性", + "key-name": "金鑰名稱", + "key-name-required": "金鑰名稱必填", + "attribute-name": "名稱屬性", + "attribute-name-required": "名稱屬性必填", + "attribute-value": "屬性值", + "attribute-value-required": "屬性值必填", + "attribute-value-pattern": "屬性值需為正整數", + "edit-attributes": "編輯屬性名稱{{ name }}", + "view-attributes": "檢視屬性名稱{{ name }}", + "add-attribute": "新增屬性", + "edit-attribute": "編輯屬性", + "view-attribute": "檢視屬性", + "remove-attribute": "移除屬性", + "delete-server-text": "小心!確認後伺服器配置資料將無法恢復。", + "delete-server-title": "您確定要刪除伺服器嗎?", + "mode": "安全性配置模式", + "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Bootstrap伺服器(短Id...)", + "lwm2m-server-legend": "LwM2M伺服器 (短Id...)", + "server": "伺服器", + "short-id": "短伺服器ID", + "short-id-tooltip": "短伺服器ID。用作關聯伺服器物件實例的鏈接。 \n此標識符唯一標識為LwM2M伺服器客戶端配置的每個LwM2M 伺服器。\n當引導伺服器資源的值為'false'時,必須設置資源。\nID:0值和ID:65535值不得用於識別LwM2M伺服器。.", + "short-id-required": "短伺服器ID必填", + "short-id-range": "短伺服器ID長度需介於1到65534。", + "short-id-pattern": "短伺服器ID需為正整數", + "lifetime": "客戶登記使用期限", + "lifetime-required": "客戶登記使用期限必填", + "lifetime-pattern": "客戶登記使用期限需為正整數", + "default-min-period": "預設最小期間 (s)", + "default-min-period-tooltip": "如果觀測中未包含此參數,則LwM2M客戶端應在觀測的最短時段內使用預設值。", + "default-min-period-required": "預設最小期間必填", + "default-min-period-pattern": "最小期間需為正整數", + "notification-storing": "關閉或離線時通知儲存通知", + "binding": "綁定", + "binding-type": { + "u": "透過UDP綁定可隨時觸及客戶。", + "m": "透過MQTT綁定可隨時觸及客戶", + "h": "透過HTTP綁定可隨時觸及客戶", + "t": "透過TCP綁定可隨時觸及客戶", + "s": "透過SMS綁定可隨時觸及客戶", + "n": "N:客戶端必須通過非IP綁定發送對此類請求的響應(自LWM2M 1.1開始支持)。", + "uq": "UQ:佇列模式下的UDP連接(自LWM2M 1.1起不支持)", + "uqs": "UQS:UDP和SMS連接都處於活動狀態; 佇列模式下的UDP,標準模式下的SMS (自LWM2M 1.1起不支持)", + "tq": "TQ:佇列模式下的TCP連接(自LWM2M 1.1起不支持)", + "tqs": "TQS:TCP和SMS連接都處於活動狀態; 佇列模式下的TCP,標準模式下的SMS (自LWM2M 1.1起不支持)", + "sq": "SQ:佇列模式下的SMS連接(自LWM2M 1.1起不支持)" + }, + "binding-tooltip": "這是LwM2M伺服器物件的\"binding\" 資源中的列表 - /1/x/7。\n 表示LwM2M客戶端中支持的綁定模式。\n 此值應與設備物件(/3/0/16)中\"支持的綁定與模式\"資源中的值相同。\n雖然支持多種傳輸,但在整個傳輸對話期間只能使用一個傳輸綁定。\n 例如,當UDP和SMS都被支持時,LwM2M客戶端和LwM2M伺服器可以選擇在整個傳輸對話期間通過UDP或SMS進行通信。", + "bootstrap-server": "Bootstrap Server", + "lwm2m-server": "LwM2M Server", + "include-bootstrap-server": "包括Bootstrap Server更新", + "bootstrap-update-title": "您已經配置過Boostrap Server,您確定要排除更新?", + "bootstrap-update-text": "小心!確認後Boostrap Server配置資料將無法恢復。", + "server-host": "主機", + "server-host-required": "需要主機。", + "server-port": "連接埠", + "server-port-required": "需要連接埠。", + "server-port-pattern": "連接埠必須是正整數。", + "server-port-range": "連接埠應該在1到65535的範圍內。", + "server-public-key": "伺服器公鑰", + "server-public-key-required": "伺服器公鑰必填", + "client-hold-off-time": "延遲時間", + "client-hold-off-time-required": "延遲時間必填", + "client-hold-off-time-pattern": "延遲時間需為正整數", + "client-hold-off-time-tooltip": "僅用於Bootstrap-Server的客戶端延遲時間", + "account-after-timeout": "超時後的帳戶", + "account-after-timeout-required": "需要超時後的帳戶", + "account-after-timeout-pattern": "超時後的帳戶必須為正整數。", + "account-after-timeout-tooltip": "此資源給定超時值後的Bootstrap-Server帳戶", + "server-type": "伺服器類型", + "add-new-server-title": "增加新的伺服器配置", + "add-server-config": "增加伺服器配置", + "add-lwm2m-server-config": "增加LwM2M伺服器", + "no-config-servers": "未配置伺服器", + "others-tab": "其他設定", + "client-strategy": "連接時的客戶端策略", + "client-strategy-label": "策略", + "client-strategy-only-observe": "在初始連接後,只向客户發出觀測請求。", + "client-strategy-read-all": "在註冊後,向客户發出資源及觀測請求。", + "fw-update": "韌體更新", + "fw-update-strategy": "韌體更新政策", + "fw-update-strategy-data": "使用物件19和資源0(資料)將韌體更新作為二進位檔案推送", + "fw-update-strategy-package": "使用物件5和資源0 (套件)將韌體更新作為二進位檔案推送", + "fw-update-strategy-package-uri": "自動生成唯一的CoAP URL 以下載套件並將韌體更新推送為物件5和資源1 (套件URI)", + "sw-update": "軟體更新", + "sw-update-strategy": "軟體更新政策", + "sw-update-strategy-package": "使用物件9和資源2(套件)推送二進位檔案", + "sw-update-strategy-package-uri": "自動生成唯一的CoAP URL以下載套件並使用物件9和資源3 (套件URI)推送軟體更新", + "fw-update-resource": "韌體更新CoAP資源", + "fw-update-resource-required": "需要韌體更新CoAP資源。", + "sw-update-resource": "軟體更新CoAP資源", + "sw-update-resource-required": "需要軟體更新CoAP資源。", + "config-json-tab": "Json設定屬性設備", + "attributes-name": { + "min-period": "最小期間", + "max-period": "最大期間", + "greater-than": "大於", + "less-than": "小於", + "step": "步", + "min-evaluation-period": "最小評估期間", + "max-evaluation-period": "最大評估期間" + }, + "composite-operations-support": "支持複合讀/寫/觀察 操作" + }, + "snmp": { + "add-communication-config": "新增通訊配置", + "add-mapping": "新增映射", + "authentication-passphrase": "密語驗證", + "authentication-passphrase-required": "密語驗證必填", + "authentication-protocol": "驗證協定", + "authentication-protocol-required": "驗證協定必填", + "communication-configs": "通訊配置", + "community": "社群字串", + "community-required": "社群字串為填", + "context-name": "情境名稱", + "data-key": "資料金鑰", + "data-key-required": "資料金鑰必填", + "data-type": "資料類型", + "data-type-required": "資料類型必填", + "engine-id": "引擎ID", + "host": "主機", + "host-required": "需要主機。", + "oid": "OID", + "oid-pattern": "OID格式無效。.", + "oid-required": "需要OID。", + "please-add-communication-config": "請新增通訊配置", + "please-add-mapping-config": "請新增映射配置", + "port": "連接埠", + "port-format": "無效連接埠格式", + "port-required": "需要連接埠。", + "privacy-passphrase": "隱私密語", + "privacy-passphrase-required": "隱私密語必填", + "privacy-protocol": "隱私協定", + "privacy-protocol-required": "隱私協定必填", + "protocol-version": "協定版本", + "protocol-version-required": "協定版本必填", + "querying-frequency": "查詢頻率", + "querying-frequency-invalid-format": "查詢頻率值需為正整數", + "querying-frequency-required": "查詢頻率必填", + "retries": "重試", + "retries-invalid-format": "重試值需為正整數", + "retries-required": "重試必填", + "scope": "範圍", + "scope-required": "範圍必填", + "security-name": "安全性名稱", + "security-name-required": "安全性名稱必填", + "timeout-ms": "超時,毫秒", + "timeout-ms-invalid-format": "超時值需為正整數", + "timeout-ms-required": "超時必填", + "user-name": "用戶名稱", + "user-name-required": "用戶名稱必填" + } + }, + "dialog": { + "close": "關閉對話框" + }, + "direction": { + "column": "列", + "row": "行" + }, + "edge": { + "edge": "邊緣", + "edge-instances": "邊緣實例", + "edge-file": "邊緣文件", + "name-max-length": "名稱應小於256", + "label-max-length": "標籤應小於256", + "type-max-length": "類型應小於256", + "management": "邊緣管理", + "no-edges-matching": "找不到與 '{{entity}}'匹配的邊緣 ", + "add": "新增邊緣", + "no-edges-text": "未找到邊緣", + "edge-details": "邊緣詳情", + "add-edge-text": "增加新邊緣", + "delete": "刪除邊緣", + "delete-edge-title": "您確定要刪除邊緣'{{edgeName}}'嗎?", + "delete-edge-text": "小心!確認後邊緣及其所有相關資料將無法恢復。", + "delete-edges-title": "您確定要刪除邊緣 { count, plural, 1 {1 edge} other {# edges} } 嗎?", + "delete-edges-text": "小心,確認後,所有選定的邊緣將被刪除,所有相關資料將無法恢復。", + "name": "名稱", + "name-starts-with": "邊緣名稱始于", + "name-required": "名稱必填", + "description": "描述", + "details": "詳細資訊", + "events": "事件", + "copy-id": "複製邊緣Id", + "id-copied-message": "邊緣已複製到剪貼簿", + "sync": "邊緣同步", + "edge-required": "邊緣必填", + "edge-type": "邊緣類型", + "edge-type-required": "邊緣類型必填", + "event-action": "事件動作", + "entity-id": "實體ID", + "select-edge-type": "選擇邊緣類型", + "assign-to-customer": "分配給客戶", + "assign-to-customer-text": "請選擇要分配邊緣的客戶", + "assign-edge-to-customer": "將邊緣分配給客戶", + "assign-edge-to-customer-text": "請選擇要分配給客戶的邊緣", + "assignedToCustomer": "分配給客戶", + "edge-public": "邊緣是公開的", + "assigned-to-customer": "分配給:{{customerTitle}}", + "unassign-from-customer": "從客戶取消分配", + "unassign-edge-title": "您確定要取消分配邊緣'{{edgeName}}'嗎?", + "unassign-edge-text": "確認後,邊緣將被取消分配,客戶將無法訪問。", + "unassign-edges-title": "您確定要取消分配 { count, plural, 1 {1 邊緣} other {# 邊緣} }嗎?", + "unassign-edges-text": "確認後,所有選定的邊緣都將被取消分配,客戶將無法訪問。", + "make-public": "公開邊緣", + "make-public-edge-title": "您確定要公開邊緣'{{edgeName}}' 嗎?", + "make-public-edge-text": "確認後,邊緣及其所有資料將公開並可供其他人訪問。", + "make-private": "將邊緣設為私有", + "public": "公開", + "make-private-edge-title": "您確定要將邊緣'{{edgeName}}'設為私有嗎?", + "make-private-edge-text": "確認後,邊緣及其所有資料將被設為私有,其他人無法訪問。", + "import": "匯入邊緣", + "label": "標籤", + "load-entity-error": "加載資料失敗。實體已被刪除。", + "assign-new-edge": "分配新邊緣", + "unassign-from-edge": "從邊緣取消分配", + "edge-key": "邊緣鍵", + "copy-edge-key": "複製邊緣鍵", + "edge-key-copied-message": "邊緣鍵已複製到剪貼板", + "edge-secret": "邊緣密鑰", + "copy-edge-secret": "複製邊緣密鑰", + "edge-secret-copied-message": "邊緣密鑰已複製到剪貼板", + "edge-assets": "邊緣資產", + "edge-devices": "邊緣設備", + "edge-entity-views": "邊緣實體視圖", + "edge-dashboards": "邊緣儀表板", + "edge-rulechains": "邊緣規則鏈", + "assets": "邊緣資產", + "devices": "邊緣設備", + "entity-views": "邊緣實體視圖", + "dashboard": "邊緣儀表板", + "dashboards": "邊緣儀表板", + "rulechain-templates": "角色鏈模型", + "rulechains": "規則鏈", + "search": "搜尋邊緣", + "selected-edges": "{ count, plural, 1 {1 邊緣} other {# 邊緣} }被選中", + "any-edge": "任何邊緣", + "no-edge-types-matching": "未找到與'{{entitySubtype}}'匹配的邊緣類型。", + "edge-type-list-empty": "未選擇邊緣類型", + "edge-types": "邊緣類型", + "enter-edge-type": "輸入邊緣類型", + "deployed": "部署", + "pending": "待辦的", + "downlinks": "下行鏈結", + "no-downlinks-prompt": "未找到下行鏈結", + "sync-process-started-successfully": "同步程序已成功啟動!", + "missing-related-rule-chains-title": "邊緣缺少相關規則鏈", + "missing-related-rule-chains-text": "分配給邊緣規則鏈的規則節點將訊息轉發給未分配給此邊緣的規則鏈。

              缺少的規則鏈清單:
              {{missingRuleChains}}", + "widget-datasource-error": "此部件僅支持邊緣實體資料來源" + }, + "edge-event": { + "type-dashboard": "儀表板", + "type-asset": "資產", + "type-device": "設備", + "type-device-profile": "設備協議", + "type-entity-view": "實體視圖", + "type-alarm": "警告", + "type-rule-chain": "規則鏈", + "type-rule-chain-metadata": "規則鏈元資料", + "type-edge": "邊緣", + "type-user": "用戶", + "type-customer": "客戶", + "type-relation": "關聯", + "type-widgets-bundle": "部件包", + "type-widgets-type": "部件類型", + "type-admin-settings": "管理員設定", + "action-type-added": "增加", + "action-type-deleted": "刪除", + "action-type-updated": "更新", + "action-type-post-attributes": "發布屬性", + "action-type-attributes-updated": "更新屬性", + "action-type-attributes-deleted": "刪除屬性", + "action-type-timeseries-updated": "更新時間序列", + "action-type-credentials-updated": "更新憑據", + "action-type-assigned-to-customer": "分配給客戶", + "action-type-unassigned-from-customer": "從客戶處取消分配", + "action-type-relation-add-or-update": "關聯新增或更新", + "action-type-relation-deleted": "刪除關聯", + "action-type-rpc-call": "RPC調用", + "action-type-alarm-ack": "警告確認", + "action-type-alarm-clear": "警告清除", + "action-type-assigned-to-edge": "分配給邊緣", + "action-type-unassigned-from-edge": "從邊緣取消分配", + "action-type-credentials-request": "憑據請求", + "action-type-entity-merge-request": "實體合併請求" + }, + "error": { + "unable-to-connect": "無法連接到伺服器!請檢查您的互聯網連接。", + "unhandled-error-code": "未處理的錯誤代碼: {{errorCode}}", + "unknown-error": "未知錯誤" + }, + "entity": { + "entity": "實體", + "entities": "實體", + "entities-count": "實體計數", + "aliases": "實體別名", + "entity-alias": "實體別名", + "unable-delete-entity-alias-title": "無法刪除實體別名", + "unable-delete-entity-alias-text": "實體別名 '{{entityAlias}}' 被以下部件使用不能刪除:
              {{widgetsList}}", + "duplicate-alias-error": "別名 '{{alias}}' 重複。
              同一儀表板別名必須唯一。", + "missing-entity-filter-error": "別名 '{{alias}}' 缺少過濾器", + "configure-alias": "別名 '{{alias}}' 配置", + "alias": "別名", + "alias-required": "實體別名必填。", + "remove-alias": "移除實體別名", + "add-alias": "增加實體別名", + "entity-list": "實體列表", + "entity-type": "實體類型", + "entity-types": "實體類型", + "entity-type-list": "實體類型列表", + "any-entity": "任意實體", + "enter-entity-type": "輸入實體類型", + "no-entities-matching": "沒有找到符合 '{{entity}}' 的實體。", + "no-entity-types-matching": "沒有找到符合 '{{entityType}}' 類型的實體。", + "name-starts-with": "名稱開始於", + "help-text": "根據需要使用'%':'%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'.", + "use-entity-name-filter": "用戶過濾", + "entity-list-empty": "沒有選擇實體。", + "entity-type-list-empty": "沒有選擇實體類型。", + "entity-name-filter-required": "實體名過濾器必填。", + "entity-name-filter-no-entity-matched": "沒有找到以 '{{entity}}' 開頭的實體", + "all-subtypes": "所有", + "select-entities": "選擇實體", + "no-aliases-found": "沒有找到別名", + "no-alias-matching": "沒有找到 '{{alias}}'", + "create-new-alias": "建立新別名", + "key": "鍵", + "key-name": "鍵名", + "no-keys-found": "沒有找到鍵", + "no-key-matching": "沒有找到鍵 '{{key}}'", + "create-new-key": "建立新鍵", + "type": "類型", + "type-required": "實體類型必填。", + "type-device": "設備", + "type-devices": "設備", + "list-of-devices": "{ count, plural, 1 {一個設備} other {# 設備列表} }", + "device-name-starts-with": "以 '{{prefix}}' 開頭的設備", + "type-asset": "資產", + "type-assets": "資產", + "list-of-assets": "{ count, plural, 1 {一個資產} other {# 資產列表} }", + "asset-name-starts-with": "以 '{{prefix}}' 開頭的資產", + "type-entity-view": "實體視圖", + "type-entity-views": "實體視圖", + "list-of-entity-views": "{ count, plural, 1 {一個實體視圖} other {# 實體視圖列表} }", + "entity-view-name-starts-with": "以 '{{prefix}}' 開頭的實體視圖", + "type-rule": "規則", + "type-rules": "規則", + "list-of-rules": "{ count, plural, 1 {一個規則} other {# 規則列表} }", + "rule-name-starts-with": "以 '{{prefix}}' 開頭的規則", + "type-plugin": "插件", + "type-plugins": "插件", + "list-of-plugins": "{ count, plural, 1 {一個插件} other {# 插件列表} }", + "tenant-name-starts-with": "名稱以 '{{prefix}}'開頭的租戶", + "type-tenant-profile": "租戶屬性", + "type-tenant-profiles": "租戶屬性", + "list-of-tenant-profiles": "{ count, plural, 1 {一個租戶屬性} other {# 租戶屬性列表} }", + "tenant-profile-name-starts-with": "名稱以 '{{prefix}}'開頭的租戶屬性", + "plugin-name-starts-with": "以 '{{prefix}}' 開頭的插件", + "type-tenant": "租戶", + "type-tenants": "租戶", + "list-of-tenants": "{ count, plural, 1 {一個租戶} other {# 租戶列表} }", + "type-customer": "客戶", + "type-customers": "客戶", + "list-of-customers": "{ count, plural, 1 {一個客戶} other {# 客戶列表} }", + "customer-name-starts-with": "以 '{{prefix}}' 開頭的客戶", + "type-user": "用戶", + "type-users": "用戶", + "list-of-users": "{ count, plural, 1 {一個用戶} other {# 用戶列表} }", + "user-name-starts-with": "以 '{{prefix}}' 開頭的用戶", + "type-dashboard": "儀表板", + "type-dashboards": "儀表板", + "list-of-dashboards": "{ count, plural, 1 {一個儀表板} other {# 儀表板列表} }", + "dashboard-name-starts-with": "以 '{{prefix}}' 開頭的儀表板", + "type-alarm": "警告", + "type-alarms": "警告", + "list-of-alarms": "{ count, plural, 1 {一個警告} other {# 警告列表} }", + "alarm-name-starts-with": "以 '{{prefix}}' 開頭的警告", + "type-rulechain": "規則鏈", + "type-rulechains": "規則鏈", + "list-of-rulechains": "{ count, plural, 1 {一個規則鏈} other {# 規則鏈列表} }", + "rulechain-name-starts-with": "規則鏈前綴名稱 '{{prefix}}'", + "type-rulenode": "規則節點", + "type-rulenodes": "規則節點", + "list-of-rulenodes": "{ count, plural, 1 {一個規則節點} other {# 規則節點列表} }", + "rulenode-name-starts-with": "名稱以'{{prefix}}'開頭的規則節點", + "type-current-customer": "當前客戶", + "type-current-tenant": "當前租戶", + "type-current-user": "當前用戶", + "type-current-user-owner": "當前用戶所有者", + "type-widgets-bundle": "部件包", + "type-widgets-bundles": "部件包", + "list-of-widgets-bundles": "{ count, plural, 1 {一個部件包} other {# 部件包列表} }", + "search": "實體檢索", + "selected-entities": "{ count, plural, 1 {1 實體} other {# 實體} } 被選中", + "entity-name": "實體名", + "entity-label": "實體標籤", + "details": "實體詳細資訊", + "no-entities-prompt": "沒有找到實體", + "no-data": "無資料", + "columns-to-display": "要顯示的列", + "type-api-usage-state": "api使用狀態", + "type-edge": "邊緣", + "type-edges": "邊緣", + "list-of-edges": "{ count, plural, 1 {一個邊緣} other {# 邊緣列表} }", + "edge-name-starts-with": "名稱以'{{prefix}}'開頭的邊緣", + "type-tb-resource": "資源", + "type-ota-package": "OTA套件" + }, + "entity-field": { + "created-time": "建立時間", + "name": "名稱", + "type": "類型", + "first-name": "名字", + "last-name": "姓", + "email": "電子郵件", + "title": "標題", + "country": "國家", + "state": "州", + "city": "城市", + "address": "地址", + "address2": "地址2", + "zip": "Zip", + "phone": "手機", + "label": "標籤" + }, + "entity-view": { + "entity-view": "實體視圖", + "entity-view-required": "實體視圖必填。", + "entity-views": "實體視圖", + "management": "實體視圖管理", + "view-entity-views": "查看實體視圖", + "entity-view-alias": "實體視圖別名", + "aliases": "實體視圖別名", + "no-alias-matching": "'{{alias}}' 沒有找到。", + "no-aliases-found": "找不到別名。", + "no-key-matching": "'{{key}}' 沒有找到。", + "no-keys-found": "找不到密鑰。", + "create-new-alias": "建立一個新的!", + "create-new-key": "建立一個新的!", + "duplicate-alias-error": "找到重複別名 '{{alias}}'。
              實體視圖別名必須是唯一的。", + "configure-alias": "配置 '{{alias}}' 別名", + "no-devices-matching": "找不到與 '{{entity}}' 符合的實體視圖。", + "public": "公開", + "alias": "別名", + "alias-required": "需要實體視圖別名。", + "remove-alias": "刪除實體視圖別名", + "add-alias": "增加實體視圖別名", + "name-starts-with": "名稱前綴", + "help-text": "根據需要使用'%':'%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", + "entity-view-list": "實體視圖列表", + "use-entity-view-name-filter": "使用過濾器", + "entity-view-list-empty": "沒有被選中的實體視圖", + "entity-view-name-filter-required": "實體視圖名稱過濾器必填。", + "entity-view-name-filter-no-entity-view-matched": "找不到以'{{entityView}}' 開頭的實體視圖。", + "add": "增加實體視圖", + "entity-view-public": "實體視圖是公開的", + "assign-to-customer": "分配給客戶", + "assign-entity-view-to-customer": "將實體視圖分配給客戶", + "assign-entity-view-to-customer-text": "請選擇要分配給客戶的實體視圖", + "assign-entity-view-to-edge-title": "將實體視圖分配給邊緣", + "no-entity-views-text": "找不到實體視圖", + "assign-to-customer-text": "請選擇客戶分配實體視圖", + "entity-view-details": "實體視圖詳細訊息", + "add-entity-view-text": "增加新實體視圖", + "delete": "刪除實體視圖", + "assign-entity-views": "分配實體視圖", + "assign-entity-views-text": "分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} } 給客戶", + "delete-entity-views": "刪除實體視圖", + "unassign-from-customer": "取消分配客戶", + "unassign-entity-views": "取消分配實體視圖", + "unassign-entity-views-action-title": "從客戶處取消分配{count,plural,1 {1 實體視圖} other {# 實體視圖} }", + "assign-new-entity-view": "分配新實體視圖", + "delete-entity-view-title": "確定要刪除實體視圖 '{{entityViewName}}'?", + "delete-entity-view-text": "小心!確認後實體視圖及其所有相關資料將無法恢復。", + "delete-entity-views-title": "確定要刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }?", + "delete-entity-views-action-title": "刪除 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }", + "delete-entity-views-text": "小心,確認後,所有選擇的實體視圖將被刪除,所有相關的資料將變得無法恢復。", + "unassign-entity-view-title": "您確定要取消對 '{{entityViewName}}'實體視圖的分配嗎?", + "unassign-entity-view-text": "確認後,實體視圖將未分配,客戶無法存取。", + "unassign-entity-view": "未分配實體視圖", + "unassign-entity-views-title": "您確定要取消分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} }嗎?", + "unassign-entity-views-text": "確認後,所有選擇的實體視圖將被分配,客戶無法存取。", + "entity-view-type": "實體視圖類型", + "entity-view-type-required": "實體視圖類型必填。", + "select-entity-view-type": "選擇實體視圖類型", + "enter-entity-view-type": "輸入實體視圖類型", + "any-entity-view": "任何實體視圖", + "no-entity-view-types-matching": "沒有找到符合 '{{entitySubtype}}' 的實體視圖類型。", + "entity-view-type-list-empty": "實體視圖類型未選擇。", + "entity-view-types": "實體視圖類型", + "created-time": "建立時間", + "name": "名稱", + "name-required": "名稱必填。", + "name-max-length": "名稱應小於256", + "type-max-length": "實體視圖類型應小於256", + "description": "描述", + "events": "事件", + "details": "詳細資訊", + "copyId": "複製實體視圖ID", + "idCopiedMessage": "實體視圖Id已複製到剪貼板", + "assignedToCustomer": "分配給客戶", + "unable-entity-view-device-alias-title": "無法刪除實體視圖別名", + "unable-entity-view-device-alias-text": "實體視圖別名 '{{entityViewAlias}}' 不能夠被刪除,因為它被下列部件所使用:
              {{widgetsList}}", + "select-entity-view": "選擇實體視圖", + "make-public": "實體視圖設為公開", + "make-private": "實體視圖設為私有", + "start-date": "開始日期", + "start-ts": "開始時間", + "end-date": "結束日期", + "end-ts": "結束時間", + "date-limits": "日期限製", + "client-attributes": "客戶端屬性", + "shared-attributes": "共享屬性", + "server-attributes": "服務端屬性", + "timeseries": "時間序列", + "client-attributes-placeholder": "客戶端屬性", + "shared-attributes-placeholder": "共享屬性", + "server-attributes-placeholder": "服務端屬性", + "timeseries-placeholder": "時間序列", + "target-entity": "目標實體", + "attributes-propagation": "屬性傳播", + "attributes-propagation-hint": "每次儲存或更新這個實體視圖時,實體視圖將自動從目標實體複製指定的屬性。由於性能原因,目標實體屬性不會在每次屬性更改時傳播到實體視圖。您可以通過配置\"copy to view\"規則鏈中的規則節點,並將\"Post attributes\"和\"attributes Updated\"消息連結到新規則節點,從而啟用自動傳播。", + "timeseries-data": "時間序列資料", + "timeseries-data-hint": "配置目標實體的時間序列資料鍵,以便實體視圖可以存取這些鍵。這個時間序列資料是只讀的。", + "search": "搜尋實體視圖", + "selected-entity-views": "{ count, plural, 1 {1 實體視圖} other {# 實體視圖} } 被選中", + "make-public-entity-view-title": "你確定你想建立公開 '{{entityViewName}}' 實體視圖?", + "make-public-entity-view-text": "確認後,實體視圖 及其所有資料將被公開並被他人存取。", + "make-private-entity-view-title": "你確定你想建立私有 '{{entityViewName}}' 實體視圖?", + "make-private-entity-view-text": "確認後,實體視圖及其所有資料將被私有化,無法被他人存取。", + "assign-entity-view-to-edge": "將實體視圖分配給邊緣", + "assign-entity-view-to-edge-text": "請選擇要分配給邊緣的實體視圖", + "unassign-entity-view-from-edge-title": "您確定要取消分配實體視圖'{{entityViewName}}'嗎?", + "unassign-entity-view-from-edge-text": "確認後,實體視圖將被取消分配,邊緣將無法訪問。", + "unassign-entity-views-from-edge-action-title": "從邊緣取消分配 { count, plural, 1 {1 實體視圖} other {# 實體視圖} } ", + "unassign-entity-view-from-edge": "取消分配實體視圖", + "unassign-entity-views-from-edge-title": "您確定要取消分配{ count, plural, 1 {1 實體視圖} other {# 實體視圖} }嗎?", + "unassign-entity-views-from-edge-text": "確認後,所有選定的實體視圖都將被取消分配,並且邊緣將無法訪問。" + }, + "event": { + "event-type": "事件類型", + "events-filter": "事件過濾器", + "clean-events": "清除事件", + "type-error": "錯誤", + "type-lc-event": "生命週期事件", + "type-stats": "類型統計", + "type-debug-rule-node": "測試", + "type-debug-rule-chain": "測試", + "no-events-prompt": "找不到事件", + "error": "錯誤", + "alarm": "報警", + "event-time": "事件時間", + "server": "伺服器", + "body": "整體", + "method": "方法", + "type": "類型", + "message": "消息", + "message-id": "消息ID", + "copy-message-id": "複製消息ID", + "message-type": "消息類型", + "data-type": "資料類型", + "relation-type": "關聯類型", + "metadata": "元資料", + "data": "資料", + "event": "事件", + "status": "狀態", + "success": "成功", + "failed": "失敗", + "messages-processed": "消息處理", + "max-messages-processed": "處理的最大消息", + "min-messages-processed": "處理的最小消息", + "errors-occurred": "錯誤發生", + "max-errors-occurred": "發生的最大錯誤", + "min-errors-occurred": "發生的最小錯誤", + "min-value": "最小值為0。", + "all-events": "所有", + "has-error": "有錯誤", + "entity-id": "實體ID", + "copy-entity-id": "複製實體ID", + "entity-type": "實體類型", + "clear-filter": "清除過濾器", + "clear-request-title": "清除所有事件", + "clear-request-text": "您確定要清除所有事件嗎?" + }, + "extension": { + "extensions": "擴展", + "selected-extensions": "{ count, plural, 1 {1 擴展} other {# 擴展} } 被選擇", + "type": "類型", + "key": "鍵名", + "value": "值", + "id": "ID", + "extension-id": "擴展ID", + "extension-type": "擴展類型", + "transformer-json": "JSON *", + "unique-id-required": "當前擴展ID已經存在。", + "delete": "刪除擴展", + "add": "增加擴展", + "edit": "編輯擴展", + "delete-extension-title": "確實要刪除擴展名'{{extensionId}}'嗎?", + "delete-extension-text": "小心,確認後,擴展和所有相關資料將變得無法恢復。", + "delete-extensions-title": "您確定要刪除 { count, plural, 1 {1 表達式} other {# 表達式} }嗎?", + "delete-extensions-text": "小心,確認後,所有選擇的擴展將被刪除。", + "converters": "轉換器", + "converter-id": "轉換器序號", + "configuration": "配置", + "converter-configurations": "轉換器的配置", + "token": "安全token", + "add-converter": "增加轉換器", + "add-config": "增加轉換器配置", + "device-name-expression": "設備名稱表達式", + "device-type-expression": "設備類型表達式", + "custom": "顧客", + "to-double": "加倍", + "transformer": "轉換器", + "json-required": "轉換器JSON必填。", + "json-parse": "無法解析轉換器JSON。", + "attributes": "屬性", + "add-attribute": "增加屬性", + "add-map": "增加映射元素", + "timeseries": "時間序列", + "add-timeseries": "增加時間序列", + "field-required": "必填欄位", + "brokers": "代理伺服器組", + "add-broker": "增加代理伺服器", + "host": "主機", + "port": "連接埠", + "port-range": "連接埠應該在1到65535的範圍內。", + "ssl": "Ssl", + "credentials": "證書", + "username": "用戶名", + "password": "密碼", + "retry-interval": "以毫秒為單位的重試間隔", + "anonymous": "匿名", + "basic": "Basic", + "pem": "PEM", + "ca-cert": "CA證書文件 *", + "private-key": "私鑰文件 *", + "cert": "證書文件 *", + "no-file": "沒有選擇文件。", + "drop-file": "刪除文件或單擊以選擇要上載的文件。", + "mapping": "映射", + "topic-filter": "主題濾波", + "converter-type": "轉換類型", + "converter-json": "Json", + "json-name-expression": "設備名稱JSON表達式", + "topic-name-expression": "設備名稱主題表達式", + "json-type-expression": "設備類型JSON表達式", + "topic-type-expression": "設備類型主題表達式", + "attribute-key-expression": "屬性關鍵字表達式", + "attr-json-key-expression": "屬性鍵JSON表達式", + "attr-topic-key-expression": "屬性關鍵字主題表達式", + "request-id-expression": "請求ID表達式", + "request-id-json-expression": "請求ID JSON表達式", + "request-id-topic-expression": "請求ID主題表達式", + "response-topic-expression": "響應主題表達式", + "value-expression": "值表達式", + "topic": "主題", + "timeout": "毫秒超時", + "converter-json-required": "轉換JSON是必需的。", + "converter-json-parse": "無法解析轉換JSON。", + "filter-expression": "過濾表達式", + "connect-requests": "連接請求", + "add-connect-request": "增加連接請求", + "disconnect-requests": "斷開請求", + "add-disconnect-request": "增加斷開請求", + "attribute-requests": "屬性請求", + "add-attribute-request": "增加屬性請求", + "attribute-updates": "屬性更新", + "add-attribute-update": "增加屬性更新", + "server-side-rpc": "服務端RPC", + "add-server-side-rpc-request": "增加服務端RPC請求", + "device-name-filter": "設備名稱濾波", + "attribute-filter": "屬性濾波", + "method-filter": "方法濾波", + "request-topic-expression": "請求主題表達式", + "response-timeout": "毫秒內響應超時", + "topic-expression": "主題表達", + "client-scope": "客戶範圍", + "add-device": "增加伺服器", + "opc-server": "伺服器組", + "opc-add-server": "增加伺服器", + "opc-add-server-prompt": "請增加伺服器", + "opc-application-name": "應用名稱", + "opc-application-uri": "應用URI", + "opc-scan-period-in-seconds": "秒級掃描週期", + "opc-security": "安全性", + "opc-identity": "身份", + "opc-keystore": "密鑰庫", + "opc-type": "類型", + "opc-keystore-type": "類型", + "opc-keystore-location": "位置 *", + "opc-keystore-password": "密碼", + "opc-keystore-alias": "別名", + "opc-keystore-key-password": "密鑰密碼", + "opc-device-node-pattern": "設備節點模式", + "opc-device-name-pattern": "設備名稱模式", + "modbus-server": "Servers/slaves", + "modbus-add-server": "增加 server/slave", + "modbus-add-server-prompt": "請增加 server/slave", + "modbus-transport": "傳輸", + "modbus-tcp-reconnect": "自動重新連接", + "modbus-rtu-over-tcp": "TCP上的RTU", + "modbus-port-name": "串口名稱", + "modbus-encoding": "編碼", + "modbus-parity": "奇偶性", + "modbus-baudrate": "鮑率", + "modbus-databits": "資料位元", + "modbus-stopbits": "停止位元", + "modbus-databits-range": "資料位元應該在7到8的範圍內。", + "modbus-stopbits-range": "停止位元應該在1到2的範圍內。", + "modbus-unit-id": "單位編號", + "modbus-unit-id-range": "單位ID應該在1到247的範圍內", + "modbus-device-name": "設備名稱", + "modbus-poll-period": "輪詢週期 (ms)", + "modbus-attributes-poll-period": "輪詢屬性週期 (ms)", + "modbus-timeseries-poll-period": "時間序列輪詢週期 (ms)", + "modbus-poll-period-range": "輪詢週期應為正值。", + "modbus-tag": "標籤", + "modbus-function": "函數", + "modbus-register-address": "寄存器地址", + "modbus-register-address-range": "寄存器地址應該在0到65535的範圍內。", + "modbus-register-bit-index": "位元索引", + "modbus-register-bit-index-range": "位元索引應該在0到15的範圍內。", + "modbus-register-count": "寄存器計數", + "modbus-register-count-range": "寄存器計數應該是一個正值。", + "modbus-byte-order": "字節順序", + "sync": { + "status": "狀態", + "sync": "同步", + "not-sync": "不同步", + "last-sync-time": "最後同步時間", + "not-available": "無法使用" + }, + "export-extensions-configuration": "匯出擴展配置", + "import-extensions-configuration": "匯入擴展配置", + "import-extensions": "匯入擴展", + "import-extension": "匯入擴展", + "export-extension": "匯出擴展", + "file": "擴展文件", + "invalid-file-error": "無效的擴展文件" + }, + "filter": { + "add": "增加過濾器", + "edit": "編輯過濾器", + "name": "過濾器名稱", + "name-required": "需要過濾器名稱。", + "duplicate-filter": "同名過濾器已存在。", + "filters": "過濾器", + "unable-delete-filter-title": "無法刪除過濾器", + "unable-delete-filter-text": "無法刪除過濾器'{{filter}}' ,因為它被以下部件使用:
              {{widgetsList}}", + "duplicate-filter-error": "找到重複的過濾器 '{{filter}}'。
              過濾器在儀表板中必須是唯一的。", + "missing-key-filters-error": "過濾器'{{filter}}'缺少關鍵過濾器。", + "filter": "過濾器", + "editable": "可編輯", + "no-filters-found": "未找到過濾器。", + "no-filter-text": "未指定過濾器", + "add-filter-prompt": "請增加過濾器", + "no-filter-matching": "找不到'{{filter}}'。", + "create-new-filter": "建立一個新的!", + "filter-required": "需要過濾器。", + "operation": { + "operation": "操作", + "equal": "等於", + "not-equal": "不相等", + "starts-with": "開始於", + "ends-with": "結束於", + "contains": "包含", + "not-contains": "不包含", + "greater": "大於", + "less": "少於", + "greater-or-equal": "大於或等於", + "less-or-equal": "少於或等於", + "and": "和", + "or": "或", + "in": "在", + "not-in": "不在" + }, + "ignore-case": "忽略大小寫", + "value": "值", + "remove-filter": "移除過濾器", + "preview": "過濾器預覽", + "no-filters": "未配置過濾器", + "add-filter": "增加過濾器", + "add-complex-filter": "增加複合過濾器", + "add-complex": "增加複合體", + "complex-filter": "複合過濾器", + "edit-complex-filter": "編輯複合過濾器", + "edit-filter-user-params": "編輯過濾謂詞用戶參數", + "filter-user-params": "過濾謂詞用戶參數", + "user-parameters": "用戶參數", + "display-label": "要顯示的標籤", + "autogenerated-label": "自動生成標籤", + "order-priority": "字段順序優先級", + "key-filter": "關鍵過濾器", + "key-filters": "關鍵過濾器", + "key-name": "鍵名", + "key-name-required": "需要鍵名。", + "key-type": { + "key-type": "鍵類型", + "attribute": "屬性", + "timeseries": "時間序列", + "entity-field": "實體字段", + "constant": "常數" + }, + "value-type": { + "value-type": "值類型", + "string": "字串", + "numeric": "數字", + "boolean": "布林值", + "date-time": "日期和時間" + }, + "value-type-required": "需要鍵值類型。", + "key-value-type-change-title": "您確定要更改鍵值類型嗎?", + "key-value-type-change-message": "如果您確認新的值類型,所有輸入的鍵過濾器都將被刪除。", + "no-key-filters": "未配置鍵過濾器", + "add-key-filter": "增加鍵過濾器", + "remove-key-filter": "移除鍵過濾器", + "edit-key-filter": "編輯鍵過濾器", + "date": "日期", + "time": "時間", + "current-tenant": "當前租戶", + "current-customer": "當前客戶", + "current-user": "當前用戶", + "current-device": "當前設備", + "default-value": "預設值", + "dynamic-source-type": "動態源類型", + "dynamic-value": "動態值", + "no-dynamic-value": "沒有動態值", + "source-attribute": "源屬性", + "switch-to-dynamic-value": "切換到動態值", + "switch-to-default-value": "切換到預設值", + "inherit-owner": "從所有者繼承", + "source-attribute-not-set": "如果未設置源屬性" + }, + "fullscreen": { + "expand": "展開到全螢幕", + "exit": "退出全螢幕", + "toggle": "切換全螢幕模式", + "fullscreen": "全螢幕" + }, + "function": { + "function": "函數" + }, + "gateway": { + "add-entry": "增加配置", + "connector-add": "增加新連接器", + "connector-enabled": "啟用連接器", + "connector-name": "連接器名稱", + "connector-name-required": "需要連接器名稱。", + "connector-type": "連接器類型", + "connector-type-required": "需要連接器類型。", + "connectors": "連接器配置", + "create-new-gateway": "建立新閘道", + "create-new-gateway-text": "您確定要建立一個名稱為:'{{gatewayName}}'的新閘道嗎?", + "delete": "刪除配置", + "download-tip": "下載配置文件", + "gateway": "閘道", + "gateway-exists": "同名設備已存在。", + "gateway-name": "閘道名稱", + "gateway-name-required": "需要閘道名稱。", + "gateway-saved": "閘道配置已成功保存。", + "json-parse": "無效的JSON", + "json-required": "欄位不能為空。", + "no-connectors": "無連接器", + "no-data": "無配置", + "no-gateway-found": "未找到閘道。", + "no-gateway-matching": " 未找到'{{item}}'。", + "path-logs": "日誌文件的路徑", + "path-logs-required": "需要路徑。", + "remote": "移除配置", + "remote-logging-level": "日誌記錄級別", + "remove-entry": "移除配置", + "save-tip": "保存配置文件", + "security-type": "安全類型", + "security-types": { + "access-token": "訪問Token", + "tls": "TLS" + }, + "storage": "貯存", + "storage-max-file-records": "文件中的最大紀錄", + "storage-max-files": "最大文件數", + "storage-max-files-min": "最小數量為1。", + "storage-max-files-pattern": "號碼無效。", + "storage-max-files-required": "需要號碼。", + "storage-max-records": "存儲中的最大紀錄", + "storage-max-records-min": "最小紀錄數為1。", + "storage-max-records-pattern": "號碼無效。", + "storage-max-records-required": "需要最大紀錄數", + "storage-pack-size": "最大事件包大小", + "storage-pack-size-min": "最小數量為1。", + "storage-pack-size-pattern": "號碼無效.", + "storage-pack-size-required": "需要最大事件包大小", + "storage-path": "存儲路徑", + "storage-path-required": "需要存儲路徑。", + "storage-type": "存儲類型", + "storage-types": { + "file-storage": "文件存儲", + "memory-storage": "記憶體存儲" + }, + "thingsboard": "ThingsBoard", + "thingsboard-host": "ThingsBoard主機", + "thingsboard-host-required": "需要主機。", + "thingsboard-port": "ThingsBoard連接埠", + "thingsboard-port-max": "最大埠號為 65535。", + "thingsboard-port-min": "最小埠號為1。", + "thingsboard-port-pattern": "連接埠無效。", + "thingsboard-port-required": "需要連接埠。", + "tidy": "整理", + "tidy-tip": "整理配置JSON", + "title-connectors-json": "連接器{{typeName}}配置", + "tls-path-ca-certificate": "閘道上CA證書的路徑", + "tls-path-client-certificate": "閘道上用戶端憑據的路徑", + "tls-path-private-key": "閘道上的私鑰路徑", + "toggle-fullscreen": "切換全螢幕", + "transformer-json-config": "配置JSON*", + "update-config": "增加/更新配置JSON" + }, + "grid": { + "delete-item-title": "您確定要刪除此項嗎?", + "delete-item-text": "注意,確認後此項及其所有相關資料將變得無法恢復。", + "delete-items-title": "你確定你要刪除 { count, plural, 1 {1 項} other {# 項} }嗎?", + "delete-items-action-title": "刪除 { count, plural, 1 {1 項} other {# 項} }", + "delete-items-text": "注意,確認後所有選擇的項目將被刪除,所有相關資料將無法恢復。", + "add-item-text": "增加新項目", + "no-items-text": "沒有找到項目", + "item-details": "項目詳細訊息", + "delete-item": "刪除項目", + "delete-items": "刪除項目", + "scroll-to-top": "滾動到頂部" + }, + "help": { + "goto-help-page": "轉到幫助頁面", + "show-help": "顯示幫助" + }, + "home": { + "home": "首頁", + "profile": "屬性", + "logout": "註銷", + "menu": "菜單", + "avatar": "頭像", + "open-user-menu": "打開用戶菜單" + }, + "file-input": { + "browse-file": "瀏覽文件", + "browse-files": "瀏覽文件" + }, + "image-input": { + "drop-image-or": "拖放圖像或", + "drop-images-or": "拖放圖像或", + "no-images": "未選擇任何圖像", + "images": "圖像" + }, + "import": { + "no-file": "沒有選擇文件", + "drop-file": "拖動一個JSON文件或者單擊以選擇要上傳的文件。", + "drop-json-file-or": "拖放JSON文件或", + "drop-file-csv": "拖放CSV文件或單擊以選擇要上傳的文件。", + "drop-file-csv-or": "拖放CSV文件或", + "column-value": "值", + "column-title": "標題", + "column-example": "示例值資料", + "column-key": "屬性/遙測鍵", + "credentials": "證書", + "csv-delimiter": "CSV分隔符號", + "csv-first-line-header": "第一行包含列名", + "csv-update-data": "更新屬性/遙測", + "details": "詳細資訊", + "import-csv-number-columns-error": "一個文件應至少包含兩列", + "import-csv-invalid-format-error": "文件格式無效。行: '{{line}}'", + "column-type": { + "name": "名稱", + "type": "類型", + "label": "標籤", + "column-type": "列類型", + "client-attribute": "客戶端屬性", + "shared-attribute": "共享屬性", + "server-attribute": "伺服器屬性", + "timeseries": "時間序列", + "entity-field": "實體字段", + "access-token": "訪問token", + "x509": "X.509", + "mqtt": { + "client-id": "MQTT客戶ID", + "user-name": "MQTT用戶名稱", + "password": "MQTT密碼" + }, + "lwm2m": { + "client-endpoint": "LwM2M端點客戶端名稱", + "security-config-mode": "LwM2M安全配置模式", + "client-identity": "LwM2M客戶端身份", + "client-key": "LwM2M 客戶密鑰", + "client-cert": "LwM2M客戶公鑰", + "bootstrap-server-security-mode": "LwM2M bootstrap server 安全模式", + "bootstrap-server-secret-key": "LwM2M bootstrap server 密鑰", + "bootstrap-server-public-key-id": "LwM2M bootstrap server 公鑰或ID", + "lwm2m-server-security-mode": "LwM2M伺服器安全模式", + "lwm2m-server-secret-key": "LwM2M伺服器密鑰", + "lwm2m-server-public-key-id": "LwM2M伺服器公鑰或ID" + }, + "isgateway": "是閘道", + "activity-time-from-gateway-device": "來自閘道設備的活動時間", + "description": "描述", + "routing-key": "邊緣鍵", + "secret": "邊緣密鑰" + }, + "stepper-text": { + "select-file": "選擇一個文件", + "configuration": "匯入配置", + "column-type": "選擇列類型", + "creat-entities": "創造新實體" + }, + "message": { + "create-entities": "已成功建立{{count}}個新實體。", + "update-entities": "{{count}}個實體已成功更新。", + "error-entities": "建立 {{count}}個實體時出錯。" + } + }, + "item": { + "selected": "選擇" + }, + "js-func": { + "no-return-error": "函數必須返回值!", + "return-type-mismatch": "函數必須返回 '{{type}}' 類型的值!", + "tidy": "整理", + "mini": "迷你" + }, + "key-val": { + "key": "鍵名", + "value": "值", + "remove-entry": "刪除條目", + "add-entry": "增加條目", + "no-data": "沒有條目" + }, + "layout": { + "layout": "佈局", + "manage": "佈局管理", + "settings": "佈局設定", + "color": "顏色", + "main": "主體", + "right": "右側", + "select": "選擇目標佈局" + }, + "legend": { + "position": "圖例位置", + "show-max": "顯示最大值", + "show-min": "顯示最小值", + "show-avg": "顯示平均值", + "show-total": "顯示總數", + "settings": "圖例設定", + "min": "最小值", + "max": "最大值", + "avg": "平均值", + "total": "總數" + }, + "login": { + "login": "登入", + "request-password-reset": "請求密碼重置", + "reset-password": "重置密碼", + "create-password": "建立密碼", + "two-factor-authentication": "雙因素身份驗證", + "passwords-mismatch-error": "輸入的密碼必須相同!", + "password-again": "再次輸入密碼", + "sign-in": "登入 ", + "username": "用戶名(電子郵件)", + "remember-me": "記住我", + "forgot-password": "忘記密碼?", + "password-reset": "密碼重置", + "expired-password-reset-message": "您的憑據已過期!請建立新密碼。", + "new-password": "新密碼", + "new-password-again": "再次輸入新密碼", + "password-link-sent-message": "密碼重置連結已成功發送!", + "email": "電子郵件", + "login-with": "使用{{name}}登入", + "or": "或", + "error": "登入錯誤", + "verify-your-identity": "驗證您的身份", + "select-way-to-verify": "選擇驗證方式", + "resend-code": "重發碼", + "resend-code-wait": "以 { time, plural, 1 {1 秒} other {# 秒} }重新發送程式碼", + "try-another-way": "嘗試別的方式", + "totp-auth-description": "請輸入安全驗證碼從您的驗證應用程式", + "totp-auth-placeholder": "程式碼", + "sms-auth-description": "安全代碼已發送至您的手機{{contact}}。", + "sms-auth-placeholder": "SMS程式碼", + "email-auth-description": "安全代碼已發送到您位於{{contact}}的電子郵件地址。", + "email-auth-placeholder": "電子郵件代碼", + "backup-code-auth-description": "請輸入您的備用代碼之一。", + "backup-code-auth-placeholder": "備用代碼" + }, + "markdown": { + "edit": "編輯", + "preview": "預覽", + "copy-code": "點擊複製", + "copied": "複製!" + }, + "ota-update": { + "add": "增加套件", + "assign-firmware": "指定韌體", + "assign-firmware-required": "指定韌體必填", + "assign-software": "指定軟體", + "assign-software-required": "指定軟體必填", + "auto-generate-checksum": "自動生成核對", + "checksum": "核對", + "checksum-hint": "如果核對為空,將自動生成", + "checksum-algorithm": "核對演算法", + "checksum-copied-message": "套件核對已複製到剪貼板", + "change-firmware": "韌體的更改可能會導致{ count, plural, 1 {1 設備} other {# 設備} }的更新。", + "change-software": "軟體的更改可能會導致{ count, plural, 1 {1 設備} other {# 設備} }的更新。", + "chose-compatible-device-profile": "上傳套件只有在所選擇的設備配置檔案獲得", + "chose-firmware-distributed-device": "選擇將分發到設備的韌體", + "chose-software-distributed-device": "選擇將分發到設備的軟體", + "content-type": "內容類型", + "copy-checksum": "複製校驗碼", + "copy-direct-url": "複製直接URL", + "copyId": "複製套件Id", + "copied": "複製!", + "delete": "刪除套件", + "delete-ota-update-text": "小心,確認後OTA更新將無法恢復。", + "delete-ota-update-title": "您確定要刪除OTA更新 '{{title}}'嗎?", + "delete-ota-updates-text": "小心,確認後,所有選擇的OTA更新都將被刪除。", + "delete-ota-updates-title": "您確定要刪除{ count, plural, 1 {1 OTA更新} other {# OTA更新} }嗎?", + "description": "描述", + "direct-url": "直接URL", + "direct-url-copied-message": "軟體包直接URL已複製到剪貼板", + "direct-url-required": "需要直接URL", + "download": "下載套件", + "drop-file": "拖放軟體包文件或單擊以選擇要上傳的文件。", + "drop-package-file-or": "拖放軟體包文件或", + "file-name": "文件名稱", + "file-size": "文件大小", + "file-size-bytes": "文件大小(位元組)", + "idCopiedMessage": "軟體包ID已複製到剪貼板", + "no-firmware-matching": "未找到與'{{entity}}' 匹配的兼容韌體OTA更新軟體包", + "no-firmware-text": "未提供兼容的韌體OTA更新軟體包。", + "no-packages-text": "未找到套件", + "no-software-matching": "未找到與 '{{entity}}' 匹配的兼容軟體OTA更新軟體包。", + "no-software-text": "未提供兼容的軟體OTA更新軟體包。", + "ota-update": "OTA更新", + "ota-update-details": "OTA更新詳情", + "ota-updates": "OTA更新", + "package-type": "套件類型", + "packages-repository": "軟體包存儲庫", + "search": "搜尋套件", + "selected-package": "{ count, plural, 1 {1 套件} other {# 套件} } 被選中", + "title": "標題", + "title-required": "需要標題。", + "title-max-length": "標題應小於256", + "types": { + "firmware": "韌體", + "software": "軟體" + }, + "upload-binary-file": "上傳二進制文件", + "use-external-url": "使用外部URL", + "version": "版本", + "version-required": "需要版本。", + "version-tag": "版本標記", + "version-tag-hint": "自定義標記應與您設備報告的軟體包版本匹配。", + "version-max-length": "版本應小於256", + "warning-after-save-no-edit": "上傳軟體包後,您將無法修改標題、版本、設備配置文件和軟體包類型。" + }, + "position": { + "top": "頂部", + "bottom": "底部", + "left": "左側", + "right": "右側" + }, + "profile": { + "profile": "屬性", + "change-password": "更改密碼", + "current-password": "當前密碼", + "copy-jwt-token": "複製JWT token", + "jwt-token": "JWT token", + "token-valid-till": "Token有效期至", + "tokenCopiedSuccessMessage": "JWT token已複製到剪貼板", + "tokenCopiedWarnMessage": "JWT token已過期,請刷新頁面。" + }, + "security": { + "security": "安全性", + "2fa": { + "2fa": "雙因素身份驗證", + "2fa-description": "雙因素身份驗證可保護您的帳戶免受未經授權的訪問。您只需在登入時輸入安全碼。", + "authenticate-with": "您可以通過以下方式進行身份驗證:", + "disable-2fa-provider-text": "禁用{{name}}將會降低您的帳戶安全性", + "disable-2fa-provider-title": "您確定要禁用{{name}}嗎?", + "get-new-code": "獲取新程式碼", + "main-2fa-method": "用作主要的雙因素身份驗證方法", + "dialog": { + "activation-step-description-email": "下次登入時,系統會提示您輸入將發送到您的電子郵件地址的安全代碼。", + "activation-step-description-sms": "下次登入時,系統會提示您輸入將發送到電話號碼的安全碼。", + "activation-step-description-totp": "下次登入時,您將需要提供一個雙因素身份驗證代碼。", + "activation-step-label": "啟動", + "backup-code-description": "列印出代碼,以便在您需要使用它們登入帳號時方便使用。每個備用代碼可以使用一次。", + "backup-code-warn": "離開此頁面後,這些代碼將無法再次顯示。使用以下選項安全地存儲它們。", + "download-txt": "下載(txt)", + "email-step-description": "輸入電子郵件以用作您的身份驗證器", + "email-step-label": "電子郵件", + "enable-email-title": "啟用電子郵件驗證器", + "enable-sms-title": "啟用SMS驗證器", + "enable-totp-title": "啟用驗證器應用程式", + "enter-verification-code": "在此輸入6位數代碼", + "get-backup-code-title": "獲取備用代碼", + "next": "下一個", + "scan-qr-code": "使用您的驗證應用程式掃描此QR code", + "send-code": "發送代碼", + "sms-step-description": "輸入一個電話號碼以用作您的身份驗證器", + "sms-step-label": "電話號碼", + "success": "成功!", + "totp-step-description-install": "您可以安裝Google Authenticator、Authy或Duo等應用程式。", + "totp-step-description-open": "在您的手機上打開身份驗證器應用程式", + "totp-step-label": "取得應用程式", + "verification-code": "6位數代碼", + "verification-code-invalid": "驗證碼格式無效", + "verification-code-incorrect": "驗證碼不正確", + "verification-code-many-request": "檢查驗證碼的請求過多", + "verification-step-description": "輸入我們剛剛發送到{{address}}的6位數代碼", + "verification-step-label": "驗證" + }, + "provider": { + "email": "電子郵件", + "email-description": "使用發送到您電子郵件地址的安全代碼進行身份驗證。", + "email-hint": "驗證碼通過電子郵件發送到{{ info }}", + "sms": "SMS", + "sms-description": "使用您的手機進行身份驗證。當您登入時,我們會透過SMS訊息向您發送一個安全碼。", + "sms-hint": "驗證碼通過簡訊發送到{{ info }}", + "totp": "身份驗證器應用程式", + "totp-description": "在您的手機上使用Google Authenticator、Authy或Duo等應用程式進行身份驗證。它將生成用於登入的安全代碼。", + "totp-hint": "已為您的帳戶設定身份驗證器應用程式", + "backup_code": "備用代碼", + "backup-code-description": "這些可列印的一次性密碼可讓您在離開手機時(例如在旅行時)登入。", + "backup-code-hint": "{{ info }}一次性代碼目前處於活動狀態" + } + }, + "password-requirement": { + "at-least": "至少:", + "character": "{ count, plural, 1 {1 字元} other {# 字元} }", + "digit": "{ count, plural, 1 {1 數字} other {# 數字} }", + "incorrect-password-try-again": "密碼不正確。再試一次", + "lowercase-letter": "{ count, plural, 1 {1 小寫字母} other {# 小寫字母} }", + "new-passwords-not-match": "新密碼不匹配", + "password-should-not-contain-spaces": "您的密碼不應包含空格", + "password-not-meet-requirements": "密碼不符合要求", + "password-requirements": "密碼要求", + "password-should-difference": "新密碼應與當前密碼不同", + "special-character": "{ count, plural, 1 {1 特殊字元} other {# 特殊字元} }", + "uppercase-letter": "{ count, plural, 1 {1 大寫字母} other {# 大寫字母} }" + } + }, + "relation": { + "relations": "關聯", + "direction": "方向", + "search-direction": { + "FROM": "從", + "TO": "到" + }, + "direction-type": { + "FROM": "從", + "TO": "到" + }, + "from-relations": "向外的關聯", + "to-relations": "向內的關聯", + "selected-relations": "{ count, plural, 1 {1 關聯} other {# 關聯} } 被選中", + "type": "類型", + "to-entity-type": "到實體類型", + "to-entity-name": "到實體名稱", + "from-entity-type": "從實體類型", + "from-entity-name": "從實體類型", + "to-entity": "到實體", + "from-entity": "從實體", + "delete": "刪除關聯", + "relation-type": "關聯類型", + "relation-type-required": "關聯類型必填", + "relation-type-max-length": "關聯類型應小於256", + "any-relation-type": "任意類型", + "add": "增加關聯", + "edit": "編輯關聯", + "delete-to-relation-title": "確定要刪除實體 '{{entityName}}' 的關聯嗎?", + "delete-to-relation-text": "確定刪除後實體 '{{entityName}}' 將取消與當前實體的關聯關係。", + "delete-to-relations-title": "確定要刪除 { count, plural, 1 {1 關聯} other {# 關聯} }?", + "delete-to-relations-text": "確定刪除所有選擇的關聯關係後,與當前實體對應的所有關聯關係將被移除。", + "delete-from-relation-title": "確定要從實體 '{{entityName}}' 刪除關聯嗎?", + "delete-from-relation-text": "確定刪除後,當前實體將與實體 '{{entityName}}' 取消關聯", + "delete-from-relations-title": "確定刪除 { count, plural, 1 {1 關聯} other {# 關聯} } 嗎?", + "delete-from-relations-text": "確定刪除所有選擇的關聯關係後,當前實體將與對應的實體取消關聯", + "remove-relation-filter": "移除關聯過濾器", + "add-relation-filter": "增加關聯過濾器", + "any-relation": "任意關聯", + "relation-filters": "關聯過濾器", + "additional-info": "附加訊息 (JSON)", + "invalid-additional-info": "無法解析附加訊息json。", + "no-relations-text": "未找到關聯" + }, + "resource": { + "add": "增加資源", + "copyId": "複製資源ID", + "delete": "刪除資源", + "delete-resource-text": "小心,確認後資源將無法恢復。", + "delete-resource-title": "您確定要刪除資源'{{resourceTitle}}'嗎?", + "delete-resources-action-title": "刪除 { count, plural, 1 {1 資源} other {# 資源} }", + "delete-resources-text": "請注意,所選資源,即使用於設備協議,也將被刪除。", + "delete-resources-title": "您確定要刪除 { count, plural, 1 {1 資源} other {# 資源} }嗎?", + "download": "下載資源", + "drop-file": "拖放資源文件或單擊以選擇要上傳的文件。", + "drop-resource-file-or": "拖放資源文件或", + "empty": "資源為空", + "file-name": "文件名", + "idCopiedMessage": "資源ID已複製到剪貼板", + "no-resource-matching": "找不到與 '{{widgetsBundle}}'匹配的資源。", + "no-resource-text": "未找到資源", + "open-widgets-bundle": "打開部件包", + "resource": "資源", + "resource-library-details": "資源詳細資訊", + "resource-type": "資源類型", + "resources-library": "資源庫", + "search": "搜尋資源", + "selected-resources": "{ count, plural, 1 {1 資源} other {# 資源} } 被選中", + "system": "系統", + "title": "標題", + "title-required": "需要標題。", + "title-max-length": "標題應小於256" + }, + "rulechain": { + "rulechain": "規則鏈", + "rulechains": "規則鏈庫", + "root": "根實體", + "delete": "刪除規則", + "activate": "啟動規則", + "suspend": "暫停規則", + "active": "啟動", + "suspended": "暫停", + "name": "名稱", + "name-required": "名稱必填。", + "description": "描述", + "add": "增加規則", + "set-root": "建立規則鏈根", + "set-root-rulechain-title": "您確定要生成規則鏈'{{RuleChainName}}'根嗎?", + "set-root-rulechain-text": "確認之後,規則鏈將變為根規格鏈,並將處理所有傳入的傳輸消息。", + "delete-rulechain-title": " 確實要刪除規則鏈'{{ruleChainName}}'嗎?", + "delete-rulechain-text": "小心,在確認規則鏈和所有相關資料將變得無法恢復。", + "delete-rulechains-title": "確實要刪除{count, plural, 1 { 1 規則鏈} other {# 規則鏈庫} }嗎?", + "delete-rulechains-action-title": "刪除 { count, plural, 1 {1 規則鏈} other {# 規則鏈庫} }", + "delete-rulechains-text": "小心,確認後,所有選擇的規則鏈將被刪除,所有相關的資料將變得無法恢復。", + "add-rulechain-text": "增加新的規則鏈", + "no-rulechains-text": "規則鏈沒有發現", + "rulechain-details": "規則鏈詳細資訊", + "details": "詳細資訊", + "events": "事件", + "system": "系統", + "import": "匯入規則", + "export": "匯出規則", + "export-failed-error": "無法匯出規則:{{error}}", + "create-new-rulechain": "建立新的規則鏈", + "rulechain-file": "規則鏈文件", + "invalid-rulechain-file-error": "不能匯入規則鏈:無效的規則鏈資料格式。", + "copyId": "複製規則鏈ID", + "idCopiedMessage": "規則ID已經複製到剪貼板", + "select-rulechain": "選擇規則鏈", + "no-rulechains-matching": "沒有發現符合'{{entity}}'的規則鏈。", + "rulechain-required": "規則鏈必填", + "management": "規則集管理", + "debug-mode": "測試模式" + }, + "rulenode": { + "details": "詳細資訊", + "events": "事件", + "search": "搜尋節點", + "open-node-library": "打開節點庫", + "add": "增加規則節點", + "name": "名稱", + "name-required": "名稱必填。", + "name-max-length": "名稱應小於256", + "type": "類型", + "description": "描述", + "delete": "刪除規則節點", + "select-all-objects": "選擇所有節點和連接", + "deselect-all-objects": "取消選擇所有節點和連接", + "delete-selected-objects": "刪除選擇的節點和連接", + "delete-selected": "刪除選擇", + "create-nested-rulechain": "建立嵌套規則鏈", + "select-all": "選擇全部", + "copy-selected": "選擇副本", + "deselect-all": "取消選擇", + "rulenode-details": "規則節點詳細資訊", + "debug-mode": "測試模式", + "configuration": "配置", + "link": "連結", + "link-details": "規則節點連結詳細資訊", + "add-link": "增加連結", + "link-label": "連結標籤", + "link-label-required": "連結標籤必填", + "custom-link-label": "自定義連結標籤", + "custom-link-label-required": "自定義連結標籤必填", + "link-labels": "連結標籤", + "link-labels-required": "需要連結標籤。", + "no-link-labels-found": "找不到連結標籤", + "no-link-label-matching": "沒找到'{{label}}'。", + "create-new-link-label": "建立一個新的!", + "type-filter": "過濾器", + "type-filter-details": "使用配置條件過濾傳入消息", + "type-enrichment": "屬性集", + "type-enrichment-details": "向消息元資料中增加附加訊息", + "type-transformation": "變換", + "type-transformation-details": "更改消息有效載荷和元資料", + "type-action": "動作", + "type-action-details": "執行特別動作", + "type-external": "外部的", + "type-external-details": "與外部系統交互", + "type-rule-chain": "規則鏈", + "type-rule-chain-details": "將傳入消息轉發到指定的規則鏈", + "type-flow": "流動", + "type-flow-details": "組織消息流", + "type-input": "輸入", + "type-input-details": "規則鏈的邏輯輸入,將傳入消息轉發到下一個相關規則節點", + "type-unknown": "未知", + "type-unknown-details": "未解析的規則節點", + "directive-is-not-loaded": "定義的配置指令 '{{directiveName}}' 不可用。", + "ui-resources-load-error": "加載配置UI資源失敗。", + "invalid-target-rulechain": "無法解析目標規則鏈!", + "test-script-function": "測試腳本功能", + "message": "消息", + "message-type": "消息類型", + "select-message-type": "選擇消息類型", + "message-type-required": "消息類型必填", + "metadata": "元資料", + "metadata-required": "元資料項不能為空。", + "output": "輸出", + "test": "測試", + "help": "幫助", + "reset-debug-mode": "重置所有節點中的調試模式" + }, + "timezone": { + "timezone": "時區", + "select-timezone": "選擇時區", + "no-timezones-matching": "找不到匹配的時區'{{timezone}}' ", + "timezone-required": "時區必填", + "browser-time": "瀏覽時間" + }, + "queue": { + "queue-name": "佇列", + "no-queues-found": "找不到佇列", + "no-queues-matching": "未找到與'{{queue}}'匹配的佇列。", + "select-name": "選擇佇列名稱", + "name": "名稱", + "name-required": "佇列名稱必填", + "name-unique": "佇列名稱不是唯一值", + "name-pattern": "佇列名稱包含ASCII字母數字以外的字元'.'、 '_' 和 '-'!", + "queue-required": "需要佇列!", + "topic-required": "佇列主題必填", + "poll-interval-required": "輪詢區隔時間必填", + "poll-interval-min-value": "輪詢區隔時間值不可小於1", + "partitions-required": "分區必填", + "partitions-min-value": "分區值不可小於1", + "pack-processing-timeout-required": "處理超時必填", + "pack-processing-timeout-min-value": "處理超時值不可小於1", + "batch-size-required": "批次檔尺寸必填", + "batch-size-min-value": "批次檔尺寸值不可小於1", + "retries-required": "重試必填", + "retries-min-value": "重試值不可為否", + "failure-percentage-required": "故障百分比必填", + "failure-percentage-min-value": "故障百分比不可小於0", + "failure-percentage-max-value": "故障百分比不可大於100", + "pause-between-retries-required": "重試之間的暫停必填", + "pause-between-retries-min-value": "重試之間的暫停不可小於1", + "max-pause-between-retries-required": "重試之間的暫停最大值必填", + "max-pause-between-retries-min-value": "重試之間的暫停最大值不可小於1", + "submit-strategy-type-required": "提交策略類型必填", + "processing-strategy-type-required": "處理策略類型必填", + "queues": "佇列", + "selected-queues": "{ count, plural, 1 {1 佇列} other {# 佇列} }被選中", + "delete-queue-title": "您確定要刪除佇列'{{queueName}}'嗎?", + "delete-queues-title": "您確定要刪除{ count, plural, 1 {1 佇列} other {# 佇列} }嗎?", + "delete-queue-text": "小心,確認後佇列和所有相關資料將無法恢復。", + "delete-queues-text": "確認後,所有選定的佇列將被刪除且無法訪問。", + "search": "搜尋佇列", + "add": "增加佇列", + "details": "佇列詳細資訊", + "topic": "主題", + "submit-settings": "提交設定", + "submit-strategy": "策略類型 *", + "grouping-parameter": "群組參數", + "processing-settings": "重試處理設定", + "processing-strategy": "處理類型 *", + "retries-settings": "重試設定", + "polling-settings": "輪詢設定", + "batch-processing": "批次設定", + "poll-interval": "輪詢間隔", + "partitions": "分區", + "immediate-processing": "立刻處理", + "consumer-per-partition": "發送輪訊訊息給每位顧客", + "consumer-per-partition-hint": "啓用個別顧客的分區", + "processing-timeout": "處理範圍內,毫秒", + "batch-size": "批量大小", + "retries": "重試次數 (0 – 無限制)", + "failure-percentage": "跳過重試的失敗消息百分比", + "pause-between-retries": "在以下範圍內重試,秒", + "max-pause-between-retries": "在秒內的其他重試", + "delete": "刪除佇列", + "copyId": "複製佇列ID", + "idCopiedMessage": "佇列ID已複製到剪貼板", + "description": "描述", + "description-hint": "此文字將顯示在佇列描述中,而不是所選策略中", + "alt-description": "提交策略:{{submitStrategy}},處理策略:{{processingStrategy}}", + "strategies": { + "sequential-by-originator-label": "按發起人排序", + "sequential-by-originator-hint": "例如,在確認設備A的上一條消息之前,不會提交設備A的新消息", + "sequential-by-tenant-label": "按租戶排序", + "sequential-by-tenant-hint": "例如,在確認租戶A的上一條消息之前,不會提交租戶A的新消息", + "sequential-label": "順序的", + "sequential-hint": "在前一條消息被確認之前不會提交新消息", + "burst-label": "破裂", + "burst-hint": "所有消息都按照它們到達的順序提交到規則鏈", + "batch-label": "批次", + "batch-hint": "在確認前一批之前不會提交新批次", + "skip-all-failures-label": "跳過所有故障", + "skip-all-failures-hint": "忽略所有故障", + "skip-all-failures-and-timeouts-label": "跳過所有故障與超時", + "skip-all-failures-and-timeouts-hint": "忽略所有故障與超時", + "retry-all-label": "全部重試", + "retry-all-hint": "所有加工處理套件重試訊息", + "retry-failed-label": "重試失敗", + "retry-failed-hint": "所有加工處理套件重試失敗訊息", + "retry-timeout-label": "重試超時", + "retry-timeout-hint": "所有加工處理套件重試超時訊息", + "retry-failed-and-timeout-label": "重試失敗與超時", + "retry-failed-and-timeout-hint": "所有加工處理套件重試失敗與超時訊息" + } + }, + "server-error": { + "general": "常規伺服器錯誤", + "authentication": "身份驗證錯誤", + "jwt-token-expired": "JWT token已過期", + "tenant-trial-expired": "租戶試用已過期", + "credentials-expired": "憑據已過期", + "permission-denied": "許可權被拒絕", + "invalid-arguments": "無效參數", + "bad-request-params": "錯誤的請求參數", + "item-not-found": "未找到項目", + "too-many-requests": "請求過多", + "too-many-updates": "更新過多" + }, + "tenant": { + "tenant": "租戶", + "tenants": "租戶", + "management": "租戶管理", + "add": "增加租戶", + "admins": "管理員", + "manage-tenant-admins": "管理租戶管理員", + "delete": "刪除租戶", + "add-tenant-text": "增加新租戶", + "no-tenants-text": "沒有找到租戶", + "tenant-details": "租客詳細資訊", + "title-max-length": "標題應小於256", + "delete-tenant-title": "您確定要刪除租戶'{{tenantTitle}}'嗎?", + "delete-tenant-text": "小心!確認後,租戶和所有相關資料將無法恢復。", + "delete-tenants-title": "您確定要刪除 {count,plural,1 {1 租戶} other {# 租戶} } 嗎?", + "delete-tenants-action-title": "刪除 { count, plural, 1 {1 租戶} other {# 租戶} }", + "delete-tenants-text": "小心!確認後,所有選擇的租戶將被刪除,所有相關資料將無法恢復。", + "title": "標題", + "title-required": "標題必填。", + "description": "描述", + "details": "詳細資訊", + "events": "事件", + "copyId": "複製租戶ID", + "idCopiedMessage": "租戶ID已經複製到剪貼板", + "select-tenant": "選擇租戶", + "no-tenants-matching": "沒有找到符合 '{{entity}}' 的租戶", + "tenant-required": "租戶必填", + "search": "搜尋租戶", + "selected-tenants": "{ count, plural, 1 {1 租戶} other {# 租戶} } 已選中", + "isolated-tb-rule-engine": "在隔離的ThingsBoard Rule規則引擎容器中處理", + "isolated-tb-rule-engine-details": "每個獨立租戶需要單獨的微服務" + }, + "tenant-profile": { + "tenant-profile": "租戶屬性", + "tenant-profiles": "租戶屬性", + "add": "新增租戶屬性", + "edit": "編輯租戶屬性", + "tenant-profile-details": "租戶屬性詳細資料", + "no-tenant-profiles-text": "找不到租戶屬性", + "name-max-length": "租戶屬性名稱應小於256", + "search": "搜尋租戶屬性", + "selected-tenant-profiles": "{ count, plural, 1 {1 租戶屬性} other {# 租戶屬性} } 被選中", + "no-tenant-profiles-matching": "找不到與'{{entity}}'匹配的租戶屬性 ", + "tenant-profile-required": "租戶屬性為必填", + "idCopiedMessage": "租戶屬性Id已複製到剪貼板", + "set-default": "將租戶屬性設為預設值", + "delete": "刪除租戶屬性", + "copyId": "複製租戶屬性Id", + "name": "姓名", + "name-required": "姓名為必填", + "data": "屬性資料", + "profile-configuration": "屬性配置", + "description": "描述", + "default": "預設", + "delete-tenant-profile-title": "是否確定要刪除租戶屬性 '{{tenantProfileName}}'?", + "delete-tenant-profile-text": "小心,確認後租戶屬性及所有相關資料將變得無法恢復。", + "delete-tenant-profiles-title": "您確定要刪除 { count, plural, 1 {1 租戶屬性} other {# 租戶屬性} }嗎?", + "delete-tenant-profiles-text": "小心,確認後所有選定的租戶屬性將被刪除,所有相關資料將變得無法恢復。", + "set-default-tenant-profile-title": "是否確定要將租戶屬性'{{tenantProfileName}}' 設為預設值?", + "set-default-tenant-profile-text": "確認後,租戶屬性將被標記為預設值,並將用於未指定屬性的新租戶。", + "no-tenant-profiles-found": "未找到租戶屬性", + "create-new-tenant-profile": "創造一個新的!", + "create-tenant-profile": "創造新的租戶屬性", + "import": "匯入租戶屬性", + "export": "匯出租戶屬性", + "export-failed-error": "無法匯出租戶屬性: {{error}}", + "tenant-profile-file": "租戶屬性文件", + "invalid-tenant-profile-file-error": "無法匯入租戶屬性:無效的租戶屬性資料結構。", + "advanced-settings": "進階設定", + "entities": "實體", + "rule-engine": "規則引擎", + "time-to-live": "生存時間", + "alarms-and-notifications": "警告和通知", + "ota-files-in-bytes": "OTA文件(位元組)", + "ws-title": "WS", + "unlimited": "(0 - 無限制)", + "maximum-devices": "設備最大數量", + "maximum-devices-required": "設備最大數量必填", + "maximum-devices-range": "設備最大數量不可為否", + "maximum-assets": "資產最大數量", + "maximum-assets-required": "資產最大數量必填", + "maximum-assets-range": "資產最大數量不可為否", + "maximum-customers": "顧客最大數量", + "maximum-customers-required": "顧客最大數量必填", + "maximum-customers-range": "顧客最大數量不可為否", + "maximum-users": "用戶最大數量", + "maximum-users-required": "用戶最大數量必填", + "maximum-users-range": "用戶最大數量不可為否", + "maximum-dashboards": "儀表板最大數量", + "maximum-dashboards-required": "儀表板最大數量必填", + "maximum-dashboards-range": "儀表板最大數量不可為否", + "maximum-rule-chains": "規則鏈最大數量", + "maximum-rule-chains-required": "規則鏈最大數量必填", + "maximum-rule-chains-range": "規則鏈最大數量不可為否", + "maximum-resources-sum-data-size": "資源檔尺寸總計", + "maximum-resources-sum-data-size-required": "資源檔尺寸總計必填", + "maximum-resources-sum-data-size-range": "資源檔尺寸總計不可為否", + "maximum-ota-packages-sum-data-size": "OTA套件檔尺寸總計", + "maximum-ota-package-sum-data-size-required": "需要OTA套件檔總和大小。", + "maximum-ota-package-sum-data-size-range": "OTA套件檔尺寸總計不可為否", + "transport-tenant-msg-rate-limit": "傳輸租戶訊息", + "transport-tenant-telemetry-msg-rate-limit": "傳輸租戶遙測訊息", + "transport-tenant-telemetry-data-points-rate-limit": "傳輸租戶遙測資料端", + "transport-device-msg-rate-limit": "傳輸設備訊息", + "transport-device-telemetry-msg-rate-limit": "傳輸設備遙測訊息", + "transport-device-telemetry-data-points-rate-limit": "傳輸設備遙測資料端", + "tenant-entity-export-rate-limit": "實體版本建立", + "tenant-entity-import-rate-limit": "實體版本負載", + "max-transport-messages": "傳輸訊息最大數量", + "max-transport-messages-required": "傳輸訊息最大數量必填", + "max-transport-messages-range": "傳輸訊息最大數量不可為否", + "max-transport-data-points": "傳輸資料端最大數量", + "max-transport-data-points-required": "傳輸資料端最大數量比填", + "max-transport-data-points-range": "傳輸資料端最大數量不可為否", + "max-r-e-executions": "規則引擎執行最大數量", + "max-r-e-executions-required": "規則引擎執行最大數量必填", + "max-r-e-executions-range": "規則引擎執行最大數量不可為否", + "max-j-s-executions": "JavaScript執行最大數量", + "max-j-s-executions-required": "JavaScript執行最大數量必填", + "max-j-s-executions-range": "JavaScript執行最大數量不可為否", + "max-d-p-storage-days": "資料端儲存天最大數", + "max-d-p-storage-days-required": "資料端儲存天最大數必填", + "max-d-p-storage-days-range": "資料端儲存天最大數不可為否", + "default-storage-ttl-days": "預設資料端儲存天總計", + "default-storage-ttl-days-required": "預設資料端儲存天總計必填", + "default-storage-ttl-days-range": "預設資料端儲存天總計不可為否", + "alarms-ttl-days": "警告天總計", + "alarms-ttl-days-required": "警告天總計必填", + "alarms-ttl-days-days-range": "警告天總計不可為否", + "rpc-ttl-days": "RPC TTL天數", + "rpc-ttl-days-required": "需要RPC TTL天數", + "rpc-ttl-days-days-range": "RPC TTL天數不能為負數", + "max-rule-node-executions-per-message": "每一訊息執行的規則節點最大數", + "max-rule-node-executions-per-message-required": "每一訊息執行的規則節點最大數必填", + "max-rule-node-executions-per-message-range": "每一訊息執行的規則節點最大數不可為否", + "max-emails": "已寄發Email最大數", + "max-emails-required": "已寄發Email最大數必填", + "max-emails-range": "已寄發Email最大數必填不可為否", + "max-sms": "已寄發SMS最大數", + "max-sms-required": "已寄發SMS最大數必填", + "max-sms-range": "已寄發SMS最大數不可為否", + "max-created-alarms": "已建立警告最大數", + "max-created-alarms-required": "已建立警告最大數必填", + "max-created-alarms-range": "已建立警告最大數不可為否", + "no-queue": "無佇列配置", + "add-queue": "新增佇列", + "queues-with-count": "佇列 ({{count}})", + "tenant-rest-limits": "剩餘租戶請求", + "customer-rest-limits": "剩餘顧客請求", + "incorrect-pattern-for-rate-limits": "格式是逗號分隔的容量和週期(以秒為單位),中間有一個冒號,列如100:1,2000:60", + "too-small-value-zero": "該值必須大於0", + "too-small-value-one": "該值必須大於1", + "cassandra-tenant-limits-configuration": "租戶的Cassandra查詢", + "ws-limit-max-sessions-per-tenant": "每個租戶的最大對談數", + "ws-limit-max-sessions-per-customer": "每個客戶的最大對談數", + "ws-limit-max-sessions-per-regular-user": "每個普通用戶的最大對話數", + "ws-limit-max-sessions-per-public-user": "每個公共用戶的最大對談數", + "ws-limit-queue-per-session": "每個對談的消息佇列最大大小", + "ws-limit-max-subscriptions-per-tenant": "每個租戶的最大訂閱數", + "ws-limit-max-subscriptions-per-customer": "每個客戶的最大訂閱數", + "ws-limit-max-subscriptions-per-regular-user": "每個普通用戶的最大訂閱數", + "ws-limit-max-subscriptions-per-public-user": "每個公共用戶的最大訂閱數", + "ws-limit-updates-per-session": "每個對談的WS更新", + "rate-limits": { + "add-limit": "增加限制", + "advanced-settings": "進階設定", + "edit-limit": "編輯限制", + "but-less-than": "但小於", + "edit-transport-tenant-msg-title": "編輯傳輸租戶訊息速率限制", + "edit-transport-tenant-telemetry-msg-title": "編輯傳輸租戶遙測訊息速率限制", + "edit-transport-tenant-telemetry-data-points-title": "編輯傳輸租戶遙測資料端速率限制", + "edit-transport-device-msg-title": "編輯傳輸設備訊息速率限制", + "edit-transport-device-telemetry-msg-title": "編輯傳輸設備遙測訊息速率限制", + "edit-transport-device-telemetry-data-points-title": "編輯傳輸設備遙測資料端速率限制", + "edit-transport-tenant-msg-rate-limit-title": "編輯傳輸租戶訊息速率限制", + "edit-customer-rest-limits-title": "編輯剩餘顧客速率限制", + "edit-ws-limit-updates-per-session-title": "編輯每個對談的 WS更新速率限制", + "edit-cassandra-tenant-limits-configuration-title": "編輯租戶速率限制的 Cassandra 查詢", + "edit-tenant-entity-export-rate-limit-title": "編輯實體版本創建速率限制", + "edit-tenant-entity-import-rate-limit-title": "編輯實體版本加載速率限制", + "messages-per": "每條消息", + "not-set": "未設定", + "number-of-messages": "消息數", + "number-of-messages-required": "需要消息數。", + "number-of-messages-min": "最小值為1。", + "preview": "預覽", + "per-seconds": "每秒", + "per-seconds-required": "需要時間速率。", + "per-seconds-min": "最小值為1。", + "rate-limits": "速率限制", + "remove-limit": "移除限制", + "transport-tenant-msg": "傳輸租戶消息", + "transport-tenant-telemetry-msg": "傳輸租戶遙測消息", + "transport-tenant-telemetry-data-points": "傳輸租戶遙測資料點", + "transport-device-msg": "傳輸設備消息", + "transport-device-telemetry-msg": "傳輸設備遙測消息", + "transport-device-telemetry-data-points": "傳輸設備遙測資料點", + "sec": "秒" + } + }, + "timeinterval": { + "seconds-interval": "{ seconds, plural, 1 {1 秒} other {# 秒} }", + "minutes-interval": "{ minutes, plural, 1 {1 分} other {# 分} }", + "hours-interval": "{ hours, plural, 1 {1 小時} other {# 小時} }", + "days-interval": "{ days, plural, 1 {1 天} other {# 天} }", + "days": "天", + "hours": "時", + "minutes": "分", + "seconds": "秒", + "advanced": "高級", + "predefined": { + "yesterday": "昨天", + "day-before-yesterday": "前天", + "this-day-last-week": "上週的這一天", + "previous-week": "前一週 (週日 - 週六)", + "previous-week-iso": "前一週 (週一 - 週日)", + "previous-month": "前一個月", + "previous-year": "上一年", + "current-hour": "當前時間", + "current-day": "當前日期", + "current-day-so-far": "當天到目前為止", + "current-week": "本週 (週日 - 週六)", + "current-week-iso": "本週 (週一 - 週日)", + "current-week-so-far": "本週到目前為止 (週日 - 週六)", + "current-week-iso-so-far": "本週到目前為止 (週一 - 週日)", + "current-month": "這個月", + "current-month-so-far": "本月至今", + "current-year": "今年", + "current-year-so-far": "本年度至今" + } + }, + "timeunit": { + "milliseconds": "毫秒", + "seconds": "秒", + "minutes": "分", + "hours": "時", + "days": "天" + }, + "timewindow": { + "days": "{ days, plural, 1 { 天 } other {# 天 } }", + "hours": "{ hours, plural, 0 { 小時 } 1 {1 小時 } other {# 小時 } }", + "minutes": "{ minutes, plural, 0 { 分 } 1 {1 分 } other {# 分 } }", + "seconds": "{ seconds, plural, 0 { 秒 } 1 {1 秒 } other {# 秒 } }", + "realtime": "實時", + "history": "歷史", + "last-prefix": "最後", + "period": "從 {{ startTime }} 到 {{ endTime }}", + "edit": "編輯時間窗口", + "date-range": "日期範圍", + "last": "最後", + "time-period": "時間段", + "hide": "隱藏", + "interval": "間隔" + }, + "user": { + "user": "用戶", + "users": "用戶", + "customer-users": "客戶用戶", + "tenant-admins": "租戶管理員", + "sys-admin": "系統管理員", + "tenant-admin": "租戶管理員", + "customer": "客戶", + "anonymous": "匿名", + "add": "增加用戶", + "delete": "刪除用戶", + "add-user-text": "增加新用戶", + "no-users-text": "找不到用戶", + "user-details": "用戶詳細訊息", + "delete-user-title": "您確定要刪除用戶 '{{userEmail}}' 嗎?", + "delete-user-text": "小心!確認後,用戶和所有相關資料將無法恢復。", + "delete-users-title": "你確定你要刪除 { count, plural, 1 {1 用戶} other {# 用戶} } 嗎?", + "delete-users-action-title": "刪除 { count, plural, 1 {1 用戶} other {# 用戶} }", + "delete-users-text": "小心!確認後,所有選擇的用戶將被刪除,所有相關資料將無法恢復。", + "activation-email-sent-message": "啟動電子郵件已成功發送!", + "resend-activation": "重新發送啟動", + "email": "電子郵件", + "email-required": "電子郵件必填。", + "invalid-email-format": "無效的郵件格式。", + "first-name": "名字", + "last-name": "姓", + "description": "描述", + "default-dashboard": "預設面板", + "always-fullscreen": "始終全螢幕", + "select-user": "選擇用戶", + "no-users-matching": "沒有找到符合 '{{entity}}' 的用戶。", + "user-required": "用戶必填", + "activation-method": "啟動方式", + "display-activation-link": "顯示啟動連結", + "send-activation-mail": "發送啟動郵件", + "activation-link": "用戶啟動連結", + "activation-link-text": "使用該連結 啟動 啟動用戶:", + "copy-activation-link": "複製用戶啟動連結", + "activation-link-copied-message": "用戶啟動連結已經複製到剪貼板", + "details": "詳細訊息", + "login-as-tenant-admin": "以租戶管理者帳號登入", + "login-as-customer-user": "以顧客用戶帳號登入", + "search": "搜尋用戶", + "selected-users": "{ count, plural, 1 {1 用戶} other {# 用戶} } 被選中", + "disable-account": "關閉用戶帳號", + "enable-account": "啓用用戶帳號", + "enable-account-message": "用戶帳號已成功啓用", + "disable-account-message": "用戶帳號已成功關閉", + "copyId": "複製用戶Id", + "idCopiedMessage": "用戶Id已複製到剪貼板" + }, + "value": { + "type": "值類型", + "string": "字符串", + "string-value": "字符串值", + "string-value-required": "需要字符串值", + "integer": "數字", + "integer-value": "數字值", + "integer-value-required": "需要整數值", + "invalid-integer-value": "整數值無效", + "double": "雙精度浮點數", + "double-value": "雙精度浮點數值", + "double-value-required": "需要雙值", + "boolean": "布林", + "boolean-value": "布林值", + "false": "假", + "true": "真", + "long": "長", + "json": "JSON", + "json-value": "JSON值", + "json-value-invalid": "JSON值的格式無效", + "json-value-required": "需要JSON值。" + }, + "version-control": { + "version-control": "版本控制", + "management": "版本控制管理", + "search": "搜尋版本", + "branch": "分支", + "default": "預設", + "select-branch": "選取分支", + "branch-required": "需要分支", + "create-entity-version": "創建實體版本", + "version-name": "版本名稱", + "version-name-required": "需要版本名稱", + "author": "作者", + "export-relations": "匯出關聯", + "export-attributes": "匯出屬性", + "export-credentials": "匯出憑據", + "entity-versions": "實體版本", + "versions": "本版", + "created-time": "創建時間", + "version-id": "版本ID", + "no-entity-versions-text": "未找到實體版本", + "no-versions-text": "未找到版本", + "copy-full-version-id": "複製完整版本ID", + "create-version": "建立版本", + "creating-version": "正在創建版本... 請稍候t", + "nothing-to-commit": "沒有要提交的更改", + "restore-version": "恢復版本", + "restore-entity-from-version": "從版本'{{versionName}}'恢復實體", + "restoring-entity-version": "正在恢復實體版本... 請稍候", + "load-relations": "負載關聯", + "load-attributes": "加載屬性", + "load-credentials": "加載憑據", + "compare-with-current": "與當前比較", + "diff-entity-with-version": "與實體版本'{{versionName}}'的差異", + "previous-difference": "上一個差異", + "next-difference": "下一個差異", + "current": "當前的", + "differences": "{ count, plural, 1 {1 差異} other {# 差異} }", + "create-entities-version": "創建實體版本", + "default-sync-strategy": "預設同步策略", + "sync-strategy-merge": "合併", + "sync-strategy-overwrite": "覆蓋", + "entities-to-export": "要匯出的實體", + "entities-to-restore": "要恢復的實體", + "sync-strategy": "同步策略", + "all-entities": "所有實體", + "no-entities-to-export-prompt": "請指定要匯出的實體", + "no-entities-to-restore-prompt": "請指定要恢復的實體", + "add-entity-type": "增加實體類型", + "remove-all": "移除全部", + "version-create-result": "{ added, plural, 0 {無實體} 1 {1 實體} other {# 實體} } 已增加。.
              { modified, plural, 0 {無實體} 1 {1 實體} other {# 實體} } 已修改。
              { removed, plural, 0 {無實體} 1 {1 實體} other {# 實體} } 已移除。", + "remove-other-entities": "移除其他實體", + "find-existing-entity-by-name": "按名稱查找現有實體", + "restore-entities-from-version": "從版本'{{versionName}}恢復實體'", + "restoring-entities-from-version": "正在恢復實體... 請稍候", + "no-entities-restored": "沒有恢復實體", + "created": "{{created}}已創建", + "updated": "{{updated}}已更新", + "deleted": "{{deleted}} 已刪除", + "remove-other-entities-confirm-text": "小心!這將永久刪除您要恢復的版本中不存在的所有當前實體。請鍵入刪除其他實體進行確認。", + "auto-commit-to-branch": "自動提交到{{ branch }}分支", + "default-create-entity-version-name": "{{entityName}} 更新", + "sync-strategy-merge-hint": "在存儲庫中創建或更新選定實體。所有其他存儲實體都不會被修改。", + "sync-strategy-overwrite-hint": "在存儲庫中創建或更新選定的實體。所有其他存儲庫實體都將被刪除。", + "device-credentials-conflict": "無法加載具有外部ID{{entityId}}的設備。
              因為資料庫中已存在另一台設備的相同憑據。 請考慮在恢復表單中禁用加載憑據設置。", + "missing-referenced-entity": "無法加載具有外部ID{{sourceEntityId}}的{{sourceEntityTypeName}},因為它引用了缺少的ID為{{targetEntityId}}的{{targetEntityTypeName}}。", + "runtime-failed": "失敗: {{message}}" + }, + "widget": { + "widget-library": "部件庫", + "widget-bundle": "部件包", + "all-bundles": "所有包", + "select-widgets-bundle": "選擇部件包", + "management": "管理部件", + "editor": "部件編輯器", + "widget-type-not-found": "加載部件配置出錯。
              可能關聯的\n 部件已經刪除了。", + "widget-type-load-error": "由於以下錯誤未加載小部件:", + "remove": "刪除部件", + "edit": "編輯部件", + "remove-widget-title": "確實要刪除 '{{widgetTitle}}'部件嗎?", + "remove-widget-text": "確認後,控件和所有相關資料將變得無法恢復。", + "timeseries": "時間序列", + "search-data": "搜尋資料", + "no-data-found": "沒有找到資料", + "latest": "最新值", + "rpc": "控件部件", + "alarm": "警告部件", + "static": "靜態部件", + "select-widget-type": "選擇窗口部件類型", + "missing-widget-title-error": "部件標題必須指定!", + "widget-saved": "部件已儲存", + "unable-to-save-widget-error": "無法儲存部件!控件有錯誤!", + "save": "儲存部件", + "saveAs": "部件另存為", + "save-widget-type-as": "部件類型另存為", + "save-widget-type-as-text": "請輸入新的部件標題或選擇目標部件包", + "toggle-fullscreen": "切換全螢幕", + "run": "執行部件", + "title": "部件標題", + "title-required": "需要部件標題。", + "type": "部件類型", + "resources": "資源", + "resource-url": "JavaScript/CSS URL", + "resource-is-module": "是模組", + "remove-resource": "刪除資源", + "add-resource": "增加資源", + "html": "HTML", + "tidy": "整理", + "css": "CSS", + "settings-schema": "設定模式", + "datakey-settings-schema": "資料鍵設定模式", + "latest-datakey-settings-schema": "最新資料鍵設置架構", + "widget-settings": "部件設定", + "description": "描述", + "image-preview": "圖像預覽", + "settings-form-selector": "設置表單選擇器", + "data-key-settings-form-selector": "資料鍵設置表單選擇器", + "latest-data-key-settings-form-selector": "最新資料鍵設置表單選擇器", + "javascript": "Javascript", + "js": "JS", + "remove-widget-type-title": "您確定要刪除部件類型 '{{widgetName}}'嗎?", + "remove-widget-type-text": "確認後,窗口部件類型和所有相關資料將無法恢復。", + "remove-widget-type": "刪除部件類型", + "add-widget-type": "增加新的部件類型", + "widget-type-load-failed-error": "無法加載部件類型!", + "widget-template-load-failed-error": "無法加載部件模板!", + "add": "增加部件", + "undo": "復原部件更改", + "export": "匯出部件", + "no-data": "部件上沒有要顯示的資料", + "data-overflow": "小部件顯示{{count}}個,共{{total}}個實體", + "alarm-data-overflow": "工具顯示{{totalEntities}}個實體中的{{allowedEntities}} (最大允許)個實體的警告", + "search": "搜尋部件", + "filter": "部件過濾器類型", + "loading-widgets": "加載部件..." + }, "widget-action": { - "action-cell-button": "動作單元格按鈕", - "row-click": "點選行", - "marker-click": "點選標記", - "polygon-click": "單擊多邊形", - "tooltip-tag-action": "提示標籤動作" + "header-button": "部件頂部按鈕", + "open-dashboard-state": "切換到新儀表板狀態", + "update-dashboard-state": "更新當前儀表板狀態", + "open-dashboard": "切換到另一個儀表板", + "custom": "自定義動作", + "custom-pretty": "自定義操作 (使用HTML模板)", + "mobile-action": "移動操作", + "target-dashboard-state": "目標儀表板狀態", + "target-dashboard-state-required": "目標儀表板狀態必填", + "set-entity-from-widget": "從部件中設定實體", + "target-dashboard": "目標儀表板", + "open-right-layout": "打開右側佈局 (移動端視圖)", + "state-display-type": "儀表板狀態顯示選項", + "open-normal": "切換正常", + "open-in-separate-dialog": "在分別的對話切換", + "open-in-popover": "彈出提示框", + "dialog-title": "對話標題", + "dialog-hide-dashboard-toolbar": "在對話工具欄中隱藏儀表板", + "dialog-width": "對話框寬度相對於視口寬度的百分比", + "dialog-height": "對話框高度相對於視口高度的百分比", + "dialog-size-range-error": "對話框大小百分比值應在1到100的範圍內。", + "popover-preferred-placement": "彈出提示框配置偏好", + "popover-placement-top": "頂部", + "popover-placement-topLeft": "頂部左側", + "popover-placement-topRight": "頂部右側", + "popover-placement-right": "右側", + "popover-placement-rightTop": "右側頂部", + "popover-placement-rightBottom": "右側底部", + "popover-placement-bottom": "底部", + "popover-placement-bottomLeft": "底部左側", + "popover-placement-bottomRight": "底部右側", + "popover-placement-left": "左側", + "popover-placement-leftTop": "左側頂部", + "popover-placement-leftBottom": "左側底部", + "popover-hide-on-click-outside": "在外部單擊時隱藏彈出視窗", + "popover-hide-dashboard-toolbar": "在彈出提示框中隱藏對話工具欄", + "popover-width": "瀏覽器單元中的彈出框寬度(例如100px、25vw)", + "popover-height": "瀏覽器單元中的彈出框高度 (例如100px、25vh)", + "popover-style": "彈出提示框形式", + "open-new-browser-tab": "在新的瀏覽器選項中打開", + "mobile": { + "action-type": "手機動作類型", + "action-type-required": "手機動作類型必填", + "take-picture-from-gallery": "由圖庫中擷取圖片", + "take-photo": "擷取圖片", + "map-direction": "開啓地圖指引", + "map-location": "開啓地圖位置", + "scan-qr-code": "掃描QR Code", + "make-phone-call": "打電話", + "get-location": "取得電話位置", + "take-screenshot": "擷取螢幕畫面" + } + }, + "widgets-bundle": { + "current": "當前包", + "widgets-bundles": "部件包", + "add": "增加部件包", + "delete": "刪除部件包", + "title": "標題", + "title-required": "標題必填。", + "title-max-length": "標題應小於256", + "description": "描述", + "image-preview": "圖像預覽", + "add-widgets-bundle-text": "增加新的部件包", + "no-widgets-bundles-text": "找不到部件包", + "empty": "部件包是空的", + "details": "詳細資訊", + "widgets-bundle-details": "部件包詳細訊息", + "delete-widgets-bundle-title": "您確定要刪除部件包 '{{widgetsBundleTitle}}'嗎?", + "delete-widgets-bundle-text": "小心!確認後,部件包和所有相關資料將無法恢復。", + "delete-widgets-bundles-title": "你確定你要刪除 { count, plural, 1 {1 部件包} other {# 部件包} } 嗎?", + "delete-widgets-bundles-action-title": "刪除 { count, plural, 1 {1 部件包} other {# 部件包} }", + "delete-widgets-bundles-text": "小心!確認後,所有選擇的部件包將被刪除,所有相關資料將無法恢復。", + "no-widgets-bundles-matching": "沒有找到與 '{{widgetsBundle}}' 符合的部件包。", + "widgets-bundle-required": "需要部件包。", + "system": "系統", + "import": "匯入部件包", + "export": "匯出部件包", + "export-failed-error": "無法匯出部件包: {{error}}", + "create-new-widgets-bundle": "建立新的部件包", + "widgets-bundle-file": "部件包文件", + "invalid-widgets-bundle-file-error": "無法匯入部件包:無效的部件包資料結構。", + "search": "搜尋部件包", + "selected-widgets-bundles": "{ count, plural, 1 {1 部件包} other {#部件包} } 被選中", + "open-widgets-bundle": "打開部件包", + "loading-widgets-bundles": "加載部件包..." + }, + "widget-config": { + "data": "資料", + "settings": "設定", + "advanced": "高級", + "title": "標題", + "title-tooltip": "標題工具提示", + "general-settings": "一般設定", + "display-title": "顯示標題", + "drop-shadow": "陰影", + "enable-fullscreen": "啟用全螢幕", + "background-color": "背景顏色", + "text-color": "文字顏色", + "padding": "填充", + "margin": "邊緣", + "widget-style": "部件風格", + "widget-css": "部件CSS", + "title-style": "標題風格", + "mobile-mode-settings": "移動端設定", + "order": "順序", + "height": "高度", + "mobile-hide": "在移動模式下隱藏部件", + "units": "特殊符號展示值", + "decimals": "浮點數後的位數", + "timewindow": "時間窗口", + "use-dashboard-timewindow": "使用儀表板的時間窗口", + "display-timewindow": "顯示時間視窗", + "legend": "圖例", + "display-legend": "顯示圖例", + "datasources": "資料源", + "maximum-datasources": "最大允許 { count, plural, 1 {1 資料} other {# 資料} }", + "datasource-type": "類型", + "datasource-parameters": "參數", + "remove-datasource": "移除資料源", + "add-datasource": "增加資料源", + "target-device": "目標設備", + "alarm-source": "警告源", + "actions": "動作", + "action": "動作", + "add-action": "增加動作", + "search-actions": "動作檢索", + "no-actions-text": "未找到動作", + "action-source": "動作源", + "action-source-required": "動作源必填", + "action-name": "動作名稱", + "action-name-required": "動作名稱必填。", + "action-name-not-unique": "動作名稱已經存在。
              統一動作源的動作名稱必須唯一。", + "action-icon": "圖示", + "show-hide-action-using-function": "使用函數顯示/隱藏動作", + "action-type": "類型", + "action-type-required": "類型必填", + "edit-action": "編輯動作", + "delete-action": "刪除動作", + "delete-action-title": "刪除部件動作", + "delete-action-text": "確定要刪除部件動作 '{{actionName}}' 嗎?", + "title-icon": "標題icon", + "display-icon": "顯示標題icon", + "icon-color": "Icon顏色", + "icon-size": "Icon尺寸", + "advanced-settings": "進階設定", + "data-settings": "資料設定", + "no-data-display-message": "\"沒有要顯示的資料\" 替代消息", + "data-page-size": "每個資料來源的最大實體數", + "settings-component-not-found": "未找到選擇器'{{selector}}'的設定表單組件" + }, + "widget-type": { + "import": "匯入部件類型", + "export": "匯出部件類型", + "export-failed-error": "無法匯出部件類型: {{error}}", + "create-new-widget-type": "建立新的部件類型", + "widget-type-file": "部件類型文件", + "invalid-widget-type-file-error": "無法匯入部件類型:無效的部件類型資料結構。" + }, + "widgets": { + "chart": { + "common-settings": "常用設定", + "enable-stacking-mode": "啟用堆疊模式", + "line-shadow-size": "線條陰影大小", + "display-smooth-lines": "顯示平滑(彎曲) 的線條", + "default-bar-width": "非聚合資料的預設條形寬度(毫秒)", + "bar-alignment": "條形對齊", + "bar-alignment-left": "左側", + "bar-alignment-right": "右側", + "bar-alignment-center": "中間", + "default-font-size": "預設字體大小", + "default-font-color": "預設", + "thresholds-line-width": "所有閾值的預設線寬", + "tooltip-settings": "工具提示設定", + "show-tooltip": "顯示工具提示", + "hover-individual-points": "懸停單個點", + "show-cumulative-values": "在堆疊模式下顯示累積值", + "hide-zero-false-values": "從工具提示中隱藏零/錯誤值", + "tooltip-value-format-function": "工具提示值格式函數", + "grid-settings": "網格設定", + "show-vertical-lines": "顯示垂直線", + "show-horizontal-lines": "顯示水平線", + "grid-outline-border-width": "網格輪廓/邊框寬度 (px)", + "primary-color": "主色", + "background-color": "背顔色", + "ticks-color": "刻度顔色", + "xaxis-settings": "X軸設定", + "axis-title": "軸標題", + "xaxis-tick-labels-settings": "X軸刻度標籤設定", + "show-tick-labels": "顯示X軸刻度標籤", + "yaxis-settings": "Y軸設定", + "min-scale-value": "最小刻度值", + "max-scale-value": "最大刻度值", + "yaxis-tick-labels-settings": "Y軸刻度標籤設定", + "tick-step-size": "刻度尺寸", + "number-of-decimals": "顯示小數點", + "ticks-formatter-function": "刻度格式化功能", + "comparison-settings": "比較設定", + "enable-comparison": "啓用比較", + "time-for-comparison": "比較期間", + "time-for-comparison-previous-interval": "上一個間隔 (預設)", + "time-for-comparison-days": "一天前", + "time-for-comparison-weeks": "一週前", + "time-for-comparison-months": "一個月前", + "time-for-comparison-years": "一年前", + "time-for-comparison-custom-interval": "自定義間隔", + "custom-interval-value": "自定義間隔值 (毫秒)", + "comparison-x-axis-settings": "比較X軸設定", + "axis-position": "軸位置", + "axis-position-top": "頂部 (預設)", + "axis-position-bottom": "底部", + "custom-legend-settings": "自定義圖例設定", + "enable-custom-legend": "啟用自定義圖例(這將允許您在鍵標籤中使用屬性/時間序列值)", + "key-name": "鍵名", + "key-name-required": "需要鍵名", + "key-type": "鍵類型", + "key-type-attribute": "屬性", + "key-type-timeseries": "時間序列", + "label-keys-list": "標籤中使用的鍵列表", + "no-label-keys": "未配置鍵", + "add-label-key": "增加新鍵", + "line-width": "線寬", + "color": "顏色", + "data-is-hidden-by-default": "預設資料隱藏", + "disable-data-hiding": "禁用資料隱藏", + "remove-from-legend": "刪除圖例中的物件屬性", + "exclude-from-stacking": "從堆疊中排除(在 \"堆疊\" 模式下可用)", + "line-settings": "線條設定", + "show-line": "顯示線條", + "fill-line": "填充線條", + "points-settings": "點物件設定", + "show-points": "顯示點物件", + "points-line-width": "點物件的線條寬度", + "points-radius": "點物件半徑", + "point-shape": "點物件外形", + "point-shape-circle": "圓形", + "point-shape-cross": "十字架", + "point-shape-diamond": "鑽石形", + "point-shape-square": "正方形", + "point-shape-triangle": "三角形", + "point-shape-custom": "客製功能", + "point-shape-draw-function": "點物件外形繪圖功能", + "show-separate-axis": "顯示獨立軸", + "axis-position-left": "左", + "axis-position-right": "右", + "thresholds": "門檻值", + "no-thresholds": "找不到指定的閥值", + "add-threshold": "新增閥值", + "show-values-for-comparison": "顯示歷史比較值", + "comparison-values-label": "歷史比較值標籤", + "threshold-settings": "閥值設定", + "use-as-threshold": "使用主要值做爲門檻值", + "threshold-line-width": "閥值的線條寬度", + "threshold-color": "閥值顔色", + "common-pie-settings": "通用派圖設定", + "radius": "半徑", + "inner-radius": "内半徑", + "tilt": "傾斜", + "stroke-settings": "筆畫設定", + "width-pixels": "寬度 (pixels)", + "show-labels": "顯示標籤", + "animation-settings": "動畫設定", + "animated-pie": "啓動派圖動畫 (實驗性的)", + "border-settings": "邊框設定", + "border-width": "邊框寬度", + "border-color": "邊框顔色", + "legend-settings": "圖例設定", + "display-legend": "顯示圖例", + "labels-font-color": "標籤文字顔色" + }, + "dashboard-state": { + "dashboard-state-settings": "儀表板狀態設定", + "dashboard-state": "儀表板狀態id", + "autofill-state-layout": "預設自動填入狀態版面高度", + "default-margin": "預設部件邊緣", + "default-background-color": "預設背景顔色", + "sync-parent-state-params": "與父儀表板狀態參數同步" + }, + "date-range-navigator": { + "date-range-picker-settings": "日期範圍選擇器設定", + "hide-date-range-picker": "隱藏日期範圍選擇器", + "picker-one-panel": "日期範圍選擇器一個面板", + "picker-auto-confirm": "日期範圍選擇器自動確認", + "picker-show-template": "日期範圍選擇器顯示模板", + "first-day-of-week": "每週的第一天", + "interval-settings": "區隔時間設定", + "hide-interval": "隱藏區隔時間", + "initial-interval": "初始區隔時間", + "interval-hour": "區隔時間-每小時", + "interval-day": "區隔時間-每天", + "interval-week": "區隔時間-每週", + "interval-two-weeks": "區隔時間-2週", + "interval-month": "區隔時間-每月", + "interval-three-months": "區隔時間-3個月", + "interval-six-months": "區隔時間-6個月", + "step-settings": "步驟設定", + "hide-step-size": "隱藏步驟尺寸", + "initial-step-size": "初始步驟尺寸", + "hide-labels": "隱藏標籤", + "use-session-storage": "使用會談儲存", + "localizationMap": { + "Sun": "週日", + "Mon": "週一", + "Tue": "週二", + "Wed": "週三", + "Thu": "週四", + "Fri": "週五", + "Sat": "週六", + "Jan": "1月", + "Feb": "2月", + "Mar": "3月", + "Apr": "4月", + "May": "5月", + "Jun": "6月", + "Jul": "7月", + "Aug": "8月", + "Sep": "9月", + "Oct": "10月", + "Nov": "11月", + "Dec": "12月", + "January": "一月", + "February": "二月", + "March": "三月", + "April": "四月", + "June": "六月", + "July": "七月", + "August": "八月", + "September": "九月", + "October": "十月", + "November": "十一月", + "December": "十二月", + "Custom Date Range": "自定義日期範圍", + "Date Range Template": "日期範圍模板", + "Today": "今天", + "Yesterday": "昨天", + "This Week": "本星期", + "Last Week": "上個星期", + "This Month": "這個月", + "Last Month": "上個月", + "Year": "年", + "This Year": "今年", + "Last Year": "去年", + "Date picker": "日期選擇器", + "Hour": "小時", + "Day": "天", + "Week": "週", + "2 weeks": "2週", + "Month": "月", + "3 months": "3個月", + "6 months": "6個月", + "Custom interval": "自定義間隔", + "Interval": "間隔", + "Step size": "步長", + "Ok": "Ok" + } + }, + "entities-hierarchy": { + "hierarchy-data-settings": "階層資料設定", + "relations-query-function": "節點關聯查詢功能", + "has-children-function": "節點有子功能", + "node-state-settings": "節點狀態設定", + "node-opened-function": "預設節點開啟功能", + "node-disabled-function": "節點禁用功能", + "display-settings": "顯示設定", + "node-icon-function": "節點圖示功能", + "node-text-function": "節點文字功能", + "sort-settings": "分類設定", + "nodes-sort-function": "節點分類設定" + }, + "edge": { + "display-default-title": "顯示預設標題" + }, + "gateway": { + "general-settings": "通用設定", + "widget-title": "部件標題", + "default-archive-file-name": "預設存檔檔名", + "device-type-for-new-gateway": "新閘道的設備類型", + "messages-settings": "訊息設定", + "save-config-success-message": "指定閘道儲存成功的文字訊息", + "device-name-exists-message": "當輸入已存在的設備名稱的文字訊息", + "gateway-title": "閘道表格", + "read-only": "唯讀", + "events-title": "閘道事件表單標題", + "events-filter": "事件過濾器", + "event-key-contains": "事件鍵包含..." + }, + "gauge": { + "default-color": "預設顏色", + "radial-gauge-settings": "逕向量規設定", + "ticks-settings": "刻度設定", + "min-value": "最小值", + "max-value": "最大值", + "start-ticks-angle": "開始刻度角度", + "ticks-angle": "刻度線角度", + "major-ticks-count": "主要刻度數", + "major-ticks-color": "主要刻度顏色", + "minor-ticks-count": "次要刻度計數", + "minor-ticks-color": "次要刻度顏色", + "tick-numbers-font": "刻度數字字體", + "unit-title-settings": "單元標題設定", + "show-unit-title": "顯示單元標題", + "unit-title": "單元標題", + "title-font": "標題文字字體", + "units-settings": "單位設定", + "units-font": "單位文字字體", + "value-box-settings": "值框設定", + "show-value-box": "顯示值框", + "value-int": "數值整數部分的位數", + "value-font": "值文字字體", + "value-box-rect-stroke-color": "值框矩形筆畫顏色", + "value-box-rect-stroke-color-end": "值框矩形筆畫顏色 - 結束漸變", + "value-box-background-color": "值框背景顏色", + "value-box-shadow-color": "值框陰影顏色", + "plate-settings": "板設定", + "show-plate-border": "顯示板邊框", + "plate-color": "板顏色", + "needle-settings": "針設定", + "needle-circle-size": "針圈尺寸", + "needle-color": "針顏色", + "needle-color-end": "針顏色 - 結束漸變", + "needle-color-shadow-up": "針影顏色的上半部分", + "needle-color-shadow-down": "放置針陰影顏色", + "highlights-settings": "高光設定", + "highlights-width": "高光寬度", + "highlights": "高光", + "highlight-from": "從", + "highlight-to": "至", + "highlight-color": "顏色", + "no-highlights": "未配置高光", + "add-highlight": "增加高光", + "animation-settings": "動畫設定", + "enable-animation": "啟用動畫", + "animation-duration": "動畫持續時間", + "animation-rule": "動畫規則", + "animation-linear": "線性", + "animation-quad": "四邊形", + "animation-quint": "導軌", + "animation-cycle": "循環", + "animation-bounce": "彈跳", + "animation-elastic": "彈性", + "animation-dequad": "對偶", + "animation-dequint": "去導軌", + "animation-decycle": "循環", + "animation-debounce": "去抖動", + "animation-delastic": "彈性", + "linear-gauge-settings": "線性量規設定", + "bar-stroke-width": "條形筆畫寬度", + "bar-stroke-color": "條形筆畫顏色", + "bar-background-color": "量規條背景顏色", + "bar-background-color-end": "條形背景顏色 - 結束漸變", + "progress-bar-color": "進度條顏色", + "progress-bar-color-end": "進度條顏色 - 結束漸變", + "major-ticks-names": "主要刻度名稱", + "show-stroke-ticks": "顯示刻度筆畫", + "major-ticks-font": "主要刻度字體", + "border-color": "邊框顏色", + "border-width": "邊框寬度", + "needle-circle-color": "針圈顏色", + "animation-target": "動畫目標", + "animation-target-needle": "針", + "animation-target-plate": "板", + "common-settings": "常用量規設定", + "gauge-type": "量規類型", + "gauge-type-arc": "弧", + "gauge-type-donut": "圓環圖", + "gauge-type-horizontal-bar": "水平條形圖", + "gauge-type-vertical-bar": "垂直條形圖", + "donut-start-angle": "起始角度", + "bar-settings": "量規條設定", + "relative-bar-width": "相對條形寬度", + "neon-glow-brightness": "霓虹燈效果亮度,(0-100),0 - 禁用效果", + "stripes-thickness": "條紋的厚度,0 - 沒有條紋", + "rounded-line-cap": "顯示圓角線蓋", + "bar-color-settings": "條形圖顏色設定", + "use-precise-level-color-values": "使用精確的顏色級別", + "bar-colors": "條形顏色,從下到上", + "color": "顏色", + "no-bar-colors": "未配置條形圖顏色", + "add-bar-color": "增加條形圖顏色", + "from": "從", + "to": "至", + "fixed-level-colors": "使用邊界值的條形圖顏色", + "gauge-title-settings": "量規標題設定", + "show-gauge-title": "顯示量規標題", + "gauge-title": "量規標題", + "gauge-title-font": "量規標題字體", + "unit-title-and-timestamp-settings": "單元標題和時間戳設定", + "show-timestamp": "顯示值時間戳", + "timestamp-format": "時間戳格式", + "label-font": "顯示低於值的標籤字體", + "value-settings": "值設定", + "show-value": "顯示值文字", + "min-max-settings": "最小/最大標籤設定", + "show-min-max": "顯示最小值和最大值", + "min-max-font": "最小和最大標籤的字體", + "show-ticks": "顯示刻度", + "tick-width": "刻度寬度", + "tick-color": "刻度顏色", + "tick-values": "刻度值", + "no-tick-values": "未配置刻度值", + "add-tick-value": "增加刻度值" + }, + "gpio": { + "pin": "針", + "label": "標籤", + "row": "行", + "column": "列", + "color": "顏色", + "panel-settings": "面板設定", + "background-color": "背景顏色", + "gpio-switches": "GPIO開關", + "no-gpio-switches": "未配置GPIO開關", + "add-gpio-switch": "增加GPIO開關", + "gpio-status-request": "GPIO狀態請求", + "method-name": "方法名稱", + "method-body": "方法主體", + "gpio-status-change-request": "GPIO狀態更改請求", + "parse-gpio-status-function": "解析gpio狀態函數", + "gpio-leds": "GPIO led", + "no-gpio-leds": "未配置GPIO led", + "add-gpio-led": "增加GPIO led" + }, + "html-card": { + "html": "HTML", + "css": "CSS" + }, + "input-widgets": { + "attribute-not-allowed": "屬性參數在這個部件無法使用", + "blocked-location": "您的瀏覽器封鎖地理位置定位", + "claim-device": "設備請求", + "claim-failed": "設備請求失敗!", + "claim-not-found": "找不到設備", + "claim-successful": "設備請求成功!", + "date": "日期", + "device-name": "設備名稱", + "device-name-required": "設備名稱必填", + "discard-changes": "忽略變更", + "entity-attribute-required": "實體屬性必填", + "entity-coordinate-required": "經緯度兩項必填", + "entity-timeseries-required": "需要實體時間序列", + "get-location": "獲取當前位置", + "invalid-date": "失效日期", + "latitude": "緯度", + "longitude": "經度", + "min-value-error": "最小值為{{value}}", + "max-value-error": "最大值為{{value}}", + "not-allowed-entity": "所選實體不能具有共享屬性", + "no-attribute-selected": "未選擇任何屬性", + "no-datakey-selected": "未選擇任何數據鍵", + "no-coordinate-specified": "未指定緯度/經度的數據鍵", + "no-entity-selected": "未選擇實體", + "no-image": "沒有圖像", + "no-support-geolocation": "您的瀏覽器不支持地理定位", + "no-support-web-camera": "您的瀏覽器不支持相機", + "enable-https-use-widget": "請啟用HTTPS以使用此部件", + "no-found-your-camera": "找不到您的相機", + "no-permission-camera": "權限被用戶拒絕 / 此站點無權使用相機", + "no-timeseries-selected": "未選擇時間序列", + "secret-key": "密鑰", + "secret-key-required": "需要密鑰", + "switch-attribute-value": "切換實體屬性值", + "switch-camera": "切換相機", + "switch-timeseries-value": "切換實體時間序列值", + "take-photo": "拍照", + "time": "時間", + "timeseries-not-allowed": "此部件中不能使用時間序列參數", + "update-failed": "更新失敗", + "update-successful": "更新成功", + "update-attribute": "更新屬性", + "update-timeseries": "更新時間序列", + "value": "值", + "general-settings": "通用設定", + "widget-title": "部件標題", + "claim-button-label": "認領按鈕標籤", + "show-secret-key-field": "顯示 '密鑰' 輸入欄位", + "labels-settings": "標籤設定", + "show-labels": "顯示標籤", + "device-name-label": "設備名稱輸入欄位的標籤", + "secret-key-label": "密鑰輸入欄位的標籤", + "messages-settings": "消息設定", + "claim-device-success-message": "設備認領成功的簡訊", + "claim-device-not-found-message": "找不到設備時的簡訊", + "claim-device-failed-message": "設備認領失敗的簡訊", + "claim-device-name-required-message": "'需要設備名稱'的錯誤消息", + "claim-device-secret-key-required-message": "'需要密鑰'的朔戊消息", + "show-label": "顯示標籤", + "label": "標籤", + "required": "必須", + "required-error-message": "'必須'的錯誤訊息", + "show-result-message": "顯示結果消息", + "integer-field-settings": "整數字段設定", + "min-value": "最小值", + "max-value": "最大值", + "double-field-settings": "雙欄位設定", + "text-field-settings": "文字字段設定", + "min-length": "最小長度", + "max-length": "最長長度", + "checkbox-settings": "複選框設定", + "true-label": "選中的標籤", + "false-label": "未選中的標籤", + "image-input-settings": "圖像輸入設定", + "display-preview": "顯示預覽", + "display-clear-button": "顯示清除按鈕", + "display-apply-button": "顯示應用按鈕", + "display-discard-button": "顯示放棄按鈕", + "datetime-field-settings": "日期/時間字段設定", + "display-time-input": "顯示時間輸入", + "latitude-key-name": "緯度鍵名", + "longitude-key-name": "經度鍵名", + "show-get-location-button": "顯示按鈕 '獲取當前位置'", + "use-high-accuracy": "使用高精度", + "location-fields-settings": "位置字段設定", + "latitude-label": "緯度標籤", + "longitude-label": "經度標籤", + "input-fields-alignment": "輸入欄位對齊", + "input-fields-alignment-column": "列 (預設)", + "input-fields-alignment-row": "行", + "latitude-field-required": "需要緯度欄位", + "longitude-field-required": "需要經度欄位", + "attribute-settings": "屬性設定", + "widget-mode": "部件模式", + "widget-mode-update-attribute": "更新屬性", + "widget-mode-update-timeseries": "更新時間序列", + "attribute-scope": "屬性範圍", + "attribute-scope-server": "伺服器屬性", + "attribute-scope-shared": "共享屬性", + "value-required": "所需值", + "image-settings": "圖像設定", + "image-format": "圖像格式", + "image-format-jpeg": "JPEG", + "image-format-png": "PNG", + "image-format-webp": "WEBP", + "image-quality": "使用jpeg和webp等有損壓縮的圖像品質", + "max-image-width": "最大圖像寬度", + "max-image-height": "最大圖像高度", + "action-buttons": "操作按鈕", + "show-action-buttons": "顯示操作按鈕", + "update-all-values": "更新所有值,而不僅僅是修改的值", + "save-button-label": "'保存'按鈕標籤", + "reset-button-label": "'取消'按鈕標籤", + "group-settings": "群組設定", + "show-group-title": "顯示與不同實體相關的欄位組的標題", + "group-title": "群組標題", + "fields-alignment": "欄位對齊", + "fields-alignment-row": "行 (預設)", + "fields-alignment-column": "列", + "fields-in-row": "行中的欄位數", + "option-value": "數值 (為創建空選項寫入 'null')", + "option-label": "標籤", + "hide-input-field": "隱藏輸入欄位", + "datakey-type": "數據鍵類型", + "datakey-type-server": "伺服器屬性 (預設)", + "datakey-type-shared": "共享屬性", + "datakey-type-timeseries": "時間序列", + "datakey-value-type": "數據鍵值類型", + "datakey-value-type-string": "字符串", + "datakey-value-type-double": "雙重的", + "datakey-value-type-integer": "整數", + "datakey-value-type-boolean-checkbox": "布林值(複選框)", + "datakey-value-type-boolean-switch": "布林值 (開關)", + "datakey-value-type-date-time": "日期和時間", + "datakey-value-type-date": "日期", + "datakey-value-type-time": "時間", + "datakey-value-type-select": "選擇", + "value-is-required": "需要值", + "ability-to-edit-attribute": "編輯屬性的能力", + "ability-to-edit-attribute-editable": "啟用 (預設)", + "ability-to-edit-attribute-disabled": "已禁用", + "ability-to-edit-attribute-readonly": "唯讀", + "disable-on-datakey-name": "禁用另一個數據鍵的錯誤值 (指定數據鍵名稱)", + "slide-toggle-settings": "滑塊切換設定", + "slide-toggle-label-position": "滑塊切換標籤位置", + "slide-toggle-label-position-after": "後", + "slide-toggle-label-position-before": "前", + "select-options": "選擇選項", + "no-select-options": "未配置選擇選項", + "add-select-option": "增加選擇選項", + "numeric-field-settings": "數值欄位設定", + "step-interval": "值之間的步長間隔", + "error-messages": "錯誤訊息", + "min-value-error-message": "錯誤訊息: '低於最大值'", + "max-value-error-message": "錯誤訊息: '超過最大值'", + "invalid-date-error-message": "錯誤訊息: '無效日期'", + "icon-settings": "圖示設定", + "use-custom-icon": "使用客製圖示", + "input-cell-icon": "在輸入儲存格之前顯示圖示", + "value-conversion-settings": "值換算設定", + "get-value-settings": "取得數值設定", + "use-get-value-function": "使用getValue函數", + "get-value-function": "getValue函數", + "set-value-settings": "設定值設定", + "use-set-value-function": "使用setValue函數", + "set-value-function": "setValue函數" + }, + "invalid-qr-code-text": "無效的QR code文字,輸入應該有一個字串類型。", + "qr-code": { + "use-qr-code-text-function": "使用QR code文字功能", + "qr-code-text-pattern": "QR code文字模式 (例如 '${entityName} | ${keyName} - 一些文字。')", + "qr-code-text-pattern-required": "QR code文字模式必填", + "qr-code-text-function": "QR code文字功能" + }, + "label-widget": { + "label-pattern": "圖案", + "label-pattern-hint": "提示: 例如 '文字 ${keyName} 單位。' 或 ${#<key index>} 單位", + "label-pattern-required": "需要圖案", + "label-position": "位置 (相對於背景的百分比)", + "x-pos": "X", + "y-pos": "Y", + "background-color": "背景顔色", + "font-settings": "文字設定", + "background-image": "背景圖片", + "labels": "標籤", + "no-labels": "無指定標籤", + "add-label": "新增標籤" + }, + "navigation": { + "title": "標題", + "navigation-path": "導航路徑", + "filter-type": "過濾器種類", + "filter-type-all": "所有過濾器項目", + "filter-type-include": "包括過濾器", + "filter-type-exclude": "不包括過濾器", + "items": "項目", + "enter-urls-to-filter": "使用urls過濾...." + }, + "persistent-table": { + "rpc-id": "RPC ID", + "message-type": "消息類型", + "method": "方法", + "params": "參數", + "created-time": "建立時間", + "expiration-time": "到期時間", + "retries": "重試", + "status": "狀態", + "filter": "過濾器", + "refresh": "刷新", + "add": "增加RPC請求", + "details": "詳細資訊", + "delete": "刪除", + "delete-request-title": "刪除永久RPC請求", + "delete-request-text": "您確定要刪除請求嗎?", + "details-title": "詳細信息RPC ID: ", + "additional-info": "附加信息", + "response": "回復", + "any-status": "任何狀態", + "rpc-status-list": "RPC狀態列表", + "no-request-prompt": "沒有顯示請求", + "send-request": "發送請求", + "add-title": "創建永久RPC請求", + "method-error": "需要方法。", + "timeout-error": "最小超時值為5000 (5秒)。", + "white-space-error": "不允許使用空格。", + "rpc-status": { + "QUEUED": "排序", + "SENT": "發送", + "DELIVERED": "發表", + "SUCCESSFUL": "成功", + "TIMEOUT": "超時", + "EXPIRED": "已到期", + "FAILED": "失敗" + }, + "rpc-search-status-all": "全部", + "message-types": { + "false": "雙向", + "true": "單向" + }, + "general-settings": "一般設定", + "enable-filter": "啓動過濾器", + "enable-sticky-header": "當捲動時顯示標題", + "enable-sticky-action": "當捲動時顯示操作列", + "display-request-details": "顯示請求詳細資料", + "allow-send-request": "允許傳送RPC請求", + "allow-delete-request": "允許刪除請求", + "columns-settings": "列設定", + "display-columns": "顯示列", + "column": "列", + "no-columns-found": "找不到列", + "no-columns-matching": "找不到'{{column}}'" + }, + "rpc": { + "value-settings": "值設定", + "initial-value": "初始值", + "retrieve-value-settings": "檢索開/關的值", + "retrieve-value-method": "檢索值使用方法", + "retrieve-value-method-none": "請勿檢索", + "retrieve-value-method-rpc": "呼叫RPC取得值的方法", + "retrieve-value-method-attribute": "訂閲屬性", + "retrieve-value-method-timeseries": "訂閲時間序列", + "attribute-value-key": "屬性鍵", + "timeseries-value-key": "時間序列鍵", + "get-value-method": "RPC取得值的方法", + "parse-value-function": "解析值函數", + "update-value-settings": "更新值設定", + "set-value-method": "RPC設定值方法", + "convert-value-function": "轉換值函數", + "rpc-settings": "RPC設定", + "request-timeout": "RPC請求超時 (毫秒)", + "persistent-rpc-settings": "永久RPC設定", + "request-persistent": "RPC請求持續", + "persistent-polling-interval": "獲取永久RPC命令響應的輪詢間隔 (毫秒)", + "common-settings": "常用設定", + "switch-title": "切換標題", + "show-on-off-labels": "顯示開/關標籤", + "slide-toggle-label": "滑塊切換標籤", + "label-position": "標籤位置", + "label-position-before": "前", + "label-position-after": "後", + "slider-color": "滑塊顏色", + "slider-color-primary": "主要的", + "slider-color-accent": "口音", + "slider-color-warn": "警告", + "button-style": "按鈕樣式", + "button-raised": "凸起的按鈕", + "button-primary": "主要顏色", + "button-background-color": "按鈕背景顏色", + "button-text-color": "按鈕文字顏色", + "widget-title": "部件標題", + "button-label": "按鈕標籤", + "device-attribute-scope": "設備屬性範圍", + "server-attribute": "伺服器屬性", + "shared-attribute": "共享屬性", + "device-attribute-parameters": "設備屬性參數", + "is-one-way-command": "是單向命令", + "rpc-method": "RPC方法", + "rpc-method-params": "RPC方法參數", + "show-rpc-error": "顯示RPC命令執行錯誤", + "led-title": "LED標題", + "led-color": "LED顏色", + "check-status-settings": "檢查狀態設定", + "perform-rpc-status-check": "執行RPC設備狀態檢查", + "retrieve-led-status-value-method": "使用方法檢索led狀態值", + "led-status-value-attribute": "包含led狀態值的設備屬性", + "led-status-value-timeseries": "包含led狀態值的設備時間序列", + "check-status-method": "RPC檢查設備狀態方法", + "parse-led-status-value-function": "解析led狀態值函數", + "knob-title": "旋鈕標題", + "min-value": "最小值", + "max-value": "最大值" + }, + "maps": { + "select-entity": "選擇實體", + "select-entity-hint": "提示:選擇後點擊地圖設置位置", + "tooltips": { + "placeMarker": "單擊以放置'{{entityName}}'實體", + "firstVertex": " '{{entityName}}'的多邊形:單擊以放置第一個點", + "firstVertex-cut": "單擊以放置第一個點", + "continueLine": " '{{entityName}}'的多邊形:單擊以繼續繪製", + "continueLine-cut": "點擊繼續繪製", + "finishLine": "單擊任何現有標記以完成", + "finishPoly": "'{{entityName}}'個多邊形:點擊第一個標記以完成並保存", + "finishPoly-cut": "單擊第一個標記以完成並保存", + "finishRect": "'{{entityName}}'的多邊形:點擊完成並保存", + "startCircle": "'{{entityName}}'的圓圈:點擊以放置圓圈中心", + "finishCircle": "'{{entityName}}'的圓圈:點擊以完成圓圈", + "placeCircleMarker": "單擊以放置圓形標記" + }, + "actions": { + "finish": "結束", + "cancel": "取消", + "removeLastVertex": "移除最後一點" + }, + "buttonTitles": { + "drawMarkerButton": "放置實體", + "drawPolyButton": "創線多邊形", + "drawLineButton": "創建折線", + "drawCircleButton": "創建圓形", + "drawRectButton": "創建矩形", + "editButton": "編輯模式", + "dragButton": "拖放模式", + "cutButton": "切割多邊形區域", + "deleteButton": "移除", + "drawCircleMarkerButton": "創建圓形標記", + "rotateButton": "旋轉多邊形" + }, + "map-provider-settings": "地圖提供者設定", + "map-provider": "地圖提供者", + "map-provider-google": "Google地圖", + "map-provider-openstreet": "OpenStreet地圖", + "map-provider-here": "HERE地圖", + "map-provider-image": "圖像地圖", + "map-provider-tencent": "騰訊地圖", + "openstreet-provider": "OpenStreet 地圖提供者", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (預設)", + "openstreet-provider-hot": "OpenStreetMap.HOT", + "openstreet-provider-esri-street": "Esri.WorldStreetMap", + "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-cartodb-positron": "CartoDB.Positron", + "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", + "use-custom-provider": "使用自定義提供程序", + "custom-provider-tile-url": "自定義提供程序磁貼URL", + "google-maps-api-key": "Google地圖API金鑰", + "default-map-type": "預設地圖類型", + "google-map-type-roadmap": "道路模式", + "google-map-type-satelite": "衛星模式", + "google-map-type-hybrid": "混合模式", + "google-map-type-terrain": "地形模式", + "map-layer": "地圖圖層", + "here-map-normal-day": "HERE.正常日間 (預設)", + "here-map-normal-night": "HERE.正常夜間", + "here-map-hybrid-day": "HERE.混合日", + "here-map-terrain-day": "HERE.地形日", + "credentials": "證書", + "here-app-id": "HERE app id", + "here-app-code": "HERE app程式碼", + "tencent-maps-api-key": "騰訊地圖API金鑰", + "tencent-map-type-roadmap": "道路模式", + "tencent-map-type-satelite": "衛星模式", + "tencent-map-type-hybrid": "混合模式", + "image-map-background": "地圖圖片背景", + "image-map-background-from-entity-attribute": "從實體屬性獲取地圖背景", + "image-url-source-entity-alias": "圖片URL來源別名", + "image-url-source-entity-attribute": "圖片URL來源屬性", + "common-map-settings": "一般地圖設定", + "x-pos-key-name": "X軸座標主要名稱", + "y-pos-key-name": "Y軸座標主要名稱", + "latitude-key-name": "緯度主要名稱", + "longitude-key-name": "經度主要名稱", + "default-map-zoom-level": "預設地圖縮放級別 (0 - 20)", + "default-map-center-position": "預設地圖中心位置(0,0)", + "disable-scroll-zooming": "關閉捲動縮放功能", + "disable-double-click-zooming": "關閉雙擊縮放功能", + "disable-zoom-control-buttons": "關閉縮放控制按鈕功能", + "fit-map-bounds": "符合地圖邊界以遮蓋所有標記", + "use-default-map-center-position": "使用預設地圖中心位置", + "entities-limit": "實體負載限制", + "markers-settings": "標記設定", + "marker-offset-x": "標記的X偏移量相對於位置乘以標記的寬度", + "marker-offset-y": "標記的Y偏移量相對於位置乘以標記的高度", + "position-function": "位置轉換函數,應將X,Y座標作爲雙數從0到1分別返回", + "draggable-marker": "可拖拉的標記", + "label": "標籤", + "show-label": "顯示標籤", + "use-label-function": "使用標籤功能", + "label-pattern": "標籤(模式示例: '${entityName}'、'${entityName}:(文字 ${keyName} 單位。)' )", + "label-function": "標籤功能", + "tooltip": "工具提示", + "show-tooltip": "顯示工具提示", + "show-tooltip-action": "顯示工具提示的動作", + "show-tooltip-action-click": "顯示工具提示的動作點擊(預設)", + "show-tooltip-action-hover": "顯示工具提示的懸停效果", + "auto-close-tooltips": "自動關閉工具提示", + "use-tooltip-function": "使用工具提示功能", + "tooltip-pattern": "工具提示 (例如 '文字 ${keyName} 單位.' 或連結文字')", + "tooltip-function": "工具提示功能", + "tooltip-offset-x": "工具提示相對於標記錨的X偏移量乘以標記的寬度", + "tooltip-offset-y": "工具提示相對於標記錨的Y偏移量乘以標記的寬度", + "color": "顔色", + "use-color-function": "使用顔色功能", + "color-function": "顔色功能", + "marker-image": "標記圖片", + "use-marker-image-function": "使用標記圖片功能", + "custom-marker-image": "客製標記圖片", + "custom-marker-image-size": "客製標記圖片尺寸(px)", + "marker-image-function": "標記圖片功能", + "marker-images": "多張標記圖片", + "polygon-settings": "多邊形設定", + "show-polygon": "顯示多邊形", + "polygon-key-name": "多邊形主要名稱", + "enable-polygon-edit": "啓用多邊形編輯", + "polygon-label": "多邊形標籤", + "show-polygon-label": "顯示多邊形標籤", + "use-polygon-label-function": "使用多邊形功能", + "polygon-label-pattern": "多邊形標籤 (模式示例: '${entityName}'、 '${entityName}: (文字${keyName} 單位。)' )", + "polygon-label-function": "多邊形標籤功能", + "polygon-tooltip": "多邊形工具提示", + "show-polygon-tooltip": "顯示多邊形標籤", + "auto-close-polygon-tooltips": "自動關閉多邊形工具提示", + "use-polygon-tooltip-function": "使用多邊形工具提示功能", + "polygon-tooltip-pattern": "工具提示 (例如'文字 ${keyName} 單位' 或 連結文字')", + "polygon-tooltip-function": "多邊形工具提示功能", + "polygon-color": "多邊形顔色", + "polygon-opacity": "多邊形不透明度", + "use-polygon-color-function": "使用多邊形顔色功能", + "polygon-color-function": "多邊形顔色功能", + "polygon-stroke": "多邊形顔色", + "stroke-color": "筆畫顔色", + "stroke-opacity": "筆畫不透明度", + "stroke-weight": "筆畫粗細", + "use-polygon-stroke-color-function": "使用多邊形筆畫顔色功能", + "polygon-stroke-color-function": "多邊形筆畫顔色功能", + "circle-settings": "圓形設定", + "show-circle": "顯示圓形", + "circle-key-name": "圓形主要名稱", + "enable-circle-edit": "啓用圓形編輯", + "circle-label": "圓形標籤", + "show-circle-label": "顯示圓形標籤", + "use-circle-label-function": "使用圓形標籤功能", + "circle-label-pattern": "圓形標籤 (模式示例: '${entityName}'、'${entityName}: (文字${keyName}單位。)' )", + "circle-label-function": "圓形標籤功能", + "circle-tooltip": "圓形工具提示", + "show-circle-tooltip": "顯示圓形工具提示", + "auto-close-circle-tooltips": "自動關閉圓形工具提示", + "use-circle-tooltip-function": "使用圓形工具提示功能", + "circle-tooltip-pattern": "工具提示 (例如'文字${keyName} 單位' 或連結文字')", + "circle-tooltip-function": "圓形工具提示功能", + "circle-fill-color": "圓形填充顔色", + "circle-fill-color-opacity": "圓形填充顔色不透明度", + "use-circle-fill-color-function": "使用圓形填充顔色功能", + "circle-fill-color-function": "圓形填充顔色功能", + "circle-stroke": "圓形筆畫", + "use-circle-stroke-color-function": "使用圓形筆畫顔色功能", + "circle-stroke-color-function": "圓形筆畫顔色功能", + "markers-clustering-settings": "標記叢集設定", + "use-map-markers-clustering": "使用地圖標記叢集", + "zoom-on-cluster-click": "當點擊地圖標記叢集時縮放", + "max-cluster-zoom": "標記可以是叢集的一部分時的最大縮放級別(0 - 18)", + "max-cluster-radius-pixels": "一個叢集可覆蓋的最大半徑,以像素為單位", + "cluster-zoom-animation": "當縮放時在標記上顯示動畫", + "show-markers-bounds-on-cluster-mouse-over": "當滑鼠移到一個叢集上時,顯示標記的邊界", + "spiderfy-max-zoom-level": "在最大變焦水平下的Spiderfy(爲了可看到所有的叢集標記)", + "load-optimization": "負載優化", + "cluster-chunked-loading": "使用塊來添加標記,這樣頁面就不會凍結了", + "cluster-markers-lazy-load": "使用延遲載入來添加標記", + "editor-settings": "編輯者設定", + "enable-snapping": "啓用對其他頂點的抓取以實現精確繪圖", + "init-draggable-mode": "在可拖拉模式下初始化地圖", + "hide-all-edit-buttons": "隱藏所有編輯控制按鈕", + "hide-draw-buttons": "隱藏繪圖按鈕", + "hide-edit-buttons": "隱藏編輯按鈕", + "hide-remove-button": "隱藏移除按鈕", + "route-map-settings": "路線圖設定", + "trip-animation-settings": "行程動畫設定", + "normalization-step": "正規化資料步驟(毫秒)", + "tooltip-background-color": "提示工具背景顔色", + "tooltip-font-color": "提示文字顔色", + "tooltip-opacity": "提示工具不透明度(0-1)", + "auto-close-tooltip": "自動關閉提示工具", + "rotation-angle": "設定標記的額外選擇角度", + "path-settings": "路徑設定", + "path-color": "路徑顔色", + "use-path-color-function": "使用路徑顔色功能", + "path-color-function": "路徑顔色功能", + "path-decorator": "路徑裝飾器", + "use-path-decorator": "使用路徑裝飾器", + "decorator-symbol": "裝飾器符號", + "decorator-symbol-arrow-head": "裝飾器符號-箭頭", + "decorator-symbol-dash": "裝飾器符號-儀表板", + "decorator-symbol-size": "裝飾器符號尺寸 (px)", + "use-path-decorator-custom-color": "使用路徑裝飾器客製顔色", + "decorator-custom-color": "裝飾器客製顔色", + "decorator-offset": "裝飾器串列修改", + "end-decorator-offset": "結束裝飾器串列修改", + "decorator-repeat": "裝飾器重複", + "points-settings": "點物件設定", + "show-points": "顯示點物件", + "point-color": "點物件顔色", + "point-size": "點物件尺寸(px)", + "use-point-color-function": "使用點物件顔色功能", + "point-color-function": "點物件顔色功能", + "use-point-as-anchor": "使用點物件做爲錨", + "point-as-anchor-function": "使用點物件做爲錨功能", + "independent-point-tooltip": "獨立點物件的工具提示" + }, + "markdown": { + "use-markdown-text-function": "使用markdown語言功能", + "markdown-text-function": "Markdown/HTML value function", + "markdown-text-pattern": "Markdown/HTML模式(markdown 或帶有變量的HTML,例如'${entityName} 或${keyName} - 一些文字。')", + "markdown-css": "Markdown/HTML CSS" + }, + "simple-card": { + "label-position": "標籤位置", + "label-position-left": "標籤置左", + "label-position-top": "標籤置頂" + }, + "table": { + "common-table-settings": "通用資料表設定", + "enable-search": "啓動搜尋", + "enable-sticky-header": "始終顯示標題", + "enable-sticky-action": "始終顯示動作欄", + "hidden-cell-button-display-mode": "隱藏儲存格按鈕動作顯示模式", + "show-empty-space-hidden-action": "顯示空格而不是隱藏儲存格的按鈕動作", + "dont-reserve-space-hidden-action": "不要為隱藏的動作按鈕保留空格", + "display-timestamp": "顯示時間戳列", + "display-milliseconds": "顯示毫秒時間戳", + "display-pagination": "顯示分頁", + "default-page-size": "預設頁面尺寸", + "use-entity-label-tab-name": "在分頁標籤名稱中使用實體標籤", + "hide-empty-lines": "隱藏空白線", + "row-style": "行種類", + "use-row-style-function": "使用行種類功能", + "row-style-function": "行種類功能", + "cell-style": "儲存格種類", + "use-cell-style-function": "使用單元格種類功能", + "cell-style-function": "儲存格種類功能", + "cell-content": "儲存格内容", + "use-cell-content-function": "使用儲存格内容功能", + "cell-content-function": "儲存格内容功能", + "show-latest-data-column": "顯示最新資料欄", + "latest-data-column-order": "最新資料欄順序", + "entities-table-title": "實體表格標題", + "enable-select-column-display": "啓用要顯示的選擇列", + "display-entity-name": "顯示實體名稱列", + "entity-name-column-title": "實體名稱列標題", + "display-entity-label": "顯示實體標籤列", + "entity-label-column-title": "實體標籤列標題", + "display-entity-type": "顯示實體類型列", + "default-sort-order": "預設排序順序", + "column-width": "列寬 (px or %)", + "default-column-visibility": "預設列能見性", + "column-visibility-visible": "顯示", + "column-visibility-hidden": "隱藏", + "column-selection-to-display": "'要顯示的列'中的列選擇", + "column-selection-to-display-enabled": "已啟用", + "column-selection-to-display-disabled": "已禁用", + "alarms-table-title": "警告表格標題", + "enable-alarms-selection": "啓動警告選項", + "enable-alarms-search": "啓動警告搜尋", + "enable-alarm-filter": "啓動警告過濾", + "display-alarm-details": "顯示警告詳細資訊", + "allow-alarms-ack": "允許警告確認", + "allow-alarms-clear": "允許警告清除" + }, + "value-source": { + "value-source": "值來源", + "predefined-value": "預定義值", + "entity-attribute": "取至實體屬性的值", + "value": "值", + "source-entity-alias": "源實體別名", + "source-entity-attribute": "源實體屬性" + }, + "widget-font": { + "font-family": "字型家族", + "size": "文字大小", + "relative-font-size": "相對文字大小(百分比)", + "font-style": "字體類別", + "font-style-normal": "正體字", + "font-style-italic": "斜體字", + "font-style-oblique": "斜體字", + "font-weight": "文字粗細", + "font-weight-normal": "一般粗細的文字", + "font-weight-bold": "粗體字", + "font-weight-bolder": "更粗的字", + "font-weight-lighter": "更細的字", + "color": "文字顔色", + "shadow-color": "文字陰影顔色" + } + }, + "icon": { + "icon": "圖示", + "select-icon": "選擇圖示", + "material-icons": "素材圖示", + "show-all": "顯示所有圖示" + }, + "phone-input": { + "phone-input-label": "電話號碼", + "phone-input-required": "電話號碼為必填項", + "phone-input-validation": "電話號碼無效或不可能", + "phone-input-pattern": "無效的電話號碼。應採用E.164格式,例如{{phoneNumber}}", + "phone-input-hint": "E.164格式的電話號碼,例如{{phoneNumber}}" + }, + "custom": { + "widget-action": { + "action-cell-button": "動作單元格按鈕", + "row-click": "點選行", + "polygon-click": "單擊多邊形", + "marker-click": "點選標記", + "circle-click": "點擊圓圈", + "tooltip-tag-action": "提示標籤動作", + "node-selected": "在選定的節點上", + "element-click": "在HTML元素上單擊", + "pie-slice-click": "點擊切片", + "row-double-click": "在行上雙擊" + } + }, + "language": { + "language": "語言", + "locales": { + "de_DE": "Deutsch", + "fr_FR": "Français", + "zh_CN": "简体中文", + "zh_TW": "繁體中文", + "en_US": "English", + "it_IT": "Italiano", + "ko_KR": "한국어", + "ru_RU": "Русский", + "es_ES": "Español", + "ja_JP": "日本語", + "tr_TR": "Türkçe", + "fa_IR": "فارسي", + "uk_UA": "Українська", + "cs_CZ": "Česky", + "el_GR": "Ελληνικά", + "ro_RO": "Română", + "lv_LV": "Latviešu", + "ka_GE": "ქართული", + "pt_BR": "Português do Brasil", + "sl_SI": "Slovenščina" + } } - }, - "language": { - "language": "語言" - } } diff --git a/ui-ngx/src/environments/environment.prod.ts b/ui-ngx/src/environments/environment.prod.ts index ac83352a2a..f724eb6687 100644 --- a/ui-ngx/src/environments/environment.prod.ts +++ b/ui-ngx/src/environments/environment.prod.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/environments/environment.ts b/ui-ngx/src/environments/environment.ts index 21470567cd..82d426e95c 100644 --- a/ui-ngx/src/environments/environment.ts +++ b/ui-ngx/src/environments/environment.ts @@ -1,5 +1,5 @@ /// -/// Copyright © 2016-2022 The Thingsboard Authors +/// Copyright © 2016-2023 The Thingsboard Authors /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. diff --git a/ui-ngx/src/index.html b/ui-ngx/src/index.html index c8899dc62a..415dae7fa9 100644 --- a/ui-ngx/src/index.html +++ b/ui-ngx/src/index.html @@ -1,6 +1,6 @@