feat: localize MedLogic UI and document Debian image
Keep only Russian and English, trim diagnostics, and add a Taskfile that builds docker.med-logic.ru/olivetin:latest. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e3ba0b70d7
commit
68a7ec2e43
36
AI.md
36
AI.md
|
|
@ -1,36 +0,0 @@
|
|||
# OliveTin's AI Policy
|
||||
|
||||
## Runtime:
|
||||
|
||||
- [x] The project does not include any AI functionality at runtime.
|
||||
- [x] No data, usage, or similar is sent to, or analyized by AI.
|
||||
|
||||
## Development - Autonomy level
|
||||
|
||||
OliveTin development uses up to **Level 2 of 5 (pair programmer)** on the [AI Levels of Autonomy in Software Engineering](https://blog.jread.com/posts/ai-levels-of-autonomy-in-software-engineering/) scale: AI may generate suggestions and non-trivial changes, but humans review and decide what lands in the project.
|
||||
|
||||
## Development - Contributions
|
||||
|
||||
- [x] The project **does accept** contributions that were written with AI help. **However**:
|
||||
- The contribution must be attributed to a human username who takes responsibility for the code as if they wrote it themselves.
|
||||
- AI often generates very unmaintainable code as it gets longer - loads of duplication, very little function re-use amd very poor at following style guides / idiomatic design. All code contributions (AI or not) are scrutinized hard for **maintainability** and **clean merging**. Please follow the CONTRIBUTORS guide.
|
||||
- AI that helps with short tab completion is generally fine.
|
||||
- AI that writes lots of new code across lots of files, or makes lots of superfluous changes is generally less likely to be accepted.
|
||||
- Vibe coding is generally not a suitable way to contribute to this project.
|
||||
- [x] Contributors should declare when AI has been used to help write contributions in the pull request body message.
|
||||
- [x] The project uses AI as an **optional** part of the PR process (coderabbitai). Please raise any concerns about usage within the PR.
|
||||
- [x] Suggestions from coderabbitai can be accepted verbaitem, but ideally it should be the PR author that uses coderabbitai as a guide, who then re-writes the contribution.
|
||||
- [x] Maintainers are the only agents permitted to accept merges.
|
||||
|
||||
## Development - Build process
|
||||
|
||||
- [x] Linters, code review tools, and others which are enabled by AI are allowed, but cannot be added as part of the standard build process.
|
||||
|
||||
## Community
|
||||
|
||||
- [x] Only project admins are allowed to run bots in the community discord server (at the time of writing, the current bot, Japella, is not AI-enabled).
|
||||
- [x] Support is currently not provided by AI.
|
||||
|
||||
## Training
|
||||
|
||||
- [x] You may use the OliveTin code base, documentation and repositories to train AI, but obviously usernames and personally identifiable information may not be stored.
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
contact@jread.com, or via Discord.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
FROM --platform=linux/amd64 debian:13-slim
|
||||
|
||||
LABEL org.opencontainers.image.source https://github.com/OliveTin/OliveTin
|
||||
LABEL org.opencontainers.image.title OliveTin
|
||||
|
||||
RUN mkdir -p /config /config/entities/ /var/www/olivetin \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
|
|
@ -14,6 +11,9 @@ RUN mkdir -p /config /config/entities/ /var/www/olivetin \
|
|||
jq \
|
||||
openssh-client \
|
||||
passwd \
|
||||
unzip \
|
||||
tar \
|
||||
gzip \
|
||||
&& install -m 0755 -d /etc/apt/keyrings \
|
||||
&& curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc \
|
||||
&& chmod a+r /etc/apt/keyrings/docker.asc \
|
||||
|
|
@ -26,10 +26,6 @@ RUN useradd --system --create-home olivetin -u 1000
|
|||
|
||||
EXPOSE 1337/tcp
|
||||
|
||||
COPY config.yaml /config
|
||||
COPY var/entities/* /config/entities/
|
||||
COPY examples/backupScript.sh /opt/backupScript.sh
|
||||
RUN chmod 755 /opt/backupScript.sh
|
||||
VOLUME /config
|
||||
|
||||
COPY OliveTin /usr/bin/OliveTin
|
||||
|
|
|
|||
2
Makefile
2
Makefile
|
|
@ -1,5 +1,5 @@
|
|||
define delete-files
|
||||
python -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
|
||||
python3 -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
|
||||
endef
|
||||
|
||||
service:
|
||||
|
|
|
|||
101
README.md
101
README.md
|
|
@ -1,96 +1,31 @@
|
|||
<div align = "center">
|
||||
<img alt = "project logo" src = "https://github.com/OliveTin/OliveTin/blob/main/frontend/OliveTinLogo.png" width = "128" />
|
||||
<h1>OliveTin</h1>
|
||||
# OliveTin (MedLogic)
|
||||
|
||||
OliveTin gives **safe** and **simple** access to predefined shell commands from a web interface.
|
||||
Форк [OliveTin](https://github.com/OliveTin/OliveTin) для МИС «Медицина».
|
||||
|
||||
[](#none)
|
||||
[](https://discord.gg/jhYWWpNJ3v)
|
||||
[](https://github.com/awesome-selfhosted/awesome-selfhosted#automation)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/5050)
|
||||
Исходный репозиторий: https://github.com/OliveTin/OliveTin
|
||||
|
||||
[](https://goreportcard.com/report/github.com/OliveTin/OliveTin)
|
||||
[-blue)](https://blog.jread.com/posts/ai-levels-of-autonomy-in-software-engineering/)
|
||||
## Docker-образ
|
||||
|
||||
[OliveTin 2k to 3k upgrade guide](https://docs.olivetin.app/upgrade/2k3k.html)
|
||||
</div>
|
||||
Официальный образ OliveTin заменён. Этот форк собирает контейнер на **Debian 13 slim** (`debian:13-slim`), а не на базовом образе оригинала.
|
||||
|
||||
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-laptop_framed.png" />
|
||||
<a href = "#screenshots">More screenshots below</a>
|
||||
Тег локальной сборки:
|
||||
|
||||
All documentation can be found at [docs.olivetin.app](https://docs.olivetin.app). This includes installation and usage guide, etc.
|
||||
```text
|
||||
docker.med-logic.ru/olivetin:latest
|
||||
```
|
||||
|
||||
The AsciiDoc sources for that site live in this repository under [`docs/`](docs/) (Antora component). The [docs.olivetin.app](https://github.com/OliveTin/docs.olivetin.app) repository contains the Antora playbook, theme supplemental files, and the workflow that publishes GitHub Pages.
|
||||
Сборка:
|
||||
|
||||
## Use cases
|
||||
```bash
|
||||
task build
|
||||
```
|
||||
|
||||
**Safely** give access to commands, for less technical people;
|
||||
Dockerfile: `Dockerfile.singlearch`.
|
||||
|
||||
* eg: Give your family a button to `podman restart plex`
|
||||
* eg: Give junior admins a simple web form with dropdowns, to start your custom script. `backupScript.sh --folder {{ customerName }}`
|
||||
* eg: Enable SSH access to the server for the next 20 mins `firewall-cmd --add-service ssh --timeout 20m`
|
||||
## Лицензия
|
||||
|
||||
**Simplify** complex commands, make them accessible and repeatable;
|
||||
Проект распространяется на условиях **GNU Affero General Public License v3.0** (AGPL-3.0).
|
||||
|
||||
* eg: Expose complex commands on touchscreen tablets stuck on walls around your house. `wake-on-lan aa:bb:cc:11:22:33`
|
||||
* eg: Run long-lived commands on your servers from your cell phone. `dnf update -y`
|
||||
* eg: Define complex commands with lots of preset arguments, and turn a few arguments into dropdown select boxes. `docker rm {{ container }} && docker create {{ container }} && docker start {{ container }}`
|
||||
Полный текст: [LICENSE](LICENSE).
|
||||
|
||||
[Join the community on Discord](https://discord.gg/jhYWWpNJ3v) to talk with other users about use cases, or to ask for support in getting started.
|
||||
|
||||
## YouTube demo video
|
||||
|
||||
[](https://www.youtube.com/watch?v=UBgOfNrzId4)
|
||||
|
||||
## Features
|
||||
|
||||
* **Responsive, touch-friendly UI** - great for tablets and mobile
|
||||
* **Super simple config in YAML** - because if it's not YAML now-a-days, it's not "cloud native" :-)
|
||||
* **Dark mode** - for those of you that roll that way.
|
||||
* **Accessible** - passes all the accessibility checks in Firefox, and issues with accessibility are taken seriously.
|
||||
* **Container** - available for quickly testing and getting it up and running, great for the selfhosted community.
|
||||
* **Integrate with anything** - OliveTin just runs Linux shell commands, so theoretically you could integrate with a bunch of stuff just by using curl, ping, etc. However, writing your own shell scripts is a great way to extend OliveTin.
|
||||
* **Lightweight on resources** - uses only a few MB of RAM and barely any CPU. Written in Go, with a web interface written as a modern, responsive, Single Page App that uses the REST/Connect RPC API.
|
||||
* **Good amount of unit tests and style checks** - helps potential contributors be consistent, and helps with maintainability.
|
||||
|
||||
## Screenshots
|
||||
|
||||
Desktop web browser;
|
||||
|
||||
<p align = "center">
|
||||
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-laptop_framed.png" />
|
||||
</p>
|
||||
|
||||
Desktop web browser (dark mode);
|
||||
|
||||
<p align = "center">
|
||||
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-darkop_framed.png" />
|
||||
</p>
|
||||
|
||||
Mobile screen size (responsive layout);
|
||||
|
||||
<p align = "center">
|
||||
<img alt = "screenshot" src = "https://github.com/OliveTin/OliveTin/blob/main/var/marketing/screenshots/mainpage-phone_framed.png" style = "width: 700px;" />
|
||||
</p>
|
||||
|
||||
## No-Nonsense Software Principles
|
||||
|
||||
OliveTin follows these principles:
|
||||
|
||||
* **Open Source & Free Software**: following the [Open Source Definition](https://opensource.org/osd) and the [Free Software Definition](https://www.gnu.org/philosophy/free-sw.html). All code and assets are available under the [AGPL-3.0 License](LICENSE).
|
||||
* **Independent**: No company owns the code or is responsible for the projects' governance.
|
||||
* **Inclusive**: No "core", "pro", "premium" or "enterprise" version. The only version is the one you can download and run, and it has all the features.
|
||||
* **Invisible**: No usage tracking, no user tracking, no ads, and no telemetry.
|
||||
* **Internal**: No internet connection required for any functionality.
|
||||
|
||||
## Documentation
|
||||
|
||||
All documentation can be found at [docs.olivetin.app](https://docs.olivetin.app). This includes installation and usage guide, etc.
|
||||
|
||||
You can find instructions in the docs on how to install as a **Linux package**, **Linux Container**, on **FreeBSD**, **Windows**, **macOS** and other platforms, too!
|
||||
|
||||
## Donations & Sponsorship
|
||||
|
||||
OliveTin does not accept monetary donations or sponsorship. See [Donations & Sponsorship](https://docs.olivetin.app/reference/donations_and_sponsorship.html) for the full explanation.
|
||||
|
||||
* Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
|
||||
Оригинальный OliveTin также лицензирован под AGPL-3.0. При использовании и дальнейшем распространении этого форка необходимо соблюдать условия AGPL-3.0, в том числе предоставление исходного кода при сетевом использовании модифицированной версии.
|
||||
|
|
|
|||
71
SECURITY.md
71
SECURITY.md
|
|
@ -1,71 +0,0 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The following branches are currently being supported with security updates:
|
||||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| `main` (3k release branch) | :white_check_mark: - advisories will be published when patched in this branch |
|
||||
| `release/2k` (2k release branch) | :white_check_mark: - receives security updates, but much slower |
|
||||
|
||||
To understand more about 2k vs 3k, see the following docs; https://docs.olivetin.app/upgrade/2k3k.html
|
||||
|
||||
## OliveTin *is* a remote code execution (RCE) "tool"
|
||||
|
||||
The very purpose of OliveTin is to allow users to execute commands remotely on a machine.
|
||||
|
||||
This means that, by design, OliveTin has much higher potential to be used for remote code execution (RCE), and any security vulnerabilities that do occur have the potential to be much more severe than in other types of software.
|
||||
|
||||
We hope that you understand that while the project goes to great aims to be safe, and mitigate, that security vulnerabilities are inevitable, as they are with all software of all sizes - like Kubernetes, the Kernel, etc - and OliveTin has substantially less resources than those projects.
|
||||
|
||||
With that being said, OliveTin tries to follow examples of best practice, so judge the project not on if/when it has security issues, but how security issues are responded to as the measure of quality.
|
||||
|
||||
This is why we take security very seriously, and why we encourage responsible disclosure practices when reporting vulnerabilities.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Please use responsible disclosure practices when reporting a vulnerability. **You will receive full credit for your discovery**, and we will work with you to ensure that the issue is resolved as quickly as **possible**. Please note that only James Read has access to security issues at the moment, so please be patient and understanding if you do not receive an immediate response.
|
||||
|
||||
* **Option A (preferred)**: GitHub Security Advisories, which allows you to report a vulnerability privately and securely. Use this direct link to report privately: `https://github.com/OliveTin/OliveTin/security/advisories/new`. This allows you to provide details without making them public.
|
||||
|
||||
* **Option B**: Please email `contact@jread.com` for responsible disclosure.
|
||||
|
||||
The following notes might be helpful when reporting a vulnerability:
|
||||
|
||||
* OliveTin does not offer a bug bounty program.
|
||||
* GitHub usernames are how we you will be credited for discoveries reported via GitHub, if using emails we'll ask for your preferred name/handle to credit you with.
|
||||
* CVEs will be requested via GitHub Security Advisories when appropriate, but we do not guarantee that all vulnerabilities will receive CVEs, as this is determined on a case-by-case basis.
|
||||
|
||||
## Feature flags (alpha / experimental)
|
||||
|
||||
OliveTin uses global `features.*` flags in `config.yaml` to ship unfinished or experimental functionality.
|
||||
|
||||
* **All feature flags default to off.** Enabling a flag is an explicit operator choice.
|
||||
* Functionality behind a feature flag is **alpha / experimental** until the flag is removed or the feature is graduated to a stable, default-on product surface.
|
||||
* Private security reports **are accepted** for vulnerabilities that affect feature-flagged (alpha) functionality when that flag is enabled. Use Option A or B above; do not file a public issue that discloses exploit details.
|
||||
* Reports that affect **stable, non-flagged** code paths remain in scope under this policy, even if a feature flag exists elsewhere in the project.
|
||||
|
||||
Operators who enable experimental features should treat them as preview software and avoid relying on them in high-assurance production deployments.
|
||||
|
||||
## Disclosure of how vulnerabilities were found
|
||||
|
||||
It is incredibly useful to not just patch security vulnerabilities, but also to understand how they were found. If you are able to share this information, it can help us and the community to better understand potential attack vectors and improve the overall security of the project.
|
||||
|
||||
## Duplicate reports
|
||||
|
||||
If you are reporting via GitHub Security Advisories, search existing [repository advisories](https://github.com/OliveTin/OliveTin/security/advisories) for the same component and attack path before filing. Maintainers may close duplicate submissions and continue work on a single canonical advisory; duplicate reporters are still credited.
|
||||
|
||||
Maintainers: see [.github/SECURITY_ADVISORY_DUPLICATES.md](.github/SECURITY_ADVISORY_DUPLICATES.md) for known duplicate pairs, triage steps, and OAuth2 issues that are easy to confuse with each other.
|
||||
|
||||
## Process
|
||||
|
||||
Once a vulnerability is reported, the process is;
|
||||
|
||||
* Check [.github/SECURITY_ADVISORY_DUPLICATES.md](.github/SECURITY_ADVISORY_DUPLICATES.md) and open advisories for duplicates before accepting.
|
||||
* Accept or reject the report, and communicate with the reporter about next steps.
|
||||
* If accepted, patch using a temporary branch, and code review will be requested from the original reporter if they are interested.
|
||||
* The severity of the vulnerability will be assessed using CVSS, and the patch will be prioritised accordingly.
|
||||
* Once the patch is ready, it will be queued for a release onto the `next` branch (3k) or `release/2k` branch (2k)
|
||||
* The reporter will be credited in the advisory and the release notes, but not the commit message.
|
||||
* The commit message will contain a reference to the CVSS score (eg: MED) and the advisory ID.
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
version: "3"
|
||||
|
||||
vars:
|
||||
IMAGE: docker.med-logic.ru/olivetin:latest
|
||||
|
||||
tasks:
|
||||
default:
|
||||
desc: Build docker.med-logic.ru/olivetin:latest
|
||||
cmds:
|
||||
- task: build
|
||||
|
||||
webui-dist:
|
||||
desc: Build frontend into ./webui
|
||||
cmds:
|
||||
- make webui-dist
|
||||
|
||||
binary:
|
||||
desc: Cross-compile OliveTin for linux/amd64
|
||||
dir: service
|
||||
cmds:
|
||||
- GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o ../OliveTin .
|
||||
|
||||
build:
|
||||
desc: Build docker.med-logic.ru/olivetin:latest (linux/amd64)
|
||||
cmds:
|
||||
- task: webui-dist
|
||||
- task: binary
|
||||
- docker build --pull=false --platform linux/amd64 -f Dockerfile.singlearch -t {{.IMAGE}} .
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
define delete-files
|
||||
python -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
|
||||
python3 -c "import shutil;shutil.rmtree('$(1)', ignore_errors=True)"
|
||||
endef
|
||||
|
||||
codestyle:
|
||||
|
|
|
|||
|
|
@ -20,21 +20,9 @@ import App from './resources/vue/App.vue'
|
|||
import { initWebsocket } from './js/websocket.js'
|
||||
import combinedTranslations from '../lang/combined_output.json'
|
||||
|
||||
function getSelectedLanguage () {
|
||||
const storedLanguage = localStorage.getItem('olivetin-language')
|
||||
const DEFAULT_LOCALE = 'ru'
|
||||
|
||||
if (storedLanguage && storedLanguage !== 'auto') {
|
||||
return storedLanguage
|
||||
}
|
||||
|
||||
if (storedLanguage === 'auto') {
|
||||
localStorage.removeItem('olivetin-language')
|
||||
}
|
||||
|
||||
if (navigator.languages && navigator.languages.length > 0) {
|
||||
const available = Object.keys(combinedTranslations.messages || {})
|
||||
|
||||
for (const candidate of navigator.languages) {
|
||||
function matchAvailableLocale (candidate, available) {
|
||||
const lowerCandidate = candidate.toLowerCase()
|
||||
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
|
||||
|
||||
|
|
@ -42,15 +30,35 @@ function getSelectedLanguage () {
|
|||
return exact
|
||||
}
|
||||
|
||||
const prefix = available.find(locale => locale.toLowerCase().startsWith(lowerCandidate.split('-')[0] + '-'))
|
||||
const langPrefix = lowerCandidate.split('-')[0]
|
||||
const languageOnly = available.find(locale => locale.toLowerCase() === langPrefix)
|
||||
|
||||
if (prefix) {
|
||||
return prefix
|
||||
if (languageOnly) {
|
||||
return languageOnly
|
||||
}
|
||||
|
||||
return available.find(locale => locale.toLowerCase().startsWith(langPrefix + '-')) || null
|
||||
}
|
||||
|
||||
function getSelectedLanguage () {
|
||||
const storedLanguage = localStorage.getItem('olivetin-language')
|
||||
const available = Object.keys(combinedTranslations.messages || {})
|
||||
|
||||
if (storedLanguage && storedLanguage !== 'auto' && available.includes(storedLanguage)) {
|
||||
return storedLanguage
|
||||
}
|
||||
|
||||
if (storedLanguage === 'auto' && navigator.languages && navigator.languages.length > 0) {
|
||||
for (const candidate of navigator.languages) {
|
||||
const matched = matchAvailableLocale(candidate, available)
|
||||
|
||||
if (matched) {
|
||||
return matched
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'en'
|
||||
return DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
async function initClient () {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { ref, onMounted, computed, watch, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Sidebar from 'picocrank/vue/components/Sidebar.vue'
|
||||
import Navigation from 'picocrank/vue/components/Navigation.vue'
|
||||
|
|
@ -210,7 +210,7 @@ import logoUrl from '../../OliveTinLogo.png'
|
|||
import { useI18n } from 'vue-i18n'
|
||||
import combinedTranslations from '../../../lang/combined_output.json'
|
||||
import { searchIndexItems, clearSearchIndex, indexSystemNavigation, indexSearchHints, indexRootDashboardEntries } from './stores/searchIndex.js'
|
||||
const { t } = useI18n()
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
|
|
@ -236,8 +236,9 @@ const headerSearchEnabled = ref(false)
|
|||
const languageDialog = ref(null)
|
||||
const browserLanguages = ref([])
|
||||
|
||||
const DEFAULT_LOCALE = 'ru'
|
||||
const initialLanguagePreference = typeof window !== 'undefined' ? localStorage.getItem('olivetin-language') : null
|
||||
const languagePreference = ref(initialLanguagePreference || 'auto')
|
||||
const languagePreference = ref(initialLanguagePreference || DEFAULT_LOCALE)
|
||||
const selectedLanguage = ref(languagePreference.value)
|
||||
|
||||
const themeDialog = ref(null)
|
||||
|
|
@ -248,12 +249,9 @@ const selectedTheme = ref(themePreference.value)
|
|||
|
||||
// Available languages with display names
|
||||
const availableLanguages = {
|
||||
auto: 'Browser Language',
|
||||
en: 'English',
|
||||
'de-DE': 'Deutsch',
|
||||
'es-ES': 'Español',
|
||||
'it-IT': 'Italiano',
|
||||
'zh-Hans-CN': '简体中文'
|
||||
auto: 'Язык браузера',
|
||||
ru: 'Русский',
|
||||
en: 'English'
|
||||
}
|
||||
|
||||
// Computed property to get current language display name
|
||||
|
|
@ -289,21 +287,25 @@ function normalizeBrowserLanguage () {
|
|||
for (const candidate of navigator.languages) {
|
||||
const lowerCandidate = candidate.toLowerCase()
|
||||
|
||||
// Try exact match (case-insensitive)
|
||||
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
|
||||
if (exact) {
|
||||
return exact
|
||||
}
|
||||
|
||||
// Try prefix match (e.g., "zh-CN" -> "zh-Hans-CN")
|
||||
const prefix = available.find(locale => locale.toLowerCase().startsWith(lowerCandidate.split('-')[0] + '-'))
|
||||
const langPrefix = lowerCandidate.split('-')[0]
|
||||
const languageOnly = available.find(locale => locale.toLowerCase() === langPrefix)
|
||||
if (languageOnly) {
|
||||
return languageOnly
|
||||
}
|
||||
|
||||
const prefix = available.find(locale => locale.toLowerCase().startsWith(langPrefix + '-'))
|
||||
if (prefix) {
|
||||
return prefix
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'en'
|
||||
return DEFAULT_LOCALE
|
||||
}
|
||||
|
||||
function toggleSidebar () {
|
||||
|
|
@ -312,6 +314,19 @@ function toggleSidebar () {
|
|||
}
|
||||
}
|
||||
|
||||
function applySidebarTitle () {
|
||||
const heading = document.querySelector('.sidebar h2')
|
||||
if (!heading) {
|
||||
return
|
||||
}
|
||||
heading.textContent = t('nav.navigation')
|
||||
}
|
||||
|
||||
watch([locale, sidebarEnabled, showNavigation], async () => {
|
||||
await nextTick()
|
||||
applySidebarTitle()
|
||||
}, { immediate: true })
|
||||
|
||||
function updateHeaderFromInit () {
|
||||
if (!window.initResponse) {
|
||||
return
|
||||
|
|
@ -505,7 +520,7 @@ function changeLanguage () {
|
|||
}
|
||||
|
||||
if (selectedLanguage.value === 'auto') {
|
||||
localStorage.removeItem('olivetin-language')
|
||||
localStorage.setItem('olivetin-language', 'auto')
|
||||
languagePreference.value = 'auto'
|
||||
window.i18n.locale.value = normalizeBrowserLanguage()
|
||||
} else {
|
||||
|
|
@ -617,6 +632,10 @@ onMounted(() => {
|
|||
if (typeof navigator !== 'undefined' && Array.isArray(navigator.languages)) {
|
||||
browserLanguages.value = navigator.languages
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
applySidebarTitle()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<div class="section-header">
|
||||
<h2>
|
||||
<span class="section-title-with-icon">
|
||||
Start action:
|
||||
<ActionIconGlyph
|
||||
v-if="icon"
|
||||
class="action-title-icon"
|
||||
|
|
@ -120,14 +119,14 @@
|
|||
type="submit"
|
||||
:disabled="!formReady || (hasConfirmation && !confirmationChecked)"
|
||||
>
|
||||
Start
|
||||
{{ t('action.start') }}
|
||||
</button>
|
||||
<button
|
||||
name="cancel"
|
||||
type="button"
|
||||
@click="handleCancel"
|
||||
>
|
||||
Cancel
|
||||
{{ t('action.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -138,6 +137,7 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount, onUnmounted, nextTick } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { requestReconnectNow } from '../../../js/websocket.js'
|
||||
import ChoiceCombobox from '../components/ChoiceCombobox.vue'
|
||||
import ChoiceChecklist from '../components/ChoiceChecklist.vue'
|
||||
|
|
@ -154,6 +154,7 @@ import {
|
|||
} from '../utils/argumentFieldIds.js'
|
||||
import { getInitialArgumentValue, readPrefilledArgumentsFromNavigation } from '../utils/prefilledArguments.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
// Reactive data
|
||||
|
|
|
|||
|
|
@ -22,89 +22,6 @@
|
|||
</template>
|
||||
</Table>
|
||||
</Section>
|
||||
|
||||
<Section :title="t('diagnostics.get-support')">
|
||||
<p>
|
||||
{{ t('diagnostics.get-support-description') }}
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
href="https://docs.olivetin.app/troubleshooting/wheretofindhelp.html"
|
||||
target="_blank"
|
||||
>{{ t('diagnostics.where-to-find-help') }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</Section>
|
||||
|
||||
<Section :title="t('diagnostics.ssh')">
|
||||
<dl>
|
||||
<dt>{{ t('diagnostics.found-key') }}</dt>
|
||||
<dd>{{ diagnostics.sshFoundKey || '?' }}</dd>
|
||||
<dt>{{ t('diagnostics.found-config') }}</dt>
|
||||
<dd>{{ diagnostics.sshFoundConfig || '?' }}</dd>
|
||||
</dl>
|
||||
</Section>
|
||||
|
||||
<Section :title="t('diagnostics.server-diagnostics')">
|
||||
<p>{{ t('diagnostics.server-diagnostics-description') }}</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://docs.olivetin.app/troubleshooting/server-diagnostics.html"
|
||||
target="_blank"
|
||||
>{{ t('diagnostics.server-diagnostics-docs') }}</a>
|
||||
</p>
|
||||
|
||||
<div role="toolbar">
|
||||
<button
|
||||
:disabled="loading"
|
||||
class="good"
|
||||
@click="generateServerDiagnostics"
|
||||
>
|
||||
{{ t('diagnostics.generate-server-diagnostics') }}
|
||||
</button>
|
||||
<button
|
||||
:disabled="!serverDiagnostics || loading"
|
||||
:class="serverDiagnosticsCopied ? 'good' : ''"
|
||||
@click="copyServerDiagnostics"
|
||||
>
|
||||
{{ serverDiagnosticsCopied ? t('diagnostics.copied') : t('diagnostics.copy-to-clipboard') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
v-model="serverDiagnostics"
|
||||
readonly
|
||||
style="flex: 1; min-height: 200px; resize: vertical; width: 100%; box-sizing: border-box;"
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section :title="t('diagnostics.browser-info')">
|
||||
<p>{{ t('diagnostics.browser-info-description') }}</p>
|
||||
|
||||
<div role="toolbar">
|
||||
<button
|
||||
:disabled="loading"
|
||||
class="good"
|
||||
@click="generateBrowserInfo"
|
||||
>
|
||||
{{ t('diagnostics.generate-browser-info') }}
|
||||
</button>
|
||||
<button
|
||||
:disabled="!browserInfo || loading"
|
||||
:class="browserInfoCopied ? 'good' : ''"
|
||||
@click="copyBrowserInfo"
|
||||
>
|
||||
{{ browserInfoCopied ? t('diagnostics.copied') : t('diagnostics.copy-to-clipboard') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<textarea
|
||||
v-model="browserInfo"
|
||||
readonly
|
||||
style="flex: 1; min-height: 200px; resize: vertical; width: 100%; box-sizing: border-box;"
|
||||
/>
|
||||
</Section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
|
@ -113,15 +30,10 @@ import Section from 'picocrank/vue/components/Section.vue'
|
|||
import Table from 'picocrank/vue/components/Table.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t, locale } = useI18n()
|
||||
const { t } = useI18n()
|
||||
|
||||
const diagnostics = ref({})
|
||||
const configIssues = ref([])
|
||||
const loading = ref(false)
|
||||
const serverDiagnostics = ref('')
|
||||
const browserInfo = ref('')
|
||||
const serverDiagnosticsCopied = ref(false)
|
||||
const browserInfoCopied = ref(false)
|
||||
|
||||
const configIssueHeaders = computed(() => [
|
||||
{ key: 'severity', label: t('diagnostics.config-issue-severity'), sortable: true, width: '7rem' },
|
||||
|
|
@ -148,167 +60,14 @@ async function fetchDiagnostics () {
|
|||
|
||||
try {
|
||||
const response = await window.client.getDiagnostics()
|
||||
diagnostics.value = {
|
||||
sshFoundKey: response.SshFoundKey,
|
||||
sshFoundConfig: response.SshFoundConfig
|
||||
}
|
||||
configIssues.value = response.configIssues || []
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch diagnostics:', err)
|
||||
diagnostics.value = {
|
||||
sshFoundKey: t('diagnostics.unknown'),
|
||||
sshFoundConfig: t('diagnostics.unknown')
|
||||
}
|
||||
configIssues.value = []
|
||||
}
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
async function generateServerDiagnostics () {
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
const response = await window.client.serverDiagnostics()
|
||||
console.log('response', response)
|
||||
serverDiagnostics.value = `\`\`\`\n${response.alert}\n\`\`\`\n`
|
||||
} catch (err) {
|
||||
console.error('Failed to generate server diagnostics:', err)
|
||||
serverDiagnostics.value = ''
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function copyServerDiagnostics () {
|
||||
try {
|
||||
await navigator.clipboard.writeText(serverDiagnostics.value)
|
||||
serverDiagnosticsCopied.value = true
|
||||
setTimeout(() => {
|
||||
serverDiagnosticsCopied.value = false
|
||||
}, 2000)
|
||||
} catch (err) {
|
||||
console.error('Failed to copy Server Diagnostics to clipboard:', err)
|
||||
}
|
||||
}
|
||||
|
||||
async function generateBrowserInfo () {
|
||||
loading.value = true
|
||||
try {
|
||||
let userAgentData = 'N/A'
|
||||
if (navigator.userAgentData) {
|
||||
try {
|
||||
const uaData = await navigator.userAgentData.getHighEntropyValues([
|
||||
'platform',
|
||||
'platformVersion',
|
||||
'architecture',
|
||||
'model',
|
||||
'uaFullVersion',
|
||||
'bitness',
|
||||
'fullVersionList'
|
||||
])
|
||||
userAgentData = JSON.stringify(uaData, null, 2)
|
||||
} catch (err) {
|
||||
userAgentData = `${t('diagnostics.useragent-data-error')}: ${err.message}`
|
||||
}
|
||||
}
|
||||
|
||||
const info = {
|
||||
userAgent: navigator.userAgent,
|
||||
platform: navigator.platform,
|
||||
language: navigator.language,
|
||||
languages: navigator.languages?.join(', ') || 'N/A',
|
||||
cookieEnabled: navigator.cookieEnabled,
|
||||
onLine: navigator.onLine,
|
||||
screenWidth: screen.width,
|
||||
screenHeight: screen.height,
|
||||
screenColorDepth: screen.colorDepth,
|
||||
screenPixelDepth: screen.pixelDepth,
|
||||
viewportWidth: window.innerWidth,
|
||||
viewportHeight: window.innerHeight,
|
||||
devicePixelRatio: window.devicePixelRatio || 'N/A',
|
||||
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
||||
timezoneOffset: new Date().getTimezoneOffset(),
|
||||
localStorageEnabled: (() => {
|
||||
try {
|
||||
localStorage.setItem('test', 'test')
|
||||
localStorage.removeItem('test')
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})(),
|
||||
sessionStorageEnabled: (() => {
|
||||
try {
|
||||
sessionStorage.setItem('test', 'test')
|
||||
sessionStorage.removeItem('test')
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
})(),
|
||||
hardwareConcurrency: navigator.hardwareConcurrency || 'N/A',
|
||||
maxTouchPoints: navigator.maxTouchPoints || 'N/A',
|
||||
userAgentData
|
||||
}
|
||||
|
||||
const showVersionNumber = window.initResponse?.effectivePolicy?.showVersionNumber ?? true
|
||||
const olivetinVersion = showVersionNumber
|
||||
? (window.initResponse?.currentVersion || t('diagnostics.unknown'))
|
||||
: '[hidden]'
|
||||
const currentLanguage = locale.value || t('diagnostics.unknown')
|
||||
|
||||
let output = ''
|
||||
output += '```\n'
|
||||
output += '### BROWSER INFO START (copy all text to BROWSER INFO END)\n'
|
||||
output += '# OliveTin Information\n'
|
||||
output += `olivetinVersion: ${olivetinVersion}\n`
|
||||
output += `currentLanguage: ${currentLanguage}\n`
|
||||
output += '\n# Browser Information\n'
|
||||
output += `userAgent: ${info.userAgent}\n`
|
||||
output += `platform: ${info.platform}\n`
|
||||
output += `language: ${info.language}\n`
|
||||
output += `languages: ${info.languages}\n`
|
||||
output += '\n# User Agent Data\n'
|
||||
output += `userAgentData:\n${info.userAgentData}\n`
|
||||
output += '\n# Display Information\n'
|
||||
output += `screenWidth: ${info.screenWidth}\n`
|
||||
output += `screenHeight: ${info.screenHeight}\n`
|
||||
output += `screenColorDepth: ${info.screenColorDepth}\n`
|
||||
output += `screenPixelDepth: ${info.screenPixelDepth}\n`
|
||||
output += `viewportWidth: ${info.viewportWidth}\n`
|
||||
output += `viewportHeight: ${info.viewportHeight}\n`
|
||||
output += `devicePixelRatio: ${info.devicePixelRatio}\n`
|
||||
output += '\n# Feature Support\n'
|
||||
output += `cookieEnabled: ${info.cookieEnabled}\n`
|
||||
output += `localStorageEnabled: ${info.localStorageEnabled}\n`
|
||||
output += `sessionStorageEnabled: ${info.sessionStorageEnabled}\n`
|
||||
output += `onLine: ${info.onLine}\n`
|
||||
output += `hardwareConcurrency: ${info.hardwareConcurrency}\n`
|
||||
output += `maxTouchPoints: ${info.maxTouchPoints}\n`
|
||||
output += '\n# Location & Time\n'
|
||||
output += `timezone: ${info.timezone}\n`
|
||||
output += `timezoneOffset: ${info.timezoneOffset}\n`
|
||||
output += '\n### BROWSER INFO END (copy all text from BROWSER INFO START)'
|
||||
output += '\n```\n'
|
||||
|
||||
browserInfo.value = output
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function copyBrowserInfo () {
|
||||
try {
|
||||
await navigator.clipboard.writeText(browserInfo.value)
|
||||
browserInfoCopied.value = true
|
||||
setTimeout(() => {
|
||||
browserInfoCopied.value = false
|
||||
}, 2000)
|
||||
} catch (err) {
|
||||
console.error('Failed to copy browser info to clipboard:', err)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchDiagnostics()
|
||||
window.addEventListener('EventConfigChanged', fetchDiagnostics)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<Section id="execution-results-popup">
|
||||
<template #title>
|
||||
<span class="section-title-with-icon">
|
||||
Execution Results:
|
||||
{{ t('execution.results') }}
|
||||
<router-link
|
||||
v-if="actionId"
|
||||
:to="`/action/${actionId}`"
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
<button
|
||||
v-for="dashboard in backToDashboards"
|
||||
:key="dashboard.path"
|
||||
:title="'Back to ' + dashboard.title"
|
||||
:title="t('execution.back-to', { title: dashboard.title })"
|
||||
class="button neutral"
|
||||
@click="goToDashboard(dashboard.path)"
|
||||
>
|
||||
|
|
@ -43,12 +43,12 @@
|
|||
</button>
|
||||
<button
|
||||
v-if="backToDashboards.length === 0"
|
||||
title="Go back"
|
||||
:title="t('execution.back')"
|
||||
class="button neutral"
|
||||
@click="goBack"
|
||||
>
|
||||
<HugeiconsIcon :icon="ArrowLeftIcon" />
|
||||
Back
|
||||
{{ t('execution.back') }}
|
||||
</button>
|
||||
</template>
|
||||
|
||||
|
|
@ -57,10 +57,10 @@
|
|||
class="flex-row"
|
||||
>
|
||||
<dl class="fg1">
|
||||
<dt>Duration</dt>
|
||||
<dt>{{ t('execution.duration') }}</dt>
|
||||
<dd>{{ duration }}</dd>
|
||||
|
||||
<dt>Status</dt>
|
||||
<dt>{{ t('execution.status') }}</dt>
|
||||
<dd class="execution-dialog-status">
|
||||
<ActionStatusDisplay
|
||||
:log-entry="logEntry"
|
||||
|
|
@ -74,13 +74,13 @@
|
|||
v-if="notFound"
|
||||
class="error-message padded-content"
|
||||
>
|
||||
<h3>Execution Not Found</h3>
|
||||
<h3>{{ t('execution.not-found') }}</h3>
|
||||
<p>{{ errorMessage }}</p>
|
||||
<p>The execution with ID <code>{{ executionTrackingId }}</code> could not be found.</p>
|
||||
<p>{{ t('execution.not-found-id') }} <code>{{ executionTrackingId }}</code>.</p>
|
||||
<router-link to="/logs">
|
||||
View all logs
|
||||
</router-link> or <router-link to="/">
|
||||
return to home
|
||||
{{ t('execution.view-logs') }}
|
||||
</router-link> {{ t('execution.or') }} <router-link to="/">
|
||||
{{ t('execution.return-home') }}
|
||||
</router-link>.
|
||||
</div>
|
||||
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
<button
|
||||
type="button"
|
||||
class="xterm-overlay-button"
|
||||
title="Copy to clipboard"
|
||||
:title="t('execution.copy')"
|
||||
@click="copyOutput"
|
||||
>
|
||||
<HugeiconsIcon :icon="Copy01Icon" />
|
||||
|
|
@ -97,7 +97,7 @@
|
|||
<button
|
||||
type="button"
|
||||
class="xterm-overlay-button"
|
||||
title="Toggle fullscreen"
|
||||
:title="t('execution.fullscreen')"
|
||||
@click="toggleSize"
|
||||
>
|
||||
<svg
|
||||
|
|
@ -123,20 +123,20 @@
|
|||
|
||||
<button
|
||||
:disabled="!canRerun"
|
||||
title="Rerun"
|
||||
:title="t('execution.rerun')"
|
||||
@click="rerunAction"
|
||||
>
|
||||
<HugeiconsIcon :icon="WorkoutRunIcon" />
|
||||
Rerun
|
||||
{{ t('execution.rerun') }}
|
||||
</button>
|
||||
<button
|
||||
id="execution-dialog-kill-action"
|
||||
:disabled="!canKill"
|
||||
title="Kill"
|
||||
:title="t('execution.kill')"
|
||||
@click="killAction"
|
||||
>
|
||||
<HugeiconsIcon :icon="Cancel02Icon" />
|
||||
Kill
|
||||
{{ t('execution.kill') }}
|
||||
</button>
|
||||
</div>
|
||||
</Section>
|
||||
|
|
@ -144,6 +144,7 @@
|
|||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import ActionIconGlyph from '../components/ActionIconGlyph.vue'
|
||||
import ActionStatusDisplay from '../components/ActionStatusDisplay.vue'
|
||||
import LogActionTitle from '../components/LogActionTitle.vue'
|
||||
|
|
@ -160,6 +161,7 @@ import {
|
|||
rerunNeedsArgumentForm
|
||||
} from '../utils/rerunArguments.js'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
// Refs for DOM elements
|
||||
|
|
@ -178,7 +180,7 @@ const hideDetails = ref(false)
|
|||
const hideDetailsOnResult = ref(false)
|
||||
const executionSeconds = ref(0)
|
||||
const icon = ref('')
|
||||
const title = ref('Waiting for result...')
|
||||
const title = ref(t('execution.waiting'))
|
||||
const titleTooltip = ref('')
|
||||
const duration = ref('')
|
||||
const logEntry = ref(null)
|
||||
|
|
@ -237,7 +239,7 @@ async function reset () {
|
|||
hideDetailsOnResult.value = false
|
||||
|
||||
icon.value = ''
|
||||
title.value = 'Waiting for result...'
|
||||
title.value = t('execution.waiting')
|
||||
titleTooltip.value = ''
|
||||
duration.value = ''
|
||||
|
||||
|
|
@ -349,7 +351,7 @@ async function fetchExecutionResult (executionTrackingIdParam) {
|
|||
// Check if it's a "not found" error (404 or similar)
|
||||
if (err.status === 404 || err.code === 'NotFound' || err.message?.includes('not found')) {
|
||||
notFound.value = true
|
||||
errorMessage.value = err.message || 'The execution could not be found in the system.'
|
||||
errorMessage.value = err.message || t('execution.not-found-generic')
|
||||
} else {
|
||||
renderError(err)
|
||||
}
|
||||
|
|
@ -360,7 +362,7 @@ async function fetchExecutionResult (executionTrackingIdParam) {
|
|||
function updateDuration (logEntryParam) {
|
||||
logEntry.value = logEntryParam
|
||||
if (logEntry.value == null) {
|
||||
duration.value = executionSeconds.value + ' seconds'
|
||||
duration.value = t('execution.seconds', { n: executionSeconds.value })
|
||||
} else if (!logEntry.value.executionStarted) {
|
||||
duration.value = logEntry.value.datetimeStarted + ' (request time). Not executed.'
|
||||
} else if (logEntry.value.executionStarted && !logEntry.value.executionFinished) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<Section
|
||||
title="Login to OliveTin"
|
||||
:title="t('login.title')"
|
||||
class="small"
|
||||
>
|
||||
<div class="login-form">
|
||||
|
|
@ -8,14 +8,14 @@
|
|||
v-if="!hasOAuth && !hasLocalLogin"
|
||||
class="login-disabled"
|
||||
>
|
||||
<span>This server is not configured with either OAuth, or local users, so you cannot login.</span>
|
||||
<span>{{ t('login.disabled') }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="hasOAuth"
|
||||
class="login-oauth2"
|
||||
>
|
||||
<h3>OAuth Login</h3>
|
||||
<h3>{{ t('login.oauth') }}</h3>
|
||||
<div class="oauth-providers">
|
||||
<button
|
||||
v-for="provider in oauthProviders"
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
/>
|
||||
<span v-else>{{ providerIcon(provider).text }}</span>
|
||||
</span>
|
||||
<span class="provider-name">Login with {{ provider.title }}</span>
|
||||
<span class="provider-name">{{ t('login.oauth-with', { provider: provider.title }) }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -42,7 +42,6 @@
|
|||
v-if="hasLocalLogin"
|
||||
class="login-local"
|
||||
>
|
||||
<h3>Local Login</h3>
|
||||
<form
|
||||
class="local-login-form"
|
||||
@submit.prevent="handleLocalLogin"
|
||||
|
|
@ -61,7 +60,7 @@
|
|||
name="username"
|
||||
autocomplete="username"
|
||||
required
|
||||
placeholder="Username"
|
||||
:placeholder="t('login.username')"
|
||||
>
|
||||
<input
|
||||
id="password"
|
||||
|
|
@ -69,7 +68,7 @@
|
|||
type="password"
|
||||
name="password"
|
||||
autocomplete="current-password"
|
||||
placeholder="Password"
|
||||
:placeholder="t('login.password')"
|
||||
required
|
||||
>
|
||||
|
||||
|
|
@ -78,7 +77,7 @@
|
|||
:disabled="loading"
|
||||
class="login-button"
|
||||
>
|
||||
{{ loading ? 'Logging in...' : 'Login' }}
|
||||
{{ loading ? t('login.submitting') : t('login.submit') }}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -90,7 +89,9 @@
|
|||
import { ref, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import Section from 'picocrank/vue/components/Section.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const router = useRouter()
|
||||
|
||||
const username = ref('')
|
||||
|
|
@ -177,11 +178,11 @@ async function handleLocalLogin () {
|
|||
// Redirect to home page on successful login
|
||||
router.push('/')
|
||||
} else {
|
||||
loginError.value = 'Login failed. Please check your credentials.'
|
||||
loginError.value = t('login.failed')
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Login error:', err)
|
||||
loginError.value = err.message || 'Network error. Please try again.'
|
||||
loginError.value = err.message || t('login.network-error')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,98 +1,9 @@
|
|||
{
|
||||
"_comment": "This file is generated. Please re-generate this file using 'make' when you update a translation.",
|
||||
"messages": {
|
||||
"de-DE": {
|
||||
"connected": "Verbunden",
|
||||
"diagnostics.browser-info": "Browser-Informationen",
|
||||
"diagnostics.browser-info-description": "Dieser Abschnitt ermöglicht es Ihnen, einen detaillierten Bericht über Ihre Browser-Informationen zu erstellen. Dies kann bei der Fehlerbehebung von browser-spezifischen Problemen hilfreich sein.",
|
||||
"diagnostics.config-issue-action": "Aktion",
|
||||
"diagnostics.config-issue-argument": "Argument",
|
||||
"diagnostics.config-issue-code": "Code",
|
||||
"diagnostics.config-issue-config-file": "Konfigurationsdatei",
|
||||
"diagnostics.config-issue-detail": "Detail",
|
||||
"diagnostics.config-issue-message": "Meldung",
|
||||
"diagnostics.config-issue-severity": "Schweregrad",
|
||||
"diagnostics.config-issue-source": "Quelle",
|
||||
"diagnostics.config-issues": "Konfigurationsprobleme",
|
||||
"diagnostics.config-issues-description": "In der aktuellen OliveTin-Konfiguration erkannte Probleme. Beheben Sie diese in Ihren Konfigurationsdateien und laden Sie OliveTin neu.",
|
||||
"diagnostics.config-issues-none": "Keine Konfigurationsprobleme erkannt.",
|
||||
"diagnostics.copied": "Kopiert!",
|
||||
"diagnostics.copy-to-clipboard": "In Zwischenablage kopieren",
|
||||
"diagnostics.found-config": "Konfiguration gefunden",
|
||||
"diagnostics.found-key": "Schlüssel gefunden",
|
||||
"diagnostics.generate-browser-info": "Browser-Informationen erstellen",
|
||||
"diagnostics.generate-server-diagnostics": "Server-Diagnostik erstellen",
|
||||
"diagnostics.get-support": "Unterstützung erhalten",
|
||||
"diagnostics.get-support-description": "Wenn Sie Probleme mit OliveTin haben und eine Support-Anfrage stellen möchten, wäre es sehr hilfreich, Server-Diagnostik von dieser Seite einzufügen.",
|
||||
"diagnostics.server-diagnostics": "Server-Diagnostik",
|
||||
"diagnostics.server-diagnostics-description": "Dieser Abschnitt ermöglicht es Ihnen, einen detaillierten Bericht über Ihre Konfiguration und Umgebung zu erstellen. Es ist eine gute Idee, dies bei einer Support-Anfrage einzufügen.",
|
||||
"diagnostics.server-diagnostics-docs": "Server-Diagnostik-Dokumentation",
|
||||
"diagnostics.ssh": "SSH",
|
||||
"diagnostics.unknown": "Unbekannt",
|
||||
"diagnostics.useragent-data-error": "Fehler beim Abrufen von userAgentData",
|
||||
"diagnostics.where-to-find-help": "Wo Sie Hilfe finden",
|
||||
"disconnected": "Getrennt",
|
||||
"disconnected-banner-announcement": "Events-Websocket getrennt.",
|
||||
"disconnected-banner-link-text": "Events-Websocket getrennt",
|
||||
"disconnected-banner-suffix": " seit {disconnectedSince}. Erneuter Verbindungsversuch in {reconnectIn}.",
|
||||
"disconnected-banner-suffix-reconnecting": " seit {disconnectedSince}. Verbindungsversuch…",
|
||||
"docs": "Dokumentation",
|
||||
"language-dialog.browser-languages": "Browser-Sprachen",
|
||||
"language-dialog.close": "Schließen",
|
||||
"language-dialog.not-available": "Nicht verfügbar",
|
||||
"language-dialog.title": "Sprache auswählen",
|
||||
"login-button": "Login",
|
||||
"logs.action": "Aktion",
|
||||
"logs.action-group-limits": "gleichzeitig: {concurrent}, Warteschlangengröße: {queueSize}",
|
||||
"logs.back-to-list": "Zurück zur Liste",
|
||||
"logs.blocked": "Blockiert",
|
||||
"logs.calendar": "Kalender",
|
||||
"logs.calendar-title": "Protokoll-Kalender",
|
||||
"logs.clear-date-filter": "Datumsfilter löschen",
|
||||
"logs.clear-filter": "Suchfilter löschen",
|
||||
"logs.completed": "Abgeschlossen",
|
||||
"logs.exit-code": "Ausführungscode",
|
||||
"logs.filter-error": "Filterausdruck konnte nicht angewendet werden.",
|
||||
"logs.filter-help-examples": "Beispiele: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "Felder: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operatoren: ==, !=, contains. Ein !-Präfix vor einem einzelnen Wort schließt passende Einträge aus.",
|
||||
"logs.filter-help-intro": "Filter laufen auf dem Server über Einträge, die Sie anzeigen dürfen. Kombinieren Sie Begriffe mit and / or.",
|
||||
"logs.filter-help-title": "Filtersyntax",
|
||||
"logs.filter-placeholder": "Protokolle filtern (z. B. !Update oder Status != Completed)",
|
||||
"logs.metadata": "Metadaten",
|
||||
"logs.no-logs-for-filter": "Keine Protokolle entsprechen dem aktuellen Filter.",
|
||||
"logs.no-logs-to-display": "Es gibt keine Protokolle zu anzeigen.",
|
||||
"logs.page-description": "Dies ist eine Liste von Protokollen von Aktionen, die ausgeführt wurden. Sie können die Liste nach Aktionstitel filtern.",
|
||||
"logs.queue": "Warteschlange",
|
||||
"logs.queue-action-details": "Aktionsdetails",
|
||||
"logs.queue-default-group": "Standard",
|
||||
"logs.queue-empty": "Derzeit gibt es keine aktiven oder wartenden Ausführungen.",
|
||||
"logs.queue-entity": "Entität",
|
||||
"logs.queue-group-active": "{active} aktiv (max. {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} aktiv",
|
||||
"logs.queue-page-description": "Aktive und wartende Ausführungen, nach Aktionsgruppe gruppiert. Einträge ohne Berechtigung werden ausgeblendet.",
|
||||
"logs.queue-position": "#{position}",
|
||||
"logs.queue-running": "Läuft",
|
||||
"logs.queue-title": "Ausführungswarteschlange",
|
||||
"logs.queue-waiting": "Wartend",
|
||||
"logs.status": "Status",
|
||||
"logs.timed-out": "Zeitüberschreitung",
|
||||
"logs.timestamp": "Zeitstempel",
|
||||
"logs.title": "Protokolle",
|
||||
"nav.actions": "Aktionen",
|
||||
"nav.diagnostics": "Diagnostik",
|
||||
"nav.entities": "Entitäten",
|
||||
"nav.logs": "Protokolle",
|
||||
"nav.system": "System",
|
||||
"raise-issue": "Ein Problem melden auf GitHub",
|
||||
"reconnecting": "Verbinde erneut…",
|
||||
"return-to-index": "Zurück zur Startseite",
|
||||
"search-filter": "Filter aktuelle Seite",
|
||||
"theme-dialog.close": "Schließen",
|
||||
"theme-dialog.default": "Standard-Design",
|
||||
"theme-dialog.title": "Design auswählen",
|
||||
"welcome": "Willkommen bei OliveTin"
|
||||
},
|
||||
"en": {
|
||||
"action.cancel": "Cancel",
|
||||
"action.start": "Start",
|
||||
"connected": "Connected",
|
||||
"diagnostics.browser-info": "Browser Info",
|
||||
"diagnostics.browser-info-description": "This section allows you to generate a detailed report of your browser information. This can be helpful when troubleshooting browser-specific issues.",
|
||||
|
|
@ -128,11 +39,38 @@
|
|||
"disconnected-banner-suffix": " since {disconnectedSince}. Trying reconnect in {reconnectIn}.",
|
||||
"disconnected-banner-suffix-reconnecting": " since {disconnectedSince}. Trying reconnect…",
|
||||
"docs": "Documentation",
|
||||
"execution.back": "Back",
|
||||
"execution.back-to": "Back to {title}",
|
||||
"execution.copy": "Copy to clipboard",
|
||||
"execution.duration": "Duration",
|
||||
"execution.fullscreen": "Toggle fullscreen",
|
||||
"execution.kill": "Kill",
|
||||
"execution.not-found": "Execution not found",
|
||||
"execution.not-found-generic": "The execution could not be found in the system.",
|
||||
"execution.not-found-id": "The execution with ID",
|
||||
"execution.or": "or",
|
||||
"execution.results": "Execution Results:",
|
||||
"execution.rerun": "Rerun",
|
||||
"execution.return-home": "return to home",
|
||||
"execution.seconds": "{n} seconds",
|
||||
"execution.status": "Status",
|
||||
"execution.view-logs": "View all logs",
|
||||
"execution.waiting": "Waiting for result…",
|
||||
"language-dialog.browser-languages": "Browser languages",
|
||||
"language-dialog.close": "Close",
|
||||
"language-dialog.not-available": "Not available",
|
||||
"language-dialog.title": "Select Language",
|
||||
"login-button": "Login",
|
||||
"login.disabled": "This server is not configured with either OAuth, or local users, so you cannot login.",
|
||||
"login.failed": "Login failed. Please check your credentials.",
|
||||
"login.network-error": "Network error. Please try again.",
|
||||
"login.oauth": "OAuth Login",
|
||||
"login.oauth-with": "Login with {provider}",
|
||||
"login.password": "Password",
|
||||
"login.submit": "Login",
|
||||
"login.submitting": "Logging in…",
|
||||
"login.title": "Авторизация",
|
||||
"login.username": "Username",
|
||||
"logs.action": "Action",
|
||||
"logs.action-group-limits": "concurrent: {concurrent}, queue size: {queueSize}",
|
||||
"logs.back-to-list": "Back to List",
|
||||
|
|
@ -173,6 +111,7 @@
|
|||
"nav.diagnostics": "Diagnostics",
|
||||
"nav.entities": "Entities",
|
||||
"nav.logs": "Logs",
|
||||
"nav.navigation": "Navigation",
|
||||
"nav.system": "System",
|
||||
"raise-issue": "Raise an issue on GitHub",
|
||||
"reconnecting": "Reconnecting…",
|
||||
|
|
@ -183,369 +122,126 @@
|
|||
"theme-dialog.title": "Select Theme",
|
||||
"welcome": "Welcome to OliveTin"
|
||||
},
|
||||
"es-ES": {
|
||||
"connected": "Conectado",
|
||||
"diagnostics.browser-info": "Información del navegador",
|
||||
"diagnostics.browser-info-description": "Esta sección le permite generar un informe detallado de su información del navegador. Esto puede ser útil al solucionar problemas específicos del navegador.",
|
||||
"diagnostics.config-issue-action": "Acción",
|
||||
"diagnostics.config-issue-argument": "Argumento",
|
||||
"diagnostics.config-issue-code": "Código",
|
||||
"diagnostics.config-issue-config-file": "Archivo de configuración",
|
||||
"diagnostics.config-issue-detail": "Detalle",
|
||||
"diagnostics.config-issue-message": "Mensaje",
|
||||
"diagnostics.config-issue-severity": "Severidad",
|
||||
"diagnostics.config-issue-source": "Origen",
|
||||
"diagnostics.config-issues": "Problemas de configuración",
|
||||
"diagnostics.config-issues-description": "Problemas detectados en la configuración actual de OliveTin. Corríjalos en sus archivos de configuración y vuelva a cargar OliveTin.",
|
||||
"diagnostics.config-issues-none": "No se detectaron problemas de configuración.",
|
||||
"diagnostics.copied": "¡Copiado!",
|
||||
"diagnostics.copy-to-clipboard": "Copiar al portapapeles",
|
||||
"diagnostics.found-config": "Configuración encontrada",
|
||||
"diagnostics.found-key": "Clave encontrada",
|
||||
"diagnostics.generate-browser-info": "Generar información del navegador",
|
||||
"diagnostics.generate-server-diagnostics": "Generar diagnóstico del servidor",
|
||||
"diagnostics.get-support": "Obtener soporte",
|
||||
"diagnostics.get-support-description": "Si tiene problemas con OliveTin y desea presentar una solicitud de soporte, sería muy útil incluir diagnósticos del servidor desde esta página.",
|
||||
"diagnostics.server-diagnostics": "Diagnóstico del servidor",
|
||||
"diagnostics.server-diagnostics-description": "Esta sección le permite generar un informe detallado de su configuración y entorno. Es una buena idea incluir esto al presentar una solicitud de soporte.",
|
||||
"diagnostics.server-diagnostics-docs": "Documentación de diagnóstico del servidor",
|
||||
"ru": {
|
||||
"action.cancel": "Отмена",
|
||||
"action.start": "Запустить",
|
||||
"connected": "Подключено",
|
||||
"diagnostics.browser-info": "Сведения о браузере",
|
||||
"diagnostics.browser-info-description": "Здесь можно сформировать подробный отчёт о браузере. Это помогает при проблемах, связанных с конкретным браузером.",
|
||||
"diagnostics.config-issue-action": "Действие",
|
||||
"diagnostics.config-issue-argument": "Аргумент",
|
||||
"diagnostics.config-issue-code": "Код",
|
||||
"diagnostics.config-issue-config-file": "Файл конфигурации",
|
||||
"diagnostics.config-issue-detail": "Подробности",
|
||||
"diagnostics.config-issue-message": "Сообщение",
|
||||
"diagnostics.config-issue-severity": "Важность",
|
||||
"diagnostics.config-issue-source": "Источник",
|
||||
"diagnostics.config-issues": "Проблемы конфигурации",
|
||||
"diagnostics.config-issues-description": "Обнаружены проблемы в текущей конфигурации OliveTin. Исправьте их в файлах конфигурации и перезагрузите OliveTin.",
|
||||
"diagnostics.config-issues-none": "Проблем конфигурации не обнаружено.",
|
||||
"diagnostics.copied": "Скопировано!",
|
||||
"diagnostics.copy-to-clipboard": "Копировать в буфер",
|
||||
"diagnostics.found-config": "Конфигурация найдена",
|
||||
"diagnostics.found-key": "Ключ найден",
|
||||
"diagnostics.generate-browser-info": "Сформировать сведения о браузере",
|
||||
"diagnostics.generate-server-diagnostics": "Сформировать диагностику сервера",
|
||||
"diagnostics.get-support": "Получить поддержку",
|
||||
"diagnostics.get-support-description": "Если возникли проблемы с OliveTin и вы хотите обратиться в поддержку, приложите диагностику сервера с этой страницы.",
|
||||
"diagnostics.server-diagnostics": "Диагностика сервера",
|
||||
"diagnostics.server-diagnostics-description": "Здесь можно сформировать подробный отчёт о конфигурации и окружении. Его полезно приложить к обращению в поддержку.",
|
||||
"diagnostics.server-diagnostics-docs": "Документация по диагностике сервера",
|
||||
"diagnostics.ssh": "SSH",
|
||||
"diagnostics.unknown": "Desconocido",
|
||||
"diagnostics.useragent-data-error": "Error al recuperar userAgentData",
|
||||
"diagnostics.where-to-find-help": "Dónde encontrar ayuda",
|
||||
"disconnected": "Desconectado",
|
||||
"disconnected-banner-announcement": "Websocket de eventos desconectado.",
|
||||
"disconnected-banner-link-text": "Websocket de eventos desconectado",
|
||||
"disconnected-banner-suffix": " desde {disconnectedSince}. Reintentando conexión en {reconnectIn}.",
|
||||
"disconnected-banner-suffix-reconnecting": " desde {disconnectedSince}. Reintentando conexión…",
|
||||
"docs": "Documentación",
|
||||
"language-dialog.browser-languages": "Idiomas del navegador",
|
||||
"language-dialog.close": "Cerrar",
|
||||
"language-dialog.not-available": "No disponible",
|
||||
"language-dialog.title": "Seleccionar idioma",
|
||||
"login-button": "Iniciar sesión",
|
||||
"logs.action": "Acción",
|
||||
"logs.action-group-limits": "simultáneas: {concurrent}, tamaño de cola: {queueSize}",
|
||||
"logs.back-to-list": "Volver a la Lista",
|
||||
"logs.blocked": "Bloqueado",
|
||||
"logs.calendar": "Calendario",
|
||||
"logs.calendar-title": "Calendario de Registros",
|
||||
"logs.clear-date-filter": "Limpiar filtro de fecha",
|
||||
"logs.clear-filter": "Limpiar filtro de búsqueda",
|
||||
"logs.completed": "Completado",
|
||||
"logs.exit-code": "Código de salida",
|
||||
"logs.filter-error": "No se pudo aplicar la expresión del filtro.",
|
||||
"logs.filter-help-examples": "Ejemplos: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "Campos: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operadores: ==, !=, contains. Un prefijo ! en una sola palabra excluye las entradas coincidentes.",
|
||||
"logs.filter-help-intro": "Los filtros se ejecutan en el servidor sobre las entradas que puede ver. Combine términos con and / or.",
|
||||
"logs.filter-help-title": "Sintaxis del filtro",
|
||||
"logs.filter-placeholder": "Filtrar registros (p. ej. !Update o Status != Completed)",
|
||||
"logs.metadata": "Metadatos",
|
||||
"logs.no-logs-for-filter": "Ningún registro coincide con el filtro actual.",
|
||||
"logs.no-logs-to-display": "No hay registros para mostrar.",
|
||||
"logs.page-description": "Esta es una lista de registros de acciones que han sido ejecutadas. Puede filtrar la lista por título de acción.",
|
||||
"logs.queue": "Cola",
|
||||
"logs.queue-action-details": "Detalles de la acción",
|
||||
"logs.queue-default-group": "Predeterminado",
|
||||
"logs.queue-empty": "No hay ejecuciones activas o en espera en este momento.",
|
||||
"logs.queue-entity": "Entidad",
|
||||
"logs.queue-group-active": "{active} activas (máx. {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} activas",
|
||||
"logs.queue-page-description": "Ejecuciones activas y en espera agrupadas por grupo de acciones. Las entradas que no puede ver se ocultan.",
|
||||
"diagnostics.unknown": "Неизвестно",
|
||||
"diagnostics.useragent-data-error": "Ошибка получения userAgentData",
|
||||
"diagnostics.where-to-find-help": "Где искать помощь",
|
||||
"disconnected": "Отключено",
|
||||
"disconnected-banner-announcement": "Websocket событий отключён.",
|
||||
"disconnected-banner-link-text": "Websocket событий отключён",
|
||||
"disconnected-banner-suffix": " с {disconnectedSince}. Повтор через {reconnectIn}.",
|
||||
"disconnected-banner-suffix-reconnecting": " с {disconnectedSince}. Переподключение…",
|
||||
"docs": "Документация",
|
||||
"execution.back": "Назад",
|
||||
"execution.back-to": "Назад к {title}",
|
||||
"execution.copy": "Копировать",
|
||||
"execution.duration": "Длительность",
|
||||
"execution.fullscreen": "На весь экран",
|
||||
"execution.kill": "Остановить",
|
||||
"execution.not-found": "Выполнение не найдено",
|
||||
"execution.not-found-generic": "Выполнение не найдено в системе.",
|
||||
"execution.not-found-id": "Выполнение с ID",
|
||||
"execution.or": "или",
|
||||
"execution.results": "Результаты выполнения:",
|
||||
"execution.rerun": "Повторить",
|
||||
"execution.return-home": "на главную",
|
||||
"execution.seconds": "{n} сек.",
|
||||
"execution.status": "Статус",
|
||||
"execution.view-logs": "Все журналы",
|
||||
"execution.waiting": "Ожидание результата…",
|
||||
"language-dialog.browser-languages": "Языки браузера",
|
||||
"language-dialog.close": "Закрыть",
|
||||
"language-dialog.not-available": "Недоступно",
|
||||
"language-dialog.title": "Выберите язык",
|
||||
"login-button": "Войти",
|
||||
"login.disabled": "На этом сервере не настроены ни OAuth, ни локальные пользователи, поэтому войти нельзя.",
|
||||
"login.failed": "Не удалось войти. Проверьте логин и пароль.",
|
||||
"login.network-error": "Ошибка сети. Попробуйте ещё раз.",
|
||||
"login.oauth": "Вход через OAuth",
|
||||
"login.oauth-with": "Войти через {provider}",
|
||||
"login.password": "Пароль",
|
||||
"login.submit": "Войти",
|
||||
"login.submitting": "Вход…",
|
||||
"login.title": "Авторизация",
|
||||
"login.username": "Имя пользователя",
|
||||
"logs.action": "Действие",
|
||||
"logs.action-group-limits": "параллельно: {concurrent}, размер очереди: {queueSize}",
|
||||
"logs.back-to-list": "К списку",
|
||||
"logs.blocked": "Заблокировано",
|
||||
"logs.calendar": "Календарь",
|
||||
"logs.calendar-title": "Календарь журналов",
|
||||
"logs.clear-date-filter": "Очистить фильтр по дате",
|
||||
"logs.clear-filter": "Очистить фильтр",
|
||||
"logs.completed": "Завершено",
|
||||
"logs.exit-code": "Код выхода",
|
||||
"logs.filter-error": "Не удалось применить выражение фильтра.",
|
||||
"logs.filter-help-examples": "Примеры: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "Поля: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Операторы: ==, !=, contains. Префикс ! у слова исключает совпадающие записи.",
|
||||
"logs.filter-help-intro": "Фильтры выполняются на сервере по записям, которые вам разрешено видеть. Объединяйте условия через and / or.",
|
||||
"logs.filter-help-title": "Синтаксис фильтра",
|
||||
"logs.filter-placeholder": "Фильтр журналов (например !Update или Status != Completed)",
|
||||
"logs.metadata": "Метаданные",
|
||||
"logs.no-logs-for-filter": "Нет журналов, подходящих под текущий фильтр.",
|
||||
"logs.no-logs-to-display": "Нет журналов для отображения.",
|
||||
"logs.page-description": "Список журналов выполненных действий. В поле фильтра можно вводить слова и выражения.",
|
||||
"logs.queue": "Очередь",
|
||||
"logs.queue-action-details": "Сведения о действии",
|
||||
"logs.queue-default-group": "По умолчанию",
|
||||
"logs.queue-empty": "Сейчас нет активных или ожидающих выполнений.",
|
||||
"logs.queue-entity": "Сущность",
|
||||
"logs.queue-group-active": "{active} активно (макс. {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} активно",
|
||||
"logs.queue-page-description": "Активные и ожидающие выполнения, сгруппированные по группе действий. Записи, которые вам нельзя видеть, скрыты.",
|
||||
"logs.queue-position": "#{position}",
|
||||
"logs.queue-running": "En ejecución",
|
||||
"logs.queue-title": "Cola de ejecución",
|
||||
"logs.queue-waiting": "En espera",
|
||||
"logs.status": "Estado",
|
||||
"logs.timed-out": "Tiempo agotado",
|
||||
"logs.timestamp": "Marca de tiempo",
|
||||
"logs.title": "Registros",
|
||||
"nav.actions": "Acciones",
|
||||
"nav.diagnostics": "Diagnósticos",
|
||||
"nav.entities": "Entidades",
|
||||
"nav.logs": "Registros",
|
||||
"nav.system": "Sistema",
|
||||
"raise-issue": "Reportar un problema en GitHub",
|
||||
"reconnecting": "Reconectando…",
|
||||
"return-to-index": "Volver a la página principal",
|
||||
"search-filter": "Filtrar página actual",
|
||||
"theme-dialog.close": "Cerrar",
|
||||
"theme-dialog.default": "Tema Predeterminado",
|
||||
"theme-dialog.title": "Seleccionar tema",
|
||||
"welcome": "Bienvenido a OliveTin"
|
||||
},
|
||||
"it-IT": {
|
||||
"connected": "Connesso",
|
||||
"diagnostics.browser-info": "Informazioni del browser",
|
||||
"diagnostics.browser-info-description": "Questa sezione ti consente di generare un rapporto dettagliato delle informazioni del tuo browser. Questo può essere utile durante la risoluzione dei problemi specifici del browser.",
|
||||
"diagnostics.config-issue-action": "Azione",
|
||||
"diagnostics.config-issue-argument": "Argomento",
|
||||
"diagnostics.config-issue-code": "Codice",
|
||||
"diagnostics.config-issue-config-file": "File di configurazione",
|
||||
"diagnostics.config-issue-detail": "Dettaglio",
|
||||
"diagnostics.config-issue-message": "Messaggio",
|
||||
"diagnostics.config-issue-severity": "Gravità",
|
||||
"diagnostics.config-issue-source": "Origine",
|
||||
"diagnostics.config-issues": "Problemi di configurazione",
|
||||
"diagnostics.config-issues-description": "Problemi rilevati nella configurazione corrente di OliveTin. Correggili nei file di configurazione e ricarica OliveTin.",
|
||||
"diagnostics.config-issues-none": "Nessun problema di configurazione rilevato.",
|
||||
"diagnostics.copied": "Copiato!",
|
||||
"diagnostics.copy-to-clipboard": "Copia negli appunti",
|
||||
"diagnostics.found-config": "Configurazione trovata",
|
||||
"diagnostics.found-key": "Chiave trovata",
|
||||
"diagnostics.generate-browser-info": "Genera informazioni del browser",
|
||||
"diagnostics.generate-server-diagnostics": "Genera diagnostica del server",
|
||||
"diagnostics.get-support": "Ottenere supporto",
|
||||
"diagnostics.get-support-description": "Se hai problemi con OliveTin e vuoi presentare una richiesta di supporto, sarebbe molto utile includere la diagnostica del server da questa pagina.",
|
||||
"diagnostics.server-diagnostics": "Diagnostica del server",
|
||||
"diagnostics.server-diagnostics-description": "Questa sezione ti consente di generare un rapporto dettagliato della tua configurazione e ambiente. È una buona idea includere questo quando si presenta una richiesta di supporto.",
|
||||
"diagnostics.server-diagnostics-docs": "Documentazione diagnostica del server",
|
||||
"diagnostics.ssh": "SSH",
|
||||
"diagnostics.unknown": "Sconosciuto",
|
||||
"diagnostics.useragent-data-error": "Errore nel recupero di userAgentData",
|
||||
"diagnostics.where-to-find-help": "Dove trovare aiuto",
|
||||
"disconnected": "Disconnesso",
|
||||
"disconnected-banner-announcement": "Websocket eventi disconnesso.",
|
||||
"disconnected-banner-link-text": "Websocket eventi disconnesso",
|
||||
"disconnected-banner-suffix": " dalle {disconnectedSince}. Nuovo tentativo tra {reconnectIn}.",
|
||||
"disconnected-banner-suffix-reconnecting": " dalle {disconnectedSince}. Tentativo di connessione…",
|
||||
"docs": "Documentazione",
|
||||
"language-dialog.browser-languages": "Lingue del browser",
|
||||
"language-dialog.close": "Chiudi",
|
||||
"language-dialog.not-available": "Non disponibile",
|
||||
"language-dialog.title": "Seleziona lingua",
|
||||
"login-button": "Login",
|
||||
"logs.action": "Azione",
|
||||
"logs.action-group-limits": "simultanei: {concurrent}, dimensione coda: {queueSize}",
|
||||
"logs.back-to-list": "Torna all'Elenco",
|
||||
"logs.blocked": "Bloccato",
|
||||
"logs.calendar": "Calendario",
|
||||
"logs.calendar-title": "Calendario dei Registri",
|
||||
"logs.clear-date-filter": "Cancella filtro data",
|
||||
"logs.clear-filter": "Cancella filtro di ricerca",
|
||||
"logs.completed": "Completato",
|
||||
"logs.exit-code": "Codice di uscita",
|
||||
"logs.filter-error": "Impossibile applicare l'espressione di filtro.",
|
||||
"logs.filter-help-examples": "Esempi: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "Campi: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operatori: ==, !=, contains. Un prefisso ! su una singola parola esclude le voci corrispondenti.",
|
||||
"logs.filter-help-intro": "I filtri vengono eseguiti sul server sulle voci che sei autorizzato a visualizzare. Combina i termini con and / or.",
|
||||
"logs.filter-help-title": "Sintassi del filtro",
|
||||
"logs.filter-placeholder": "Filtra i registri (es. !Update o Status != Completed)",
|
||||
"logs.metadata": "Metadati",
|
||||
"logs.no-logs-for-filter": "Nessun registro corrisponde al filtro corrente.",
|
||||
"logs.no-logs-to-display": "Non ci sono registri da mostrare.",
|
||||
"logs.page-description": "Questa è una lista di registri delle azioni che sono state eseguite. Puoi filtrare la lista per titolo dell'azione.",
|
||||
"logs.queue": "Coda",
|
||||
"logs.queue-action-details": "Dettagli azione",
|
||||
"logs.queue-default-group": "Predefinito",
|
||||
"logs.queue-empty": "Non ci sono esecuzioni attive o in attesa al momento.",
|
||||
"logs.queue-entity": "Entità",
|
||||
"logs.queue-group-active": "{active} attive (max {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} attive",
|
||||
"logs.queue-page-description": "Esecuzioni attive e in attesa raggruppate per gruppo di azioni. Le voci non autorizzate sono nascoste.",
|
||||
"logs.queue-position": "#{position}",
|
||||
"logs.queue-running": "In esecuzione",
|
||||
"logs.queue-title": "Coda di esecuzione",
|
||||
"logs.queue-waiting": "In attesa",
|
||||
"logs.status": "Stato",
|
||||
"logs.timed-out": "Tempo scaduto",
|
||||
"logs.timestamp": "Date e ora",
|
||||
"logs.title": "Registri",
|
||||
"nav.actions": "Azioni",
|
||||
"nav.diagnostics": "Diagnostica",
|
||||
"nav.entities": "Entità",
|
||||
"nav.logs": "Registri",
|
||||
"nav.system": "Sistema",
|
||||
"raise-issue": "Segnala un problema su GitHub",
|
||||
"reconnecting": "Riconnessione…",
|
||||
"return-to-index": "Torna alla pagina principale",
|
||||
"search-filter": "Filtra la pagina corrente",
|
||||
"theme-dialog.close": "Chiudi",
|
||||
"theme-dialog.default": "Tema Predefinito",
|
||||
"theme-dialog.title": "Seleziona tema",
|
||||
"welcome": "Benvenuto in OliveTin"
|
||||
},
|
||||
"zh-Hans-CN": {
|
||||
"connected": "已连接",
|
||||
"diagnostics.browser-info": "浏览器信息",
|
||||
"diagnostics.browser-info-description": "此部分允许您生成浏览器信息的详细报告。这在排查浏览器特定问题时很有帮助。",
|
||||
"diagnostics.config-issue-action": "操作",
|
||||
"diagnostics.config-issue-argument": "参数",
|
||||
"diagnostics.config-issue-code": "代码",
|
||||
"diagnostics.config-issue-config-file": "配置文件",
|
||||
"diagnostics.config-issue-detail": "详情",
|
||||
"diagnostics.config-issue-message": "消息",
|
||||
"diagnostics.config-issue-severity": "严重程度",
|
||||
"diagnostics.config-issue-source": "来源",
|
||||
"diagnostics.config-issues": "配置问题",
|
||||
"diagnostics.config-issues-description": "当前 OliveTin 配置中检测到的问题。请在配置文件中修复这些问题并重新加载 OliveTin。",
|
||||
"diagnostics.config-issues-none": "未检测到配置问题。",
|
||||
"diagnostics.copied": "已复制!",
|
||||
"diagnostics.copy-to-clipboard": "复制到剪贴板",
|
||||
"diagnostics.found-config": "找到配置",
|
||||
"diagnostics.found-key": "找到密钥",
|
||||
"diagnostics.generate-browser-info": "生成浏览器信息",
|
||||
"diagnostics.generate-server-diagnostics": "生成服务器诊断",
|
||||
"diagnostics.get-support": "获取支持",
|
||||
"diagnostics.get-support-description": "如果您在使用 OliveTin 时遇到问题并希望提交支持请求,从本页面包含服务器诊断将非常有帮助。",
|
||||
"diagnostics.server-diagnostics": "服务器诊断",
|
||||
"diagnostics.server-diagnostics-description": "此部分允许您生成配置和环境的详细报告。在提交支持请求时包含此信息是个好主意。",
|
||||
"diagnostics.server-diagnostics-docs": "服务器诊断文档",
|
||||
"diagnostics.ssh": "SSH",
|
||||
"diagnostics.unknown": "未知",
|
||||
"diagnostics.useragent-data-error": "检索 userAgentData 时出错",
|
||||
"diagnostics.where-to-find-help": "在哪里找到帮助",
|
||||
"disconnected": "已断开连接",
|
||||
"disconnected-banner-announcement": "事件 WebSocket 已断开。",
|
||||
"disconnected-banner-link-text": "事件 WebSocket 已断开",
|
||||
"disconnected-banner-suffix": "自 {disconnectedSince}。{reconnectIn} 后尝试重连。",
|
||||
"disconnected-banner-suffix-reconnecting": "自 {disconnectedSince}。正在尝试重连…",
|
||||
"docs": "文档",
|
||||
"language-dialog.browser-languages": "浏览器语言",
|
||||
"language-dialog.close": "关闭",
|
||||
"language-dialog.not-available": "不可用",
|
||||
"language-dialog.title": "选择语言",
|
||||
"login-button": "登录",
|
||||
"logs.action": "动作",
|
||||
"logs.action-group-limits": "并发:{concurrent},队列大小:{queueSize}",
|
||||
"logs.back-to-list": "返回列表",
|
||||
"logs.blocked": "阻塞",
|
||||
"logs.calendar": "日历",
|
||||
"logs.calendar-title": "日志日历",
|
||||
"logs.clear-date-filter": "清除日期筛选器",
|
||||
"logs.clear-filter": "清除搜索筛选器",
|
||||
"logs.completed": "完成",
|
||||
"logs.exit-code": "退出代码",
|
||||
"logs.filter-error": "无法应用过滤表达式。",
|
||||
"logs.filter-help-examples": "示例:backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "字段:Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode。运算符:==, !=, contains。在单个单词前加上 ! 前缀可排除匹配的条目。",
|
||||
"logs.filter-help-intro": "过滤器会在服务器端针对您有权限查看的条目进行筛选。您可以使用 and / or 来组合搜索条件。",
|
||||
"logs.filter-help-title": "过滤语法",
|
||||
"logs.filter-placeholder": "过滤日志(例如 !Update 或 Status != Completed)",
|
||||
"logs.metadata": "元数据",
|
||||
"logs.no-logs-for-filter": "没有符合当前过滤条件的日志。",
|
||||
"logs.no-logs-to-display": "没有日志可显示。",
|
||||
"logs.page-description": "这是一个动作执行日志列表。您可以按动作标题过滤列表。",
|
||||
"logs.queue": "队列",
|
||||
"logs.queue-action-details": "动作详细信息",
|
||||
"logs.queue-default-group": "默认",
|
||||
"logs.queue-empty": "当前没有正在运行或等待中的执行。",
|
||||
"logs.queue-entity": "实体",
|
||||
"logs.queue-group-active": "{active} 个活动(上限 {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} 个活动",
|
||||
"logs.queue-page-description": "按动作组分组显示正在运行和等待中的执行。您无权查看的条目会被隐藏。",
|
||||
"logs.queue-position": "第 {position} 位",
|
||||
"logs.queue-running": "运行中",
|
||||
"logs.queue-title": "执行队列",
|
||||
"logs.queue-waiting": "等待中",
|
||||
"logs.status": "状态",
|
||||
"logs.timed-out": "超时",
|
||||
"logs.timestamp": "时间戳",
|
||||
"logs.title": "日志",
|
||||
"nav.actions": "动作",
|
||||
"nav.diagnostics": "诊断",
|
||||
"nav.entities": "实体",
|
||||
"nav.logs": "日志",
|
||||
"nav.system": "系统",
|
||||
"raise-issue": "在 GitHub 上报告问题",
|
||||
"reconnecting": "正在重新连接…",
|
||||
"return-to-index": "返回首页",
|
||||
"search-filter": "过滤当前页面",
|
||||
"theme-dialog.close": "关闭",
|
||||
"theme-dialog.default": "默认主题",
|
||||
"theme-dialog.title": "选择主题",
|
||||
"welcome": "欢迎使用 OliveTin"
|
||||
},
|
||||
"zh-Hant-TW": {
|
||||
"connected": "已連線",
|
||||
"diagnostics.browser-info": "瀏覽器資訊",
|
||||
"diagnostics.browser-info-description": "此區塊可讓您產生瀏覽器資訊的詳細報告。這在排解特定瀏覽器問題時相當有幫助。",
|
||||
"diagnostics.config-issue-action": "動作",
|
||||
"diagnostics.config-issue-argument": "參數",
|
||||
"diagnostics.config-issue-code": "代碼",
|
||||
"diagnostics.config-issue-config-file": "設定檔",
|
||||
"diagnostics.config-issue-detail": "詳細資料",
|
||||
"diagnostics.config-issue-message": "訊息",
|
||||
"diagnostics.config-issue-severity": "嚴重程度",
|
||||
"diagnostics.config-issue-source": "來源",
|
||||
"diagnostics.config-issues": "設定問題",
|
||||
"diagnostics.config-issues-description": "目前 OliveTin 設定中偵測到的問題。請在設定檔中修正這些問題並重新載入 OliveTin。",
|
||||
"diagnostics.config-issues-none": "未偵測到設定問題。",
|
||||
"diagnostics.copied": "已複製!",
|
||||
"diagnostics.copy-to-clipboard": "複製到剪貼簿",
|
||||
"diagnostics.found-config": "找到設定檔 (Config)",
|
||||
"diagnostics.found-key": "找到金鑰 (Key)",
|
||||
"diagnostics.generate-browser-info": "產生瀏覽器資訊",
|
||||
"diagnostics.generate-server-diagnostics": "產生伺服器診斷資訊",
|
||||
"diagnostics.get-support": "尋求技術支援",
|
||||
"diagnostics.get-support-description": "如果您在使用 OliveTin 時遇到問題並希望提出支援請求,提供此頁面的「伺服器診斷資訊」將會有很大的幫助。",
|
||||
"diagnostics.server-diagnostics": "伺服器診斷",
|
||||
"diagnostics.server-diagnostics-description": "此區塊可讓您產生詳細的設定與環境報告。建議在提出支援請求時附上此報告。",
|
||||
"diagnostics.server-diagnostics-docs": "伺服器診斷官方文件",
|
||||
"diagnostics.ssh": "SSH",
|
||||
"diagnostics.unknown": "未知",
|
||||
"diagnostics.useragent-data-error": "取得 userAgentData 時發生錯誤",
|
||||
"diagnostics.where-to-find-help": "哪裡可以尋求協助",
|
||||
"disconnected": "已斷線",
|
||||
"disconnected-banner-announcement": "系統事件 WebSocket 已斷線。",
|
||||
"disconnected-banner-link-text": "系統事件 WebSocket 已斷線",
|
||||
"disconnected-banner-suffix": " 自 {disconnectedSince} 起。將在 {reconnectIn} 後嘗試重新連線。",
|
||||
"disconnected-banner-suffix-reconnecting": " 自 {disconnectedSince} 起。嘗試重新連線中…",
|
||||
"docs": "官方文件",
|
||||
"language-dialog.browser-languages": "瀏覽器語言",
|
||||
"language-dialog.close": "關閉",
|
||||
"language-dialog.not-available": "無法使用",
|
||||
"language-dialog.title": "選擇語言",
|
||||
"login-button": "登入",
|
||||
"logs.action": "動作",
|
||||
"logs.action-group-limits": "並行數:{concurrent},佇列大小:{queueSize}",
|
||||
"logs.back-to-list": "返回清單",
|
||||
"logs.blocked": "已阻擋",
|
||||
"logs.calendar": "日曆",
|
||||
"logs.calendar-title": "日誌日曆",
|
||||
"logs.clear-date-filter": "清除日期過濾條件",
|
||||
"logs.clear-filter": "清除搜尋過濾條件",
|
||||
"logs.completed": "已完成",
|
||||
"logs.exit-code": "結束代碼",
|
||||
"logs.filter-error": "無法套用過濾運算式。",
|
||||
"logs.filter-help-examples": "範例:backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed",
|
||||
"logs.filter-help-fields": "欄位:Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode。運算子:==, !=, contains。在單一單字前加上 ! 前綴可排除相符的項目。",
|
||||
"logs.filter-help-intro": "過濾器會在伺服器端針對您有權限檢視的項目進行篩選。您可以使用 and / or 來組合搜尋條件。",
|
||||
"logs.filter-help-title": "過濾語法",
|
||||
"logs.filter-placeholder": "過濾日誌 (例如 !Update 或 Status != Completed)",
|
||||
"logs.metadata": "中繼資料",
|
||||
"logs.no-logs-for-filter": "沒有符合目前過濾條件的日誌。",
|
||||
"logs.no-logs-to-display": "目前沒有可顯示的日誌。",
|
||||
"logs.page-description": "這是已執行動作的日誌清單。請使用過濾條件欄位來搜尋關鍵字與運算式。",
|
||||
"logs.queue": "佇列",
|
||||
"logs.queue-action-details": "動作詳細資訊",
|
||||
"logs.queue-default-group": "預設",
|
||||
"logs.queue-empty": "目前沒有使用中或等待中的執行項目。",
|
||||
"logs.queue-entity": "實體",
|
||||
"logs.queue-group-active": "{active} 個使用中 (最大值 {max})",
|
||||
"logs.queue-group-active-unlimited": "{active} 個使用中",
|
||||
"logs.queue-page-description": "依動作群組分類的使用中與等待中執行項目。您無權檢視的項目將會被隱藏。",
|
||||
"logs.queue-position": "#{position}",
|
||||
"logs.queue-running": "執行中",
|
||||
"logs.queue-title": "執行佇列",
|
||||
"logs.queue-waiting": "等待中",
|
||||
"logs.status": "狀態",
|
||||
"logs.timed-out": "執行逾時",
|
||||
"logs.timestamp": "時間戳記",
|
||||
"logs.title": "日誌",
|
||||
"nav.actions": "動作",
|
||||
"nav.diagnostics": "診斷",
|
||||
"nav.entities": "實體",
|
||||
"nav.logs": "日誌",
|
||||
"nav.system": "系統",
|
||||
"raise-issue": "在 GitHub 上建立 Issue",
|
||||
"reconnecting": "重新連線中…",
|
||||
"return-to-index": "返回首頁",
|
||||
"search-filter": "過濾目前頁面",
|
||||
"theme-dialog.close": "關閉",
|
||||
"theme-dialog.default": "預設佈景主題",
|
||||
"theme-dialog.title": "選擇佈景主題",
|
||||
"welcome": "歡迎使用 OliveTin"
|
||||
"logs.queue-running": "Выполняется",
|
||||
"logs.queue-title": "Очередь выполнения",
|
||||
"logs.queue-waiting": "Ожидание",
|
||||
"logs.status": "Статус",
|
||||
"logs.timed-out": "Истекло время ожидания",
|
||||
"logs.timestamp": "Время",
|
||||
"logs.title": "Журналы",
|
||||
"nav.actions": "Действия",
|
||||
"nav.diagnostics": "Диагностика",
|
||||
"nav.entities": "Сущности",
|
||||
"nav.logs": "Журналы",
|
||||
"nav.navigation": "Навигация",
|
||||
"nav.system": "Система",
|
||||
"raise-issue": "Сообщить о проблеме на GitHub",
|
||||
"reconnecting": "Переподключение…",
|
||||
"return-to-index": "Вернуться на главную",
|
||||
"search-filter": "Фильтр текущей страницы",
|
||||
"theme-dialog.close": "Закрыть",
|
||||
"theme-dialog.default": "Тема по умолчанию",
|
||||
"theme-dialog.title": "Выберите тему",
|
||||
"welcome": "Добро пожаловать в OliveTin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: Willkommen bei OliveTin
|
||||
nav.actions: Aktionen
|
||||
nav.logs: Protokolle
|
||||
nav.entities: Entitäten
|
||||
nav.diagnostics: Diagnostik
|
||||
nav.system: System
|
||||
connected: Verbunden
|
||||
disconnected: Getrennt
|
||||
reconnecting: Verbinde erneut…
|
||||
disconnected-banner-announcement: Events-Websocket getrennt.
|
||||
disconnected-banner-link-text: "Events-Websocket getrennt"
|
||||
disconnected-banner-suffix: " seit {disconnectedSince}. Erneuter Verbindungsversuch in {reconnectIn}."
|
||||
disconnected-banner-suffix-reconnecting: " seit {disconnectedSince}. Verbindungsversuch…"
|
||||
login-button: Login
|
||||
raise-issue: Ein Problem melden auf GitHub
|
||||
docs: Dokumentation
|
||||
logs.title: Protokolle
|
||||
logs.page-description: Dies ist eine Liste von Protokollen von Aktionen, die ausgeführt wurden. Sie können die Liste nach Aktionstitel filtern.
|
||||
logs.filter-placeholder: Protokolle filtern (z. B. !Update oder Status != Completed)
|
||||
logs.filter-help-title: Filtersyntax
|
||||
logs.filter-help-intro: Filter laufen auf dem Server über Einträge, die Sie anzeigen dürfen. Kombinieren Sie Begriffe mit and / or.
|
||||
logs.filter-help-fields: "Felder: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operatoren: ==, !=, contains. Ein !-Präfix vor einem einzelnen Wort schließt passende Einträge aus."
|
||||
logs.filter-help-examples: "Beispiele: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: Filterausdruck konnte nicht angewendet werden.
|
||||
logs.no-logs-for-filter: Keine Protokolle entsprechen dem aktuellen Filter.
|
||||
logs.timestamp: Zeitstempel
|
||||
logs.action: Aktion
|
||||
logs.metadata: Metadaten
|
||||
logs.status: Status
|
||||
logs.no-logs-to-display: Es gibt keine Protokolle zu anzeigen.
|
||||
logs.timed-out: Zeitüberschreitung
|
||||
logs.blocked: Blockiert
|
||||
logs.exit-code: Ausführungscode
|
||||
logs.completed: Abgeschlossen
|
||||
logs.clear-filter: Suchfilter löschen
|
||||
logs.clear-date-filter: Datumsfilter löschen
|
||||
logs.calendar: Kalender
|
||||
logs.calendar-title: Protokoll-Kalender
|
||||
logs.back-to-list: Zurück zur Liste
|
||||
logs.queue: Warteschlange
|
||||
logs.queue-title: Ausführungswarteschlange
|
||||
logs.queue-page-description: Aktive und wartende Ausführungen, nach Aktionsgruppe gruppiert. Einträge ohne Berechtigung werden ausgeblendet.
|
||||
logs.queue-default-group: Standard
|
||||
logs.action-group-limits: "gleichzeitig: {concurrent}, Warteschlangengröße: {queueSize}"
|
||||
logs.queue-group-active-unlimited: "{active} aktiv"
|
||||
logs.queue-empty: Derzeit gibt es keine aktiven oder wartenden Ausführungen.
|
||||
logs.queue-group-active: "{active} aktiv (max. {max})"
|
||||
logs.queue-waiting: Wartend
|
||||
logs.queue-running: Läuft
|
||||
logs.queue-position: "#{position}"
|
||||
logs.queue-entity: Entität
|
||||
logs.queue-action-details: Aktionsdetails
|
||||
diagnostics.get-support: Unterstützung erhalten
|
||||
diagnostics.get-support-description: Wenn Sie Probleme mit OliveTin haben und eine Support-Anfrage stellen möchten, wäre es sehr hilfreich, Server-Diagnostik von dieser Seite einzufügen.
|
||||
diagnostics.where-to-find-help: Wo Sie Hilfe finden
|
||||
diagnostics.config-issues: Konfigurationsprobleme
|
||||
diagnostics.config-issues-description: In der aktuellen OliveTin-Konfiguration erkannte Probleme. Beheben Sie diese in Ihren Konfigurationsdateien und laden Sie OliveTin neu.
|
||||
diagnostics.config-issues-none: Keine Konfigurationsprobleme erkannt.
|
||||
diagnostics.config-issue-severity: Schweregrad
|
||||
diagnostics.config-issue-code: Code
|
||||
diagnostics.config-issue-message: Meldung
|
||||
diagnostics.config-issue-action: Aktion
|
||||
diagnostics.config-issue-argument: Argument
|
||||
diagnostics.config-issue-config-file: Konfigurationsdatei
|
||||
diagnostics.config-issue-detail: Detail
|
||||
diagnostics.config-issue-source: Quelle
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: Schlüssel gefunden
|
||||
diagnostics.found-config: Konfiguration gefunden
|
||||
diagnostics.server-diagnostics: Server-Diagnostik
|
||||
diagnostics.server-diagnostics-description: Dieser Abschnitt ermöglicht es Ihnen, einen detaillierten Bericht über Ihre Konfiguration und Umgebung zu erstellen. Es ist eine gute Idee, dies bei einer Support-Anfrage einzufügen.
|
||||
diagnostics.server-diagnostics-docs: Server-Diagnostik-Dokumentation
|
||||
diagnostics.generate-server-diagnostics: Server-Diagnostik erstellen
|
||||
diagnostics.browser-info: Browser-Informationen
|
||||
diagnostics.browser-info-description: Dieser Abschnitt ermöglicht es Ihnen, einen detaillierten Bericht über Ihre Browser-Informationen zu erstellen. Dies kann bei der Fehlerbehebung von browser-spezifischen Problemen hilfreich sein.
|
||||
diagnostics.generate-browser-info: Browser-Informationen erstellen
|
||||
diagnostics.copy-to-clipboard: In Zwischenablage kopieren
|
||||
diagnostics.copied: Kopiert!
|
||||
diagnostics.unknown: Unbekannt
|
||||
diagnostics.useragent-data-error: Fehler beim Abrufen von userAgentData
|
||||
return-to-index: Zurück zur Startseite
|
||||
search-filter: Filter aktuelle Seite
|
||||
language-dialog.title: Sprache auswählen
|
||||
language-dialog.browser-languages: Browser-Sprachen
|
||||
language-dialog.not-available: Nicht verfügbar
|
||||
language-dialog.close: Schließen
|
||||
theme-dialog.title: Design auswählen
|
||||
theme-dialog.default: Standard-Design
|
||||
theme-dialog.close: Schließen
|
||||
30
lang/en.yaml
30
lang/en.yaml
|
|
@ -4,10 +4,30 @@ translations:
|
|||
docs: Documentation
|
||||
raise-issue: Raise an issue on GitHub
|
||||
nav.actions: Actions
|
||||
nav.navigation: Navigation
|
||||
nav.logs: Logs
|
||||
nav.entities: Entities
|
||||
nav.diagnostics: Diagnostics
|
||||
nav.system: System
|
||||
action.start: Start
|
||||
action.cancel: Cancel
|
||||
execution.results: "Execution Results:"
|
||||
execution.duration: Duration
|
||||
execution.status: Status
|
||||
execution.rerun: Rerun
|
||||
execution.kill: Kill
|
||||
execution.back: Back
|
||||
execution.back-to: Back to {title}
|
||||
execution.copy: Copy to clipboard
|
||||
execution.fullscreen: Toggle fullscreen
|
||||
execution.waiting: Waiting for result…
|
||||
execution.seconds: "{n} seconds"
|
||||
execution.not-found: Execution not found
|
||||
execution.not-found-id: "The execution with ID"
|
||||
execution.not-found-generic: The execution could not be found in the system.
|
||||
execution.view-logs: View all logs
|
||||
execution.or: or
|
||||
execution.return-home: return to home
|
||||
connected: Connected
|
||||
disconnected: Disconnected
|
||||
reconnecting: Reconnecting…
|
||||
|
|
@ -16,6 +36,16 @@ translations:
|
|||
disconnected-banner-suffix: " since {disconnectedSince}. Trying reconnect in {reconnectIn}."
|
||||
disconnected-banner-suffix-reconnecting: " since {disconnectedSince}. Trying reconnect…"
|
||||
login-button: Login
|
||||
login.title: Авторизация
|
||||
login.disabled: This server is not configured with either OAuth, or local users, so you cannot login.
|
||||
login.oauth: OAuth Login
|
||||
login.oauth-with: Login with {provider}
|
||||
login.username: Username
|
||||
login.password: Password
|
||||
login.submit: Login
|
||||
login.submitting: Logging in…
|
||||
login.failed: Login failed. Please check your credentials.
|
||||
login.network-error: Network error. Please try again.
|
||||
logs.title: Logs
|
||||
logs.page-description: This is a list of logs from actions that have been executed. Use the filter box for search terms and expressions.
|
||||
logs.filter-placeholder: Filter logs (e.g. !Update or Status != Completed)
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: Bienvenido a OliveTin
|
||||
nav.actions: Acciones
|
||||
nav.logs: Registros
|
||||
nav.entities: Entidades
|
||||
nav.diagnostics: Diagnósticos
|
||||
nav.system: Sistema
|
||||
connected: Conectado
|
||||
disconnected: Desconectado
|
||||
reconnecting: Reconectando…
|
||||
disconnected-banner-announcement: Websocket de eventos desconectado.
|
||||
disconnected-banner-link-text: "Websocket de eventos desconectado"
|
||||
disconnected-banner-suffix: " desde {disconnectedSince}. Reintentando conexión en {reconnectIn}."
|
||||
disconnected-banner-suffix-reconnecting: " desde {disconnectedSince}. Reintentando conexión…"
|
||||
login-button: Iniciar sesión
|
||||
raise-issue: Reportar un problema en GitHub
|
||||
docs: Documentación
|
||||
logs.title: Registros
|
||||
logs.page-description: Esta es una lista de registros de acciones que han sido ejecutadas. Puede filtrar la lista por título de acción.
|
||||
logs.filter-placeholder: Filtrar registros (p. ej. !Update o Status != Completed)
|
||||
logs.filter-help-title: Sintaxis del filtro
|
||||
logs.filter-help-intro: Los filtros se ejecutan en el servidor sobre las entradas que puede ver. Combine términos con and / or.
|
||||
logs.filter-help-fields: "Campos: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operadores: ==, !=, contains. Un prefijo ! en una sola palabra excluye las entradas coincidentes."
|
||||
logs.filter-help-examples: "Ejemplos: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: No se pudo aplicar la expresión del filtro.
|
||||
logs.no-logs-for-filter: Ningún registro coincide con el filtro actual.
|
||||
logs.timestamp: Marca de tiempo
|
||||
logs.action: Acción
|
||||
logs.metadata: Metadatos
|
||||
logs.status: Estado
|
||||
logs.no-logs-to-display: No hay registros para mostrar.
|
||||
logs.timed-out: Tiempo agotado
|
||||
logs.blocked: Bloqueado
|
||||
logs.exit-code: Código de salida
|
||||
logs.completed: Completado
|
||||
logs.clear-filter: Limpiar filtro de búsqueda
|
||||
logs.clear-date-filter: Limpiar filtro de fecha
|
||||
logs.calendar: Calendario
|
||||
logs.calendar-title: Calendario de Registros
|
||||
logs.back-to-list: Volver a la Lista
|
||||
logs.queue: Cola
|
||||
logs.queue-title: Cola de ejecución
|
||||
logs.queue-page-description: Ejecuciones activas y en espera agrupadas por grupo de acciones. Las entradas que no puede ver se ocultan.
|
||||
logs.queue-default-group: Predeterminado
|
||||
logs.action-group-limits: "simultáneas: {concurrent}, tamaño de cola: {queueSize}"
|
||||
logs.queue-group-active-unlimited: "{active} activas"
|
||||
logs.queue-empty: No hay ejecuciones activas o en espera en este momento.
|
||||
logs.queue-group-active: "{active} activas (máx. {max})"
|
||||
logs.queue-waiting: En espera
|
||||
logs.queue-running: En ejecución
|
||||
logs.queue-position: "#{position}"
|
||||
logs.queue-entity: Entidad
|
||||
logs.queue-action-details: Detalles de la acción
|
||||
diagnostics.get-support: Obtener soporte
|
||||
diagnostics.get-support-description: Si tiene problemas con OliveTin y desea presentar una solicitud de soporte, sería muy útil incluir diagnósticos del servidor desde esta página.
|
||||
diagnostics.where-to-find-help: Dónde encontrar ayuda
|
||||
diagnostics.config-issues: Problemas de configuración
|
||||
diagnostics.config-issues-description: Problemas detectados en la configuración actual de OliveTin. Corríjalos en sus archivos de configuración y vuelva a cargar OliveTin.
|
||||
diagnostics.config-issues-none: No se detectaron problemas de configuración.
|
||||
diagnostics.config-issue-severity: Severidad
|
||||
diagnostics.config-issue-code: Código
|
||||
diagnostics.config-issue-message: Mensaje
|
||||
diagnostics.config-issue-action: Acción
|
||||
diagnostics.config-issue-argument: Argumento
|
||||
diagnostics.config-issue-config-file: Archivo de configuración
|
||||
diagnostics.config-issue-detail: Detalle
|
||||
diagnostics.config-issue-source: Origen
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: Clave encontrada
|
||||
diagnostics.found-config: Configuración encontrada
|
||||
diagnostics.server-diagnostics: Diagnóstico del servidor
|
||||
diagnostics.server-diagnostics-description: Esta sección le permite generar un informe detallado de su configuración y entorno. Es una buena idea incluir esto al presentar una solicitud de soporte.
|
||||
diagnostics.server-diagnostics-docs: Documentación de diagnóstico del servidor
|
||||
diagnostics.generate-server-diagnostics: Generar diagnóstico del servidor
|
||||
diagnostics.browser-info: Información del navegador
|
||||
diagnostics.browser-info-description: Esta sección le permite generar un informe detallado de su información del navegador. Esto puede ser útil al solucionar problemas específicos del navegador.
|
||||
diagnostics.generate-browser-info: Generar información del navegador
|
||||
diagnostics.copy-to-clipboard: Copiar al portapapeles
|
||||
diagnostics.copied: ¡Copiado!
|
||||
diagnostics.unknown: Desconocido
|
||||
diagnostics.useragent-data-error: Error al recuperar userAgentData
|
||||
return-to-index: Volver a la página principal
|
||||
search-filter: Filtrar página actual
|
||||
language-dialog.title: Seleccionar idioma
|
||||
language-dialog.browser-languages: Idiomas del navegador
|
||||
language-dialog.not-available: No disponible
|
||||
language-dialog.close: Cerrar
|
||||
theme-dialog.title: Seleccionar tema
|
||||
theme-dialog.default: Tema Predeterminado
|
||||
theme-dialog.close: Cerrar
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: Benvenuto in OliveTin
|
||||
nav.actions: Azioni
|
||||
nav.logs: Registri
|
||||
nav.entities: Entità
|
||||
nav.diagnostics: Diagnostica
|
||||
nav.system: Sistema
|
||||
docs: Documentazione
|
||||
connected: Connesso
|
||||
disconnected: Disconnesso
|
||||
reconnecting: Riconnessione…
|
||||
disconnected-banner-announcement: Websocket eventi disconnesso.
|
||||
disconnected-banner-link-text: "Websocket eventi disconnesso"
|
||||
disconnected-banner-suffix: " dalle {disconnectedSince}. Nuovo tentativo tra {reconnectIn}."
|
||||
disconnected-banner-suffix-reconnecting: " dalle {disconnectedSince}. Tentativo di connessione…"
|
||||
login-button: Login
|
||||
raise-issue: Segnala un problema su GitHub
|
||||
logs.title: Registri
|
||||
logs.page-description: Questa è una lista di registri delle azioni che sono state eseguite. Puoi filtrare la lista per titolo dell'azione.
|
||||
logs.filter-placeholder: Filtra i registri (es. !Update o Status != Completed)
|
||||
logs.filter-help-title: Sintassi del filtro
|
||||
logs.filter-help-intro: I filtri vengono eseguiti sul server sulle voci che sei autorizzato a visualizzare. Combina i termini con and / or.
|
||||
logs.filter-help-fields: "Campi: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Operatori: ==, !=, contains. Un prefisso ! su una singola parola esclude le voci corrispondenti."
|
||||
logs.filter-help-examples: "Esempi: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: Impossibile applicare l'espressione di filtro.
|
||||
logs.no-logs-for-filter: Nessun registro corrisponde al filtro corrente.
|
||||
logs.timestamp: Date e ora
|
||||
logs.action: Azione
|
||||
logs.metadata: Metadati
|
||||
logs.status: Stato
|
||||
logs.no-logs-to-display: Non ci sono registri da mostrare.
|
||||
logs.timed-out: Tempo scaduto
|
||||
logs.blocked: Bloccato
|
||||
logs.exit-code: Codice di uscita
|
||||
logs.completed: Completato
|
||||
logs.clear-filter: Cancella filtro di ricerca
|
||||
logs.clear-date-filter: Cancella filtro data
|
||||
logs.calendar: Calendario
|
||||
logs.calendar-title: Calendario dei Registri
|
||||
logs.back-to-list: Torna all'Elenco
|
||||
logs.queue: Coda
|
||||
logs.queue-title: Coda di esecuzione
|
||||
logs.queue-page-description: Esecuzioni attive e in attesa raggruppate per gruppo di azioni. Le voci non autorizzate sono nascoste.
|
||||
logs.queue-default-group: Predefinito
|
||||
logs.action-group-limits: "simultanei: {concurrent}, dimensione coda: {queueSize}"
|
||||
logs.queue-group-active-unlimited: "{active} attive"
|
||||
logs.queue-empty: Non ci sono esecuzioni attive o in attesa al momento.
|
||||
logs.queue-group-active: "{active} attive (max {max})"
|
||||
logs.queue-waiting: In attesa
|
||||
logs.queue-running: In esecuzione
|
||||
logs.queue-position: "#{position}"
|
||||
logs.queue-entity: Entità
|
||||
logs.queue-action-details: Dettagli azione
|
||||
diagnostics.get-support: Ottenere supporto
|
||||
diagnostics.get-support-description: Se hai problemi con OliveTin e vuoi presentare una richiesta di supporto, sarebbe molto utile includere la diagnostica del server da questa pagina.
|
||||
diagnostics.where-to-find-help: Dove trovare aiuto
|
||||
diagnostics.config-issues: Problemi di configurazione
|
||||
diagnostics.config-issues-description: Problemi rilevati nella configurazione corrente di OliveTin. Correggili nei file di configurazione e ricarica OliveTin.
|
||||
diagnostics.config-issues-none: Nessun problema di configurazione rilevato.
|
||||
diagnostics.config-issue-severity: Gravità
|
||||
diagnostics.config-issue-code: Codice
|
||||
diagnostics.config-issue-message: Messaggio
|
||||
diagnostics.config-issue-action: Azione
|
||||
diagnostics.config-issue-argument: Argomento
|
||||
diagnostics.config-issue-config-file: File di configurazione
|
||||
diagnostics.config-issue-detail: Dettaglio
|
||||
diagnostics.config-issue-source: Origine
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: Chiave trovata
|
||||
diagnostics.found-config: Configurazione trovata
|
||||
diagnostics.server-diagnostics: Diagnostica del server
|
||||
diagnostics.server-diagnostics-description: Questa sezione ti consente di generare un rapporto dettagliato della tua configurazione e ambiente. È una buona idea includere questo quando si presenta una richiesta di supporto.
|
||||
diagnostics.server-diagnostics-docs: Documentazione diagnostica del server
|
||||
diagnostics.generate-server-diagnostics: Genera diagnostica del server
|
||||
diagnostics.browser-info: Informazioni del browser
|
||||
diagnostics.browser-info-description: Questa sezione ti consente di generare un rapporto dettagliato delle informazioni del tuo browser. Questo può essere utile durante la risoluzione dei problemi specifici del browser.
|
||||
diagnostics.generate-browser-info: Genera informazioni del browser
|
||||
diagnostics.copy-to-clipboard: Copia negli appunti
|
||||
diagnostics.copied: Copiato!
|
||||
diagnostics.unknown: Sconosciuto
|
||||
diagnostics.useragent-data-error: Errore nel recupero di userAgentData
|
||||
return-to-index: Torna alla pagina principale
|
||||
search-filter: Filtra la pagina corrente
|
||||
language-dialog.title: Seleziona lingua
|
||||
language-dialog.browser-languages: Lingue del browser
|
||||
language-dialog.not-available: Non disponibile
|
||||
language-dialog.close: Chiudi
|
||||
theme-dialog.title: Seleziona tema
|
||||
theme-dialog.default: Tema Predefinito
|
||||
theme-dialog.close: Chiudi
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: Добро пожаловать в OliveTin
|
||||
docs: Документация
|
||||
raise-issue: Сообщить о проблеме на GitHub
|
||||
nav.actions: Действия
|
||||
nav.navigation: Навигация
|
||||
nav.logs: Журналы
|
||||
nav.entities: Сущности
|
||||
nav.diagnostics: Диагностика
|
||||
nav.system: Система
|
||||
action.start: Запустить
|
||||
action.cancel: Отмена
|
||||
execution.results: "Результаты выполнения:"
|
||||
execution.duration: Длительность
|
||||
execution.status: Статус
|
||||
execution.rerun: Повторить
|
||||
execution.kill: Остановить
|
||||
execution.back: Назад
|
||||
execution.back-to: Назад к {title}
|
||||
execution.copy: Копировать
|
||||
execution.fullscreen: На весь экран
|
||||
execution.waiting: Ожидание результата…
|
||||
execution.seconds: "{n} сек."
|
||||
execution.not-found: Выполнение не найдено
|
||||
execution.not-found-id: "Выполнение с ID"
|
||||
execution.not-found-generic: Выполнение не найдено в системе.
|
||||
execution.view-logs: Все журналы
|
||||
execution.or: или
|
||||
execution.return-home: на главную
|
||||
connected: Подключено
|
||||
disconnected: Отключено
|
||||
reconnecting: Переподключение…
|
||||
disconnected-banner-announcement: Websocket событий отключён.
|
||||
disconnected-banner-link-text: "Websocket событий отключён"
|
||||
disconnected-banner-suffix: " с {disconnectedSince}. Повтор через {reconnectIn}."
|
||||
disconnected-banner-suffix-reconnecting: " с {disconnectedSince}. Переподключение…"
|
||||
login-button: Войти
|
||||
login.title: Авторизация
|
||||
login.disabled: На этом сервере не настроены ни OAuth, ни локальные пользователи, поэтому войти нельзя.
|
||||
login.oauth: Вход через OAuth
|
||||
login.oauth-with: Войти через {provider}
|
||||
login.username: Имя пользователя
|
||||
login.password: Пароль
|
||||
login.submit: Войти
|
||||
login.submitting: Вход…
|
||||
login.failed: Не удалось войти. Проверьте логин и пароль.
|
||||
login.network-error: Ошибка сети. Попробуйте ещё раз.
|
||||
logs.title: Журналы
|
||||
logs.page-description: Список журналов выполненных действий. В поле фильтра можно вводить слова и выражения.
|
||||
logs.filter-placeholder: Фильтр журналов (например !Update или Status != Completed)
|
||||
logs.filter-help-title: Синтаксис фильтра
|
||||
logs.filter-help-intro: Фильтры выполняются на сервере по записям, которые вам разрешено видеть. Объединяйте условия через and / or.
|
||||
logs.filter-help-fields: "Поля: Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode. Операторы: ==, !=, contains. Префикс ! у слова исключает совпадающие записи."
|
||||
logs.filter-help-examples: "Примеры: backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: Не удалось применить выражение фильтра.
|
||||
logs.no-logs-for-filter: Нет журналов, подходящих под текущий фильтр.
|
||||
logs.timestamp: Время
|
||||
logs.action: Действие
|
||||
logs.metadata: Метаданные
|
||||
logs.status: Статус
|
||||
logs.no-logs-to-display: Нет журналов для отображения.
|
||||
logs.timed-out: Истекло время ожидания
|
||||
logs.blocked: Заблокировано
|
||||
logs.exit-code: Код выхода
|
||||
logs.completed: Завершено
|
||||
logs.clear-filter: Очистить фильтр
|
||||
logs.clear-date-filter: Очистить фильтр по дате
|
||||
logs.calendar: Календарь
|
||||
logs.calendar-title: Календарь журналов
|
||||
logs.back-to-list: К списку
|
||||
logs.queue: Очередь
|
||||
logs.queue-title: Очередь выполнения
|
||||
logs.queue-page-description: Активные и ожидающие выполнения, сгруппированные по группе действий. Записи, которые вам нельзя видеть, скрыты.
|
||||
logs.queue-empty: Сейчас нет активных или ожидающих выполнений.
|
||||
logs.queue-default-group: По умолчанию
|
||||
logs.action-group-limits: "параллельно: {concurrent}, размер очереди: {queueSize}"
|
||||
logs.queue-group-active: "{active} активно (макс. {max})"
|
||||
logs.queue-group-active-unlimited: "{active} активно"
|
||||
logs.queue-waiting: Ожидание
|
||||
logs.queue-running: Выполняется
|
||||
logs.queue-position: "#{position}"
|
||||
logs.queue-entity: Сущность
|
||||
logs.queue-action-details: Сведения о действии
|
||||
diagnostics.get-support: Получить поддержку
|
||||
diagnostics.get-support-description: Если возникли проблемы с OliveTin и вы хотите обратиться в поддержку, приложите диагностику сервера с этой страницы.
|
||||
diagnostics.where-to-find-help: Где искать помощь
|
||||
diagnostics.config-issues: Проблемы конфигурации
|
||||
diagnostics.config-issues-description: Обнаружены проблемы в текущей конфигурации OliveTin. Исправьте их в файлах конфигурации и перезагрузите OliveTin.
|
||||
diagnostics.config-issues-none: Проблем конфигурации не обнаружено.
|
||||
diagnostics.config-issue-severity: Важность
|
||||
diagnostics.config-issue-code: Код
|
||||
diagnostics.config-issue-message: Сообщение
|
||||
diagnostics.config-issue-action: Действие
|
||||
diagnostics.config-issue-argument: Аргумент
|
||||
diagnostics.config-issue-config-file: Файл конфигурации
|
||||
diagnostics.config-issue-detail: Подробности
|
||||
diagnostics.config-issue-source: Источник
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: Ключ найден
|
||||
diagnostics.found-config: Конфигурация найдена
|
||||
diagnostics.server-diagnostics: Диагностика сервера
|
||||
diagnostics.server-diagnostics-description: Здесь можно сформировать подробный отчёт о конфигурации и окружении. Его полезно приложить к обращению в поддержку.
|
||||
diagnostics.server-diagnostics-docs: Документация по диагностике сервера
|
||||
diagnostics.generate-server-diagnostics: Сформировать диагностику сервера
|
||||
diagnostics.browser-info: Сведения о браузере
|
||||
diagnostics.browser-info-description: Здесь можно сформировать подробный отчёт о браузере. Это помогает при проблемах, связанных с конкретным браузером.
|
||||
diagnostics.generate-browser-info: Сформировать сведения о браузере
|
||||
diagnostics.copy-to-clipboard: Копировать в буфер
|
||||
diagnostics.copied: Скопировано!
|
||||
diagnostics.unknown: Неизвестно
|
||||
diagnostics.useragent-data-error: Ошибка получения userAgentData
|
||||
return-to-index: Вернуться на главную
|
||||
search-filter: Фильтр текущей страницы
|
||||
language-dialog.title: Выберите язык
|
||||
language-dialog.browser-languages: Языки браузера
|
||||
language-dialog.not-available: Недоступно
|
||||
language-dialog.close: Закрыть
|
||||
theme-dialog.title: Выберите тему
|
||||
theme-dialog.default: Тема по умолчанию
|
||||
theme-dialog.close: Закрыть
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: 欢迎使用 OliveTin
|
||||
nav.actions: 动作
|
||||
nav.logs: 日志
|
||||
nav.entities: 实体
|
||||
nav.diagnostics: 诊断
|
||||
nav.system: 系统
|
||||
connected: 已连接
|
||||
disconnected: 已断开连接
|
||||
reconnecting: 正在重新连接…
|
||||
disconnected-banner-announcement: 事件 WebSocket 已断开。
|
||||
disconnected-banner-link-text: "事件 WebSocket 已断开"
|
||||
disconnected-banner-suffix: "自 {disconnectedSince}。{reconnectIn} 后尝试重连。"
|
||||
disconnected-banner-suffix-reconnecting: "自 {disconnectedSince}。正在尝试重连…"
|
||||
login-button: 登录
|
||||
raise-issue: 在 GitHub 上报告问题
|
||||
docs: 文档
|
||||
logs.title: 日志
|
||||
logs.page-description: 这是一个动作执行日志列表。您可以按动作标题过滤列表。
|
||||
logs.filter-placeholder: 过滤日志(例如 !Update 或 Status != Completed)
|
||||
logs.filter-help-title: 过滤语法
|
||||
logs.filter-help-intro: 过滤器会在服务器端针对您有权限查看的条目进行筛选。您可以使用 and / or 来组合搜索条件。
|
||||
logs.filter-help-fields: "字段:Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode。运算符:==, !=, contains。在单个单词前加上 ! 前缀可排除匹配的条目。"
|
||||
logs.filter-help-examples: "示例:backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: 无法应用过滤表达式。
|
||||
logs.no-logs-for-filter: 没有符合当前过滤条件的日志。
|
||||
logs.timestamp: 时间戳
|
||||
logs.action: 动作
|
||||
logs.metadata: 元数据
|
||||
logs.status: 状态
|
||||
logs.no-logs-to-display: 没有日志可显示。
|
||||
return-to-index: 返回首页
|
||||
search-filter: 过滤当前页面
|
||||
language-dialog.title: 选择语言
|
||||
language-dialog.browser-languages: 浏览器语言
|
||||
language-dialog.not-available: 不可用
|
||||
language-dialog.close: 关闭
|
||||
theme-dialog.title: 选择主题
|
||||
theme-dialog.default: 默认主题
|
||||
theme-dialog.close: 关闭
|
||||
logs.timed-out: 超时
|
||||
logs.blocked: 阻塞
|
||||
logs.exit-code: 退出代码
|
||||
logs.completed: 完成
|
||||
logs.clear-filter: 清除搜索筛选器
|
||||
logs.clear-date-filter: 清除日期筛选器
|
||||
logs.calendar: 日历
|
||||
logs.calendar-title: 日志日历
|
||||
logs.back-to-list: 返回列表
|
||||
logs.queue: 队列
|
||||
logs.queue-title: 执行队列
|
||||
logs.queue-page-description: 按动作组分组显示正在运行和等待中的执行。您无权查看的条目会被隐藏。
|
||||
logs.queue-default-group: 默认
|
||||
logs.action-group-limits: "并发:{concurrent},队列大小:{queueSize}"
|
||||
logs.queue-group-active-unlimited: "{active} 个活动"
|
||||
logs.queue-empty: 当前没有正在运行或等待中的执行。
|
||||
logs.queue-group-active: "{active} 个活动(上限 {max})"
|
||||
logs.queue-waiting: 等待中
|
||||
logs.queue-running: 运行中
|
||||
logs.queue-position: "第 {position} 位"
|
||||
logs.queue-entity: 实体
|
||||
logs.queue-action-details: 动作详细信息
|
||||
diagnostics.get-support: 获取支持
|
||||
diagnostics.get-support-description: 如果您在使用 OliveTin 时遇到问题并希望提交支持请求,从本页面包含服务器诊断将非常有帮助。
|
||||
diagnostics.where-to-find-help: 在哪里找到帮助
|
||||
diagnostics.config-issues: 配置问题
|
||||
diagnostics.config-issues-description: 当前 OliveTin 配置中检测到的问题。请在配置文件中修复这些问题并重新加载 OliveTin。
|
||||
diagnostics.config-issues-none: 未检测到配置问题。
|
||||
diagnostics.config-issue-severity: 严重程度
|
||||
diagnostics.config-issue-code: 代码
|
||||
diagnostics.config-issue-message: 消息
|
||||
diagnostics.config-issue-action: 操作
|
||||
diagnostics.config-issue-argument: 参数
|
||||
diagnostics.config-issue-config-file: 配置文件
|
||||
diagnostics.config-issue-detail: 详情
|
||||
diagnostics.config-issue-source: 来源
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: 找到密钥
|
||||
diagnostics.found-config: 找到配置
|
||||
diagnostics.server-diagnostics: 服务器诊断
|
||||
diagnostics.server-diagnostics-description: 此部分允许您生成配置和环境的详细报告。在提交支持请求时包含此信息是个好主意。
|
||||
diagnostics.server-diagnostics-docs: 服务器诊断文档
|
||||
diagnostics.generate-server-diagnostics: 生成服务器诊断
|
||||
diagnostics.browser-info: 浏览器信息
|
||||
diagnostics.browser-info-description: 此部分允许您生成浏览器信息的详细报告。这在排查浏览器特定问题时很有帮助。
|
||||
diagnostics.generate-browser-info: 生成浏览器信息
|
||||
diagnostics.copy-to-clipboard: 复制到剪贴板
|
||||
diagnostics.copied: 已复制!
|
||||
diagnostics.unknown: 未知
|
||||
diagnostics.useragent-data-error: 检索 userAgentData 时出错
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
schemaVersion: 1
|
||||
translations:
|
||||
welcome: 歡迎使用 OliveTin
|
||||
docs: 官方文件
|
||||
raise-issue: 在 GitHub 上建立 Issue
|
||||
nav.actions: 動作
|
||||
nav.logs: 日誌
|
||||
nav.entities: 實體
|
||||
nav.diagnostics: 診斷
|
||||
nav.system: 系統
|
||||
connected: 已連線
|
||||
disconnected: 已斷線
|
||||
reconnecting: 重新連線中…
|
||||
disconnected-banner-announcement: 系統事件 WebSocket 已斷線。
|
||||
disconnected-banner-link-text: "系統事件 WebSocket 已斷線"
|
||||
disconnected-banner-suffix: " 自 {disconnectedSince} 起。將在 {reconnectIn} 後嘗試重新連線。"
|
||||
disconnected-banner-suffix-reconnecting: " 自 {disconnectedSince} 起。嘗試重新連線中…"
|
||||
login-button: 登入
|
||||
logs.title: 日誌
|
||||
logs.page-description: 這是已執行動作的日誌清單。請使用過濾條件欄位來搜尋關鍵字與運算式。
|
||||
logs.filter-placeholder: 過濾日誌 (例如 !Update 或 Status != Completed)
|
||||
logs.filter-help-title: 過濾語法
|
||||
logs.filter-help-intro: 過濾器會在伺服器端針對您有權限檢視的項目進行篩選。您可以使用 and / or 來組合搜尋條件。
|
||||
logs.filter-help-fields: "欄位:Status, Action, User, Output, Blocked, TimedOut, Running, ExitCode。運算子:==, !=, contains。在單一單字前加上 ! 前綴可排除相符的項目。"
|
||||
logs.filter-help-examples: "範例:backup · !Update · Status != Completed · Status == Blocked · Action contains backup and Status == Completed"
|
||||
logs.filter-error: 無法套用過濾運算式。
|
||||
logs.no-logs-for-filter: 沒有符合目前過濾條件的日誌。
|
||||
logs.timestamp: 時間戳記
|
||||
logs.action: 動作
|
||||
logs.metadata: 中繼資料
|
||||
logs.status: 狀態
|
||||
logs.no-logs-to-display: 目前沒有可顯示的日誌。
|
||||
logs.timed-out: 執行逾時
|
||||
logs.blocked: 已阻擋
|
||||
logs.exit-code: 結束代碼
|
||||
logs.completed: 已完成
|
||||
logs.clear-filter: 清除搜尋過濾條件
|
||||
logs.clear-date-filter: 清除日期過濾條件
|
||||
logs.calendar: 日曆
|
||||
logs.calendar-title: 日誌日曆
|
||||
logs.back-to-list: 返回清單
|
||||
logs.queue: 佇列
|
||||
logs.queue-title: 執行佇列
|
||||
logs.queue-page-description: 依動作群組分類的使用中與等待中執行項目。您無權檢視的項目將會被隱藏。
|
||||
logs.queue-empty: 目前沒有使用中或等待中的執行項目。
|
||||
logs.queue-default-group: 預設
|
||||
logs.action-group-limits: "並行數:{concurrent},佇列大小:{queueSize}"
|
||||
logs.queue-group-active: "{active} 個使用中 (最大值 {max})"
|
||||
logs.queue-group-active-unlimited: "{active} 個使用中"
|
||||
logs.queue-waiting: 等待中
|
||||
logs.queue-running: 執行中
|
||||
logs.queue-position: "#{position}"
|
||||
logs.queue-entity: 實體
|
||||
logs.queue-action-details: 動作詳細資訊
|
||||
diagnostics.get-support: 尋求技術支援
|
||||
diagnostics.get-support-description: 如果您在使用 OliveTin 時遇到問題並希望提出支援請求,提供此頁面的「伺服器診斷資訊」將會有很大的幫助。
|
||||
diagnostics.where-to-find-help: 哪裡可以尋求協助
|
||||
diagnostics.config-issues: 設定問題
|
||||
diagnostics.config-issues-description: 目前 OliveTin 設定中偵測到的問題。請在設定檔中修正這些問題並重新載入 OliveTin。
|
||||
diagnostics.config-issues-none: 未偵測到設定問題。
|
||||
diagnostics.config-issue-severity: 嚴重程度
|
||||
diagnostics.config-issue-code: 代碼
|
||||
diagnostics.config-issue-message: 訊息
|
||||
diagnostics.config-issue-action: 動作
|
||||
diagnostics.config-issue-argument: 參數
|
||||
diagnostics.config-issue-config-file: 設定檔
|
||||
diagnostics.config-issue-detail: 詳細資料
|
||||
diagnostics.config-issue-source: 來源
|
||||
diagnostics.ssh: SSH
|
||||
diagnostics.found-key: 找到金鑰 (Key)
|
||||
diagnostics.found-config: 找到設定檔 (Config)
|
||||
diagnostics.server-diagnostics: 伺服器診斷
|
||||
diagnostics.server-diagnostics-description: 此區塊可讓您產生詳細的設定與環境報告。建議在提出支援請求時附上此報告。
|
||||
diagnostics.server-diagnostics-docs: 伺服器診斷官方文件
|
||||
diagnostics.generate-server-diagnostics: 產生伺服器診斷資訊
|
||||
diagnostics.browser-info: 瀏覽器資訊
|
||||
diagnostics.browser-info-description: 此區塊可讓您產生瀏覽器資訊的詳細報告。這在排解特定瀏覽器問題時相當有幫助。
|
||||
diagnostics.generate-browser-info: 產生瀏覽器資訊
|
||||
diagnostics.copy-to-clipboard: 複製到剪貼簿
|
||||
diagnostics.copied: 已複製!
|
||||
diagnostics.unknown: 未知
|
||||
diagnostics.useragent-data-error: 取得 userAgentData 時發生錯誤
|
||||
return-to-index: 返回首頁
|
||||
search-filter: 過濾目前頁面
|
||||
language-dialog.title: 選擇語言
|
||||
language-dialog.browser-languages: 瀏覽器語言
|
||||
language-dialog.not-available: 無法使用
|
||||
language-dialog.close: 關閉
|
||||
theme-dialog.title: 選擇佈景主題
|
||||
theme-dialog.default: 預設佈景主題
|
||||
theme-dialog.close: 關閉
|
||||
Loading…
Reference in New Issue