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:
Ilya Mukhortov 2026-08-24 10:41:07 +10:00
parent e3ba0b70d7
commit 68a7ec2e43
22 changed files with 460 additions and 1554 deletions

36
AI.md
View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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
View File

@ -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) для МИС «Медицина».
[![Maturity Badge](https://img.shields.io/badge/maturity-Production-brightgreen)](#none)
[![Discord](https://img.shields.io/discord/846737624960860180?label=Discord%20Server)](https://discord.gg/jhYWWpNJ3v)
[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/awesome-selfhosted/awesome-selfhosted#automation)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5050/badge)](https://bestpractices.coreinfrastructure.org/projects/5050)
Исходный репозиторий: https://github.com/OliveTin/OliveTin
[![Go Report Card](https://goreportcard.com/badge/github.com/Olivetin/OliveTin)](https://goreportcard.com/report/github.com/OliveTin/OliveTin)
[![AI Autonomy Level](https://img.shields.io/badge/AI%20Autonomy-Level%202%20of%205%20(pair--programmer)-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
[![YouTube demo video](https://raw.githubusercontent.com/OliveTin/OliveTin/main/var/marketing/YouTubeBanner.png)](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, в том числе предоставление исходного кода при сетевом использовании модифицированной версии.

View File

@ -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.

28
Taskfile.yml Normal file
View File

@ -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}} .

View File

@ -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:

View File

@ -20,37 +20,45 @@ import App from './resources/vue/App.vue'
import { initWebsocket } from './js/websocket.js'
import combinedTranslations from '../lang/combined_output.json'
const DEFAULT_LOCALE = 'ru'
function matchAvailableLocale (candidate, available) {
const lowerCandidate = candidate.toLowerCase()
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
if (exact) {
return exact
}
const langPrefix = lowerCandidate.split('-')[0]
const languageOnly = available.find(locale => locale.toLowerCase() === langPrefix)
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') {
if (storedLanguage && storedLanguage !== 'auto' && available.includes(storedLanguage)) {
return storedLanguage
}
if (storedLanguage === 'auto') {
localStorage.removeItem('olivetin-language')
}
if (navigator.languages && navigator.languages.length > 0) {
const available = Object.keys(combinedTranslations.messages || {})
if (storedLanguage === 'auto' && navigator.languages && navigator.languages.length > 0) {
for (const candidate of navigator.languages) {
const lowerCandidate = candidate.toLowerCase()
const exact = available.find(locale => locale.toLowerCase() === lowerCandidate)
const matched = matchAvailableLocale(candidate, available)
if (exact) {
return exact
}
const prefix = available.find(locale => locale.toLowerCase().startsWith(lowerCandidate.split('-')[0] + '-'))
if (prefix) {
return prefix
if (matched) {
return matched
}
}
}
return 'en'
return DEFAULT_LOCALE
}
async function initClient () {

View File

@ -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>

View File

@ -1,17 +1,16 @@
<template>
<section id="argument-popup">
<div class="section-header">
<h2>
<span class="section-title-with-icon">
Start action:
<ActionIconGlyph
v-if="icon"
class="action-title-icon"
:glyph="icon"
/>
{{ title }}
</span>
</h2>
<h2>
<span class="section-title-with-icon">
<ActionIconGlyph
v-if="icon"
class="action-title-icon"
:glyph="icon"
/>
{{ title }}
</span>
</h2>
</div>
<div class="section-content padding">
<form @submit="handleSubmit">
@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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
}

View File

@ -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"
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

121
lang/ru.yaml Normal file
View File

@ -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: Закрыть

View File

@ -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 时出错

View File

@ -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: 關閉